SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
BootROMs/cgb_boot.asm
1 ; SameBoy CGB bootstrap ROM
2
3 include "sameboot.inc"
4
5 SECTION "BootCode", ROM0[$0000]
6 Start:
7 ; Init stack pointer
8 ld sp, $FFFE
9
10 ; Clear memory VRAM
11 call ClearMemoryVRAM
12
13 ; Clear OAM
14 ld h, HIGH(_OAMRAM)
15 ld c, sizeof_OAM_ATTRS * OAM_COUNT
16 .clearOAMLoop
17 ldi [hl], a
18 dec c
19 jr nz, .clearOAMLoop
20
21 IF !DEF(CGB0)
22 ; Init waveform
23 ld c, 16
24 ld hl, _AUD3WAVERAM
25 .waveformLoop
26 ldi [hl], a
27 cpl
28 dec c
29 jr nz, .waveformLoop
30 ENDC
31
32 ; Clear chosen input palette
33 ldh [hInputPalette], a
34 ; Clear title checksum
35 ldh [hTitleChecksum], a
36
37 ; Init Audio
38 ld a, AUDENA_ON
39 ldh [rNR52], a
40 assert AUDENA_ON == AUDLEN_DUTY_50
41 ldh [rNR11], a
42 ld a, $F3
43 ldh [rNR12], a ; Envelope $F, decreasing, sweep $3
44 ldh [rNR51], a ; Channels 1+2+3+4 left, channels 1+2 right
45 ld a, $77
46 ldh [rNR50], a ; Volume $7, left and right
47
48 ; Init BG palette
49 ld a, %11_11_11_00
50 ldh [rBGP], a
51
52 ; Load logo from ROM.
53 ; A nibble represents a 4-pixels line, 2 bytes represent a 4x4 tile, scaled to 8x8.
54 ; Tiles are ordered left to right, top to bottom.
55 ; These tiles are not used, but are required for DMG compatibility. This is done
56 ; by the original CGB Boot ROM as well.
57 ld de, NintendoLogo
58 ld hl, _VRAM + $10 ; This is where we load the tiles in VRAM
59
60 .loadLogoLoop
61 ld a, [de] ; Read 2 rows
62 ld b, a
63 call DoubleBitsAndWriteRowTwice
64 inc de
65 ld a, e
66 cp LOW(NintendoLogoEnd)
67 jr nz, .loadLogoLoop
68 call ReadTrademarkSymbol
69
70 ; Clear the second VRAM bank
71 ld a, 1
72 ldh [rVBK], a
73 call ClearMemoryVRAM
74 call LoadTileset
75
76 ld b, 3
77 IF DEF(FAST)
78 xor a
79 ldh [rVBK], a
80 ELSE
81 ; Load Tilemap
82 ld hl, _SCRN0 + 6 * SCRN_VX_B + 2
83 ld d, 3
84 ld a, 8
85
86 .tilemapLoop
87 ld c, 16
88
89 .tilemapRowLoop
90
91 call .write_with_palette
92
93 ; Repeat the 3 tiles common between E and B. This saves 27 bytes after
94 ; compression, with a cost of 17 bytes of code.
95 push af
96 sub $20
97 sub $3
98 jr nc, .notspecial
99 add $20
100 call .write_with_palette
101 dec c
102 .notspecial
103 pop af
104
105 add d ; d = 3 for SameBoy logo, d = 1 for Nintendo logo
106 dec c
107 jr nz, .tilemapRowLoop
108 sub 44
109 push de
110 ld de, $10
111 add hl, de
112 pop de
113 dec b
114 jr nz, .tilemapLoop
115
116 dec d
117 jr z, .endTilemap
118 dec d
119
120 ld a, $38
121 ld l, $A7
122 lb bc, 1, 7 ; $0107
123 jr .tilemapRowLoop
124
125 .write_with_palette
126 push af
127 ; Switch to second VRAM Bank
128 ld a, 1
129 ldh [rVBK], a
130 ld [hl], 8
131 ; Switch to back first VRAM Bank
132 xor a
133 ldh [rVBK], a
134 pop af
135 ldi [hl], a
136 ret
137 .endTilemap
138 ENDC
139
140 ; Expand Palettes
141 ld de, AnimationColors
142 ld c, 8
143 ld hl, hBgPalettes
144 xor a
145 .expandPalettesLoop:
146 cpl
147 ; One white
148 ld [hli], a
149 ld [hli], a
150
151 ; Mixed with white
152 ld a, [de]
153 inc e
154 or $20
155 ld b, a
156
157 ld a, [de]
158 dec e
159 or $84
160 rra
161 rr b
162 ld [hl], b
163 inc l
164 ld [hli], a
165
166 ; One black
167 xor a
168 ld [hli], a
169 ld [hli], a
170
171 ; One color
172 ld a, [de]
173 inc e
174 ld [hli], a
175 ld a, [de]
176 inc e
177 ld [hli], a
178
179 xor a
180 dec c
181 jr nz, .expandPalettesLoop
182
183 call LoadPalettesFromHRAM
184
185 ; Turn on LCD
186 ld a, LCDCF_ON | LCDCF_BLK01 | LCDCF_BGON
187 ldh [rLCDC], a
188
189 IF !DEF(FAST)
190 call DoIntroAnimation
191
192 ld a, 48 ; frames to wait after playing the chime
193 ldh [hWaitLoopCounter], a
194 ld b, 4 ; frames to wait before playing the chime
195 call WaitBFrames
196
197 ; Play first sound
198 ld a, $83
199 call PlaySound
200 ld b, 5
201 call WaitBFrames
202 ; Play second sound
203 ld a, $C1
204 call PlaySound
205
206 .waitLoop
207 call GetInputPaletteIndex
208 call WaitFrame
209 ld hl, hWaitLoopCounter
210 dec [hl]
211 jr nz, .waitLoop
212 ELSE
213 ld a, $C1
214 call PlaySound
215 ENDC
216 call Preboot
217 IF DEF(AGB)
218 inc b
219 ENDC
220 jr BootGame
221
222 HDMAData:
223 MACRO hdma_data ; source, destination, length
224 db HIGH(\1), LOW(\1)
225 db HIGH(\2), LOW(\2)
226 db (\3)
227 ENDM
228 hdma_data _RAMBANK, _SCRN0 + 5 * SCRN_VX_B + 0, 18
229 hdma_data _RAMBANK, _VRAM, 64
230
231 SECTION "BootGame", ROM0[$00FE]
232 BootGame:
233 ldh [rBANK], a ; unmap boot ROM
234
235 SECTION "BootData", ROM0[$0200]
236 ; Game Palettes Data
237 TitleChecksums:
238 db $00 ; Default
239 db $88 ; ALLEY WAY
240 db $16 ; YAKUMAN
241 db $36 ; BASEBALL, (Game and Watch 2)
242 db $D1 ; TENNIS
243 db $DB ; TETRIS
244 db $F2 ; QIX
245 db $3C ; DR.MARIO
246 db $8C ; RADARMISSION
247 db $92 ; F1RACE
248 db $3D ; YOSSY NO TAMAGO
249 db $5C ;
250 db $58 ; X
251 db $C9 ; MARIOLAND2
252 db $3E ; YOSSY NO COOKIE
253 db $70 ; ZELDA
254 db $1D ;
255 db $59 ;
256 db $69 ; TETRIS FLASH
257 db $19 ; DONKEY KONG
258 db $35 ; MARIO'S PICROSS
259 db $A8 ;
260 db $14 ; POKEMON RED, (GAMEBOYCAMERA G)
261 db $AA ; POKEMON GREEN
262 db $75 ; PICROSS 2
263 db $95 ; YOSSY NO PANEPON
264 db $99 ; KIRAKIRA KIDS
265 db $34 ; GAMEBOY GALLERY
266 db $6F ; POCKETCAMERA
267 db $15 ;
268 db $FF ; BALLOON KID
269 db $97 ; KINGOFTHEZOO
270 db $4B ; DMG FOOTBALL
271 db $90 ; WORLD CUP
272 db $17 ; OTHELLO
273 db $10 ; SUPER RC PRO-AM
274 db $39 ; DYNABLASTER
275 db $F7 ; BOY AND BLOB GB2
276 db $F6 ; MEGAMAN
277 db $A2 ; STAR WARS-NOA
278 db $49 ;
279 db $4E ; WAVERACE
280 db $43 ;
281 db $68 ; LOLO2
282 db $E0 ; YOSHI'S COOKIE
283 db $8B ; MYSTIC QUEST
284 db $F0 ;
285 db $CE ; TOPRANKINGTENNIS
286 db $0C ; MANSELL
287 db $29 ; MEGAMAN3
288 db $E8 ; SPACE INVADERS
289 db $B7 ; GAME&WATCH
290 db $86 ; DONKEYKONGLAND95
291 db $9A ; ASTEROIDS/MISCMD
292 db $52 ; STREET FIGHTER 2
293 db $01 ; DEFENDER/JOUST
294 db $9D ; KILLERINSTINCT95
295 db $71 ; TETRIS BLAST
296 db $9C ; PINOCCHIO
297 db $BD ;
298 db $5D ; BA.TOSHINDEN
299 db $6D ; NETTOU KOF 95
300 db $67 ;
301 db $3F ; TETRIS PLUS
302 db $6B ; DONKEYKONGLAND 3
303 ; For these games, the 4th letter is taken into account
304 FirstChecksumWithDuplicate:
305 ; Let's play hangman!
306 db $B3 ; ???[B]????????
307 db $46 ; SUP[E]R MARIOLAND
308 db $28 ; GOL[F]
309 db $A5 ; SOL[A]RSTRIKER
310 db $C6 ; GBW[A]RS
311 db $D3 ; KAE[R]UNOTAMENI
312 db $27 ; ???[B]????????
313 db $61 ; POK[E]MON BLUE
314 db $18 ; DON[K]EYKONGLAND
315 db $66 ; GAM[E]BOY GALLERY2
316 db $6A ; DON[K]EYKONGLAND 2
317 db $BF ; KID[ ]ICARUS
318 db $0D ; TET[R]IS2
319 db $F4 ; ???[-]????????
320 db $B3 ; MOG[U]RANYA
321 db $46 ; ???[R]????????
322 db $28 ; GAL[A]GA&GALAXIAN
323 db $A5 ; BT2[R]AGNAROKWORLD
324 db $C6 ; KEN[ ]GRIFFEY JR
325 db $D3 ; ???[I]????????
326 db $27 ; MAG[N]ETIC SOCCER
327 db $61 ; VEG[A]S STAKES
328 db $18 ; ???[I]????????
329 db $66 ; MIL[L]I/CENTI/PEDE
330 db $6A ; MAR[I]O & YOSHI
331 db $BF ; SOC[C]ER
332 db $0D ; POK[E]BOM
333 db $F4 ; G&W[ ]GALLERY
334 db $B3 ; TET[R]IS ATTACK
335 ChecksumsEnd:
336
337 PalettePerChecksum:
338 MACRO palette_index ; palette[, flags]
339 IF _NARG == 1
340 db (\1)
341 ELSE
342 db (\1) | (\2) ; flag $80 means game requires DMG boot tilemap
343 ENDC
344 ENDM
345 palette_index 0 ; Default Palette
346 palette_index 4 ; ALLEY WAY
347 palette_index 5 ; YAKUMAN
348 palette_index 35 ; BASEBALL, (Game and Watch 2)
349 palette_index 34 ; TENNIS
350 palette_index 3 ; TETRIS
351 palette_index 31 ; QIX
352 palette_index 15 ; DR.MARIO
353 palette_index 10 ; RADARMISSION
354 palette_index 5 ; F1RACE
355 palette_index 19 ; YOSSY NO TAMAGO
356 palette_index 36 ;
357 palette_index 7, $80 ; X
358 palette_index 37 ; MARIOLAND2
359 palette_index 30 ; YOSSY NO COOKIE
360 palette_index 44 ; ZELDA
361 palette_index 21 ;
362 palette_index 32 ;
363 palette_index 31 ; TETRIS FLASH
364 palette_index 20 ; DONKEY KONG
365 palette_index 5 ; MARIO'S PICROSS
366 palette_index 33 ;
367 palette_index 13 ; POKEMON RED, (GAMEBOYCAMERA G)
368 palette_index 14 ; POKEMON GREEN
369 palette_index 5 ; PICROSS 2
370 palette_index 29 ; YOSSY NO PANEPON
371 palette_index 5 ; KIRAKIRA KIDS
372 palette_index 18 ; GAMEBOY GALLERY
373 palette_index 9 ; POCKETCAMERA
374 palette_index 3 ;
375 palette_index 2 ; BALLOON KID
376 palette_index 26 ; KINGOFTHEZOO
377 palette_index 25 ; DMG FOOTBALL
378 palette_index 25 ; WORLD CUP
379 palette_index 41 ; OTHELLO
380 palette_index 42 ; SUPER RC PRO-AM
381 palette_index 26 ; DYNABLASTER
382 palette_index 45 ; BOY AND BLOB GB2
383 palette_index 42 ; MEGAMAN
384 palette_index 45 ; STAR WARS-NOA
385 palette_index 36 ;
386 palette_index 38 ; WAVERACE
387 palette_index 26, $80 ;
388 palette_index 42 ; LOLO2
389 palette_index 30 ; YOSHI'S COOKIE
390 palette_index 41 ; MYSTIC QUEST
391 palette_index 34 ;
392 palette_index 34 ; TOPRANKINGTENNIS
393 palette_index 5 ; MANSELL
394 palette_index 42 ; MEGAMAN3
395 palette_index 6 ; SPACE INVADERS
396 palette_index 5 ; GAME&WATCH
397 palette_index 33 ; DONKEYKONGLAND95
398 palette_index 25 ; ASTEROIDS/MISCMD
399 palette_index 42 ; STREET FIGHTER 2
400 palette_index 42 ; DEFENDER/JOUST
401 palette_index 40 ; KILLERINSTINCT95
402 palette_index 2 ; TETRIS BLAST
403 palette_index 16 ; PINOCCHIO
404 palette_index 25 ;
405 palette_index 42 ; BA.TOSHINDEN
406 palette_index 42 ; NETTOU KOF 95
407 palette_index 5 ;
408 palette_index 0 ; TETRIS PLUS
409 palette_index 39 ; DONKEYKONGLAND 3
410 palette_index 36 ;
411 palette_index 22 ; SUPER MARIOLAND
412 palette_index 25 ; GOLF
413 palette_index 6 ; SOLARSTRIKER
414 palette_index 32 ; GBWARS
415 palette_index 12 ; KAERUNOTAMENI
416 palette_index 36 ;
417 palette_index 11 ; POKEMON BLUE
418 palette_index 39 ; DONKEYKONGLAND
419 palette_index 18 ; GAMEBOY GALLERY2
420 palette_index 39 ; DONKEYKONGLAND 2
421 palette_index 24 ; KID ICARUS
422 palette_index 31 ; TETRIS2
423 palette_index 50 ;
424 palette_index 17 ; MOGURANYA
425 palette_index 46 ;
426 palette_index 6 ; GALAGA&GALAXIAN
427 palette_index 27 ; BT2RAGNAROKWORLD
428 palette_index 0 ; KEN GRIFFEY JR
429 palette_index 47 ;
430 palette_index 41 ; MAGNETIC SOCCER
431 palette_index 41 ; VEGAS STAKES
432 palette_index 0 ;
433 palette_index 0 ; MILLI/CENTI/PEDE
434 palette_index 19 ; MARIO & YOSHI
435 palette_index 34 ; SOCCER
436 palette_index 23 ; POKEBOM
437 palette_index 18 ; G&W GALLERY
438 palette_index 29 ; TETRIS ATTACK
439
440 Dups4thLetterArray:
441 db "BEFAARBEKEK R-URAR INAILICE R"
442
443 ; We assume the last three arrays fit in the same $100 byte page!
444
445 PaletteCombinations:
446 MACRO palette_comb ; Obj0, Obj1, Bg
447 db (\1) * 8, (\2) * 8, (\3) *8
448 ENDM
449 MACRO raw_palette_comb ; Obj0, Obj1, Bg
450 db (\1) * 2, (\2) * 2, (\3) * 2
451 ENDM
452 palette_comb 4, 4, 29 ; 0, Right + A
453 palette_comb 18, 18, 18 ; 1, Right
454 palette_comb 20, 20, 20 ; 2
455 palette_comb 24, 24, 24 ; 3, Down + A
456 palette_comb 9, 9, 9 ; 4
457 palette_comb 0, 0, 0 ; 5, Up
458 palette_comb 27, 27, 27 ; 6, Right + B
459 palette_comb 5, 5, 5 ; 7, Left + B
460 palette_comb 12, 12, 12 ; 8, Down
461 palette_comb 26, 26, 26 ; 9
462 palette_comb 16, 8, 8 ; 10
463 palette_comb 4, 28, 28 ; 11
464 palette_comb 4, 2, 2 ; 12
465 palette_comb 3, 4, 4 ; 13
466 palette_comb 4, 29, 29 ; 14
467 palette_comb 28, 4, 28 ; 15
468 palette_comb 2, 17, 2 ; 16
469 palette_comb 16, 16, 8 ; 17
470 palette_comb 4, 4, 7 ; 18
471 palette_comb 4, 4, 18 ; 19
472 palette_comb 4, 4, 20 ; 20
473 palette_comb 19, 19, 9 ; 21
474 raw_palette_comb 4 * 4 - 1, 4 * 4 - 1, 11 * 4 ; 22
475 palette_comb 17, 17, 2 ; 23
476 palette_comb 4, 4, 2 ; 24
477 palette_comb 4, 4, 3 ; 25
478 palette_comb 28, 28, 0 ; 26
479 palette_comb 3, 3, 0 ; 27
480 palette_comb 0, 0, 1 ; 28, Up + B
481 palette_comb 18, 22, 18 ; 29
482 palette_comb 20, 22, 20 ; 30
483 palette_comb 24, 22, 24 ; 31
484 palette_comb 16, 22, 8 ; 32
485 palette_comb 17, 4, 13 ; 33
486 raw_palette_comb 28 * 4 - 1, 0 * 4, 14 * 4 ; 34
487 raw_palette_comb 28 * 4 - 1, 4 * 4, 15 * 4 ; 35
488 raw_palette_comb 19 * 4, 23 * 4 - 1, 9 * 4 ; 36
489 palette_comb 16, 28, 10 ; 37
490 palette_comb 4, 23, 28 ; 38
491 palette_comb 17, 22, 2 ; 39
492 palette_comb 4, 0, 2 ; 40, Left + A
493 palette_comb 4, 28, 3 ; 41
494 palette_comb 28, 3, 0 ; 42
495 palette_comb 3, 28, 4 ; 43, Up + A
496 palette_comb 21, 28, 4 ; 44
497 palette_comb 3, 28, 0 ; 45
498 palette_comb 25, 3, 28 ; 46
499 palette_comb 0, 28, 8 ; 47
500 palette_comb 4, 3, 28 ; 48, Left
501 palette_comb 28, 3, 6 ; 49, Down + B
502 palette_comb 4, 28, 29 ; 50
503 ; SameBoy "Exclusives"
504 palette_comb 30, 30, 30 ; 51, Right + A + B, CGA
505 palette_comb 31, 31, 31 ; 52, Left + A + B, DMG LCD
506 palette_comb 28, 4, 1 ; 53, Up + A + B
507 palette_comb 0, 0, 2 ; 54, Down + A + B
508
509 Palettes:
510 dw $7FFF, $32BF, $00D0, $0000 ; 0
511 dw $639F, $4279, $15B0, $04CB ; 1
512 dw $7FFF, $6E31, $454A, $0000 ; 2
513 dw $7FFF, $1BEF, $0200, $0000 ; 3
514 dw $7FFF, $421F, $1CF2, $0000 ; 4
515 dw $7FFF, $5294, $294A, $0000 ; 5
516 dw $7FFF, $03FF, $012F, $0000 ; 6
517 dw $7FFF, $03EF, $01D6, $0000 ; 7
518 dw $7FFF, $42B5, $3DC8, $0000 ; 8
519 dw $7E74, $03FF, $0180, $0000 ; 9
520 dw $67FF, $77AC, $1A13, $2D6B ; 10
521 dw $7ED6, $4BFF, $2175, $0000 ; 11
522 dw $53FF, $4A5F, $7E52, $0000 ; 12
523 dw $4FFF, $7ED2, $3A4C, $1CE0 ; 13
524 dw $03ED, $7FFF, $255F, $0000 ; 14
525 dw $036A, $021F, $03FF, $7FFF ; 15
526 dw $7FFF, $01DF, $0112, $0000 ; 16
527 dw $231F, $035F, $00F2, $0009 ; 17
528 dw $7FFF, $03EA, $011F, $0000 ; 18
529 dw $299F, $001A, $000C, $0000 ; 19
530 dw $7FFF, $027F, $001F, $0000 ; 20
531 dw $7FFF, $03E0, $0206, $0120 ; 21
532 dw $7FFF, $7EEB, $001F, $7C00 ; 22
533 dw $7FFF, $3FFF, $7E00, $001F ; 23
534 dw $7FFF, $03FF, $001F, $0000 ; 24
535 dw $03FF, $001F, $000C, $0000 ; 25
536 dw $7FFF, $033F, $0193, $0000 ; 26
537 dw $0000, $4200, $037F, $7FFF ; 27
538 dw $7FFF, $7E8C, $7C00, $0000 ; 28
539 dw $7FFF, $1BEF, $6180, $0000 ; 29
540 ; SameBoy "Exclusives"
541 dw $7FFF, $7FEA, $7D5F, $0000 ; 30, CGA 1
542 dw $4778, $3290, $1D87, $0861 ; 31, DMG LCD
543
544 KeyCombinationPalettes:
545 MACRO palette_comb_id ; PaletteCombinations ID
546 db (\1) * 3
547 ENDM
548 palette_comb_id 1 ; 1, Right
549 palette_comb_id 48 ; 2, Left
550 palette_comb_id 5 ; 3, Up
551 palette_comb_id 8 ; 4, Down
552 palette_comb_id 0 ; 5, Right + A
553 palette_comb_id 40 ; 6, Left + A
554 palette_comb_id 43 ; 7, Up + A
555 palette_comb_id 3 ; 8, Down + A
556 palette_comb_id 6 ; 9, Right + B
557 palette_comb_id 7 ; 10, Left + B
558 palette_comb_id 28 ; 11, Up + B
559 palette_comb_id 49 ; 12, Down + B
560 ; SameBoy "Exclusives"
561 palette_comb_id 51 ; 13, Right + A + B
562 palette_comb_id 52 ; 14, Left + A + B
563 palette_comb_id 53 ; 15, Up + A + B
564 palette_comb_id 54 ; 16, Down + A + B
565
566 TrademarkSymbol:
567 pusho
568 opt b.X
569 db %..XXXX..
570 db %.X....X.
571 db %X.XXX..X
572 db %X.X..X.X
573 db %X.XXX..X
574 db %X.X..X.X
575 db %.X....X.
576 db %..XXXX..
577 popo
578 TrademarkSymbolEnd:
579
580 SameBoyLogo:
581 incbin "SameBoyLogo.pb12"
582
583
584 AnimationColors:
585 dw $7FFF ; White
586 dw $774F ; Cyan
587 dw $22C7 ; Green
588 dw $039F ; Yellow
589 dw $017D ; Orange
590 dw $241D ; Red
591 dw $6D38 ; Purple
592 IF DEF(AGB)
593 dw $6D60 ; Blue
594 ELSE
595 dw $5500 ; Blue
596 ENDC
597
598 AnimationColorsEnd:
599
600 ; Helper Functions
601 DoubleBitsAndWriteRowTwice:
602 call .twice
603 .twice
604 ; Double the most significant 4 bits, b is shifted by 4
605 ld a, 4
606 ld c, 0
607 .doubleCurrentBit
608 sla b
609 push af
610 rl c
611 pop af
612 rl c
613 dec a
614 jr nz, .doubleCurrentBit
615 ld a, c
616 ; Write as two rows
617 ldi [hl], a
618 inc hl
619 ldi [hl], a
620 inc hl
621 ret
622
623 WaitFrame:
624 push hl
625 ld hl, rIF
626 res 0, [hl]
627 .wait
628 bit 0, [hl]
629 jr z, .wait
630 pop hl
631 ret
632
633 WaitBFrames:
634 call GetInputPaletteIndex
635 call WaitFrame
636 dec b
637 jr nz, WaitBFrames
638 ret
639
640 PlaySound:
641 ldh [rNR13], a
642 ld a, $87
643 ldh [rNR14], a
644 ret
645
646 ClearMemoryVRAM:
647 ld hl, _VRAM
648 ; Clear from HL to HL | 0x2000
649 ClearMemoryPage:
650 xor a
651 ldi [hl], a
652 bit 5, h
653 jr z, ClearMemoryPage
654 ret
655
656 ReadTwoTileLines:
657 call ReadTileLine
658 ; c = $F0 for even lines, $0F for odd lines.
659 ReadTileLine:
660 ld a, [de]
661 and c
662 ld b, a
663 inc e
664 inc e
665 ld a, [de]
666 dec e
667 dec e
668 and c
669 swap a
670 or b
671 bit 0, c
672 jr z, .dontSwap
673 swap a
674 .dontSwap
675 inc hl
676 ldi [hl], a
677 swap c
678 ret
679
680
681 ReadCGBLogoHalfTile:
682 call .do_twice
683 .do_twice
684 call ReadTwoTileLines
685 inc e
686 ld a, e
687 ret
688
689 ; LoadTileset using PB12 codec, 2020 Jakub Kądziołka
690 ; (based on PB8 codec, 2019 Damian Yerrick)
691
692 LoadTileset:
693 ld hl, SameBoyLogo ; source
694 ld de, _VRAM + $80 - 1 ; destination
695 ld c, (128 * 24) / (8 * 8) ; length
696 .refill
697 ; Register map for PB12 decompression
698 ; HL: source address in boot ROM
699 ; DE: destination address in VRAM
700 ; A: Current literal value
701 ; B: Repeat bits, terminated by 1000...
702 ; Source address in HL lets the repeat bits go straight to B,
703 ; bypassing A and avoiding spilling registers to the stack.
704 ld b, [hl]
705 dec b
706 jr z, .sameboyLogoEnd
707 inc b
708 inc hl
709
710 ; Shift a 1 into lower bit of shift value. Once this bit
711 ; reaches the carry, B becomes 0 and the byte is over
712 scf
713 rl b
714
715 .loop
716 ; If not a repeat, load a literal byte
717 jr c, .simple_repeat
718 sla b
719 jr c, .shifty_repeat
720 ld a, [hli]
721 jr .got_byte
722 .shifty_repeat
723 sla b
724 jr nz, .no_refill_during_shift
725 ld b, [hl] ; see above. Also, no, factoring it out into a callable
726 inc hl ; routine doesn't save bytes, even with conditional calls
727 scf
728 rl b
729 .no_refill_during_shift
730 ld c, a
731 jr nc, .shift_left
732 srl a
733 db $FE ; eat the `add a` with `cp d8`
734 .shift_left
735 add a
736 sla b
737 jr c, .go_and
738 or c
739 db $FE ; eat the `and c` with `cp d8`
740 .go_and
741 and c
742 jr .got_byte
743 .simple_repeat
744 sla b
745 jr c, .got_byte
746 ; far repeat
747 dec de
748 ld a, [de]
749 inc de
750 .got_byte
751 inc de
752 ld [de], a
753 sla b
754 jr nz, .loop
755 jr .refill
756
757 ; End PB12 decoding. The rest uses HL as the destination
758 .sameboyLogoEnd
759 ld h, d
760 ld l, $80
761
762 ; Copy (unresized) ROM logo
763 ld de, NintendoLogo
764 .CGBROMLogoLoop
765 ld c, $F0
766 call ReadCGBLogoHalfTile
767 add a, 22
768 ld e, a
769 call ReadCGBLogoHalfTile
770 sub a, 22
771 ld e, a
772 cp $1C
773 jr nz, .CGBROMLogoLoop
774 inc hl
775 ; fallthrough
776 ReadTrademarkSymbol:
777 ld de, TrademarkSymbol
778 ld c, TrademarkSymbolEnd - TrademarkSymbol
779 .loadTrademarkSymbolLoop:
780 ld a, [de]
781 inc de
782 ldi [hl], a
783 inc hl
784 dec c
785 jr nz, .loadTrademarkSymbolLoop
786 ret
787
788 DoIntroAnimation:
789 ; Animate the intro
790 ld a, 1
791 ldh [rVBK], a
792 ld d, 26
793 .animationLoop
794 ld b, 2
795 call WaitBFrames
796 ld hl, _SCRN0 + 6 * SCRN_VX_B + 0
797 ld c, 3 ; Row count
798 .loop
799 ld a, [hl]
800 cp $F ; Already blue
801 jr z, .nextTile
802 inc [hl]
803 and $7
804 jr z, .nextLine ; Changed a white tile, go to next line
805 .nextTile
806 inc hl
807 jr .loop
808 .nextLine
809 ld a, l
810 or $1F
811 ld l, a
812 inc hl
813 dec c
814 jr nz, .loop
815 dec d
816 jr nz, .animationLoop
817 ret
818
819 Preboot:
820 IF !DEF(FAST)
821 ld b, 32 ; 32 times to fade
822 .fadeLoop
823 ld c, (hBgPalettesEnd - hBgPalettes) / 2 ; 32 colors to fade
824 ld hl, hBgPalettes
825 .frameLoop
826 push bc
827
828 ; Brighten Color
829 ld a, [hli]
830 ld e, a
831 ld a, [hld]
832 ld d, a
833 ; RGB(1,1,1)
834 ld bc, $0421
835
836 ; Is blue maxed?
837 ld a, e
838 and $1F
839 cp $1F
840 jr nz, .blueNotMaxed
841 dec c
842 .blueNotMaxed
843
844 ; Is green maxed?
845 ld a, e
846 cp $E0
847 jr c, .greenNotMaxed
848 ld a, d
849 and $3
850 cp $3
851 jr nz, .greenNotMaxed
852 res 5, c
853 .greenNotMaxed
854
855 ; Is red maxed?
856 ld a, d
857 and $7C
858 cp $7C
859 jr nz, .redNotMaxed
860 res 2, b
861 .redNotMaxed
862
863 ld a, e
864 add c
865 ld [hli], a
866 ld a, d
867 adc b
868 ld [hli], a
869 pop bc
870
871 dec c
872 jr nz, .frameLoop
873
874 call WaitFrame
875 call LoadPalettesFromHRAM
876 call WaitFrame
877 dec b
878 jr nz, .fadeLoop
879 ENDC
880 ld a, 2
881 ldh [rSVBK], a
882 ; Clear RAM Bank 2 (Like the original boot ROM)
883 ld hl, _RAMBANK
884 call ClearMemoryPage
885 inc a
886 call ClearVRAMViaHDMA
887 call _ClearVRAMViaHDMA
888 call ClearVRAMViaHDMA ; A = $40, so it's bank 0
889 xor a
890 ldh [rSVBK], a
891 cpl
892 ldh [rJOYP], a
893
894 ; Final values for CGB mode
895 ld d, a
896 ld e, c
897 ld l, $0D
898
899 ld a, [CGBFlag]
900 bit 7, a
901 call z, EmulateDMG
902 bit 7, a
903
904 ldh [rKEY0], a ; write CGB compatibility byte, CGB mode
905 ldh a, [hTitleChecksum]
906 ld b, a
907
908 jr z, .skipDMGForCGBCheck
909 ldh a, [hInputPalette]
910 and a
911 jr nz, .emulateDMGForCGBGame
912 .skipDMGForCGBCheck
913 IF DEF(AGB)
914 ; Set registers to match the original AGB-CGB boot
915 ; AF = $1100, C = 0
916 xor a
917 ld c, a
918 add a, BOOTUP_A_CGB
919 ld h, c
920 ; B is set to BOOTUP_B_AGB (1) after ret
921 ELSE
922 ; Set registers to match the original CGB boot
923 ; AF = $1180, C = 0
924 xor a
925 ld c, a
926 ld a, BOOTUP_A_CGB
927 ld h, c
928 ; B is set to the title checksum (BOOTUP_B_CGB, 0)
929 ENDC
930 ret
931
932 .emulateDMGForCGBGame
933 call EmulateDMG
934 ldh [rKEY0], a ; write $04, DMG emulation mode
935 ld a, $1
936 ret
937
938 GetKeyComboPalette:
939 ld hl, KeyCombinationPalettes - 1 ; Return value is 1-based, 0 means nothing down
940 ld c, a
941 ld b, 0
942 add hl, bc
943 ld a, [hl]
944 ret
945
946 EmulateDMG:
947 ld a, 1
948 ldh [rOPRI], a ; DMG Emulation sprite priority
949 call GetPaletteIndex
950 bit 7, a
951 call nz, LoadDMGTilemap
952 res 7, a
953 ld b, a
954 add b
955 add b
956 ld b, a
957 ldh a, [hInputPalette]
958 and a
959 jr z, .nothingDown
960 call GetKeyComboPalette
961 jr .paletteFromKeys
962 .nothingDown
963 ld a, b
964 .paletteFromKeys
965 call WaitFrame
966 call LoadPalettesFromIndex
967 ld a, 4
968 ; Set the final values for DMG mode
969 ld de, 8
970 ld l, $7C
971 ret
972
973 GetPaletteIndex:
974 ld hl, OldLicenseeCode
975 ld a, [hl]
976 cp $33
977 jr z, .newLicensee
978 dec a ; 1 = Nintendo
979 jr nz, .notNintendo
980 jr .doChecksum
981 .newLicensee
982 ld l, LOW(NewLicenseeCode)
983 ld a, [hli]
984 cp $30 ; ASCII '0'
985 jr nz, .notNintendo
986 ld a, [hl]
987 cp $31 ; ASCII '1'
988 jr nz, .notNintendo
989
990 .doChecksum
991 ld l, LOW(Title)
992 ld c, 16
993 xor a
994 .checksumLoop
995 add [hl]
996 inc l
997 dec c
998 jr nz, .checksumLoop
999 ldh [hTitleChecksum], a
1000 ld b, a
1001
1002 ; c = 0
1003 ld hl, TitleChecksums
1004
1005 .searchLoop
1006 ld a, l
1007 sub LOW(ChecksumsEnd) ; use sub to zero out a
1008 ret z
1009 ld a, [hli]
1010 cp b
1011 jr nz, .searchLoop
1012
1013 ; We might have a match, Do duplicate/4th letter check
1014 ld a, l
1015 sub FirstChecksumWithDuplicate - TitleChecksums + 1
1016 jr c, .match ; Does not have a duplicate, must be a match!
1017 ; Has a duplicate; check 4th letter
1018 push hl
1019 ld a, l
1020 add Dups4thLetterArray - FirstChecksumWithDuplicate - 1 ; -1 since hl was incremented
1021 ld l, a
1022 ld a, [hl]
1023 pop hl
1024 ld c, a
1025 ld a, [Title + 3] ; Get 4th letter
1026 cp c
1027 jr nz, .searchLoop ; Not a match, continue
1028
1029 .match
1030 ld a, l
1031 add PalettePerChecksum - TitleChecksums - 1; -1 since hl was incremented
1032 ld l, a
1033 ld a, b
1034 ldh [hTitleChecksum], a
1035 ld a, [hl]
1036 ret
1037
1038 .notNintendo
1039 xor a
1040 ret
1041
1042 ; optimizations in callers rely on this returning with b = 0
1043 GetPaletteCombo:
1044 ld hl, PaletteCombinations
1045 ld b, 0
1046 ld c, a
1047 add hl, bc
1048 ret
1049
1050 LoadPalettesFromIndex: ; a = index of combination
1051 call GetPaletteCombo
1052
1053 ; Obj Palettes
1054 ld e, 0
1055 .loadObjPalette
1056 ld a, [hli]
1057 push hl
1058 ld hl, Palettes
1059 ; b is already 0
1060 ld c, a
1061 add hl, bc
1062 ld d, 4 * 2
1063 ld c, LOW(rOBPI)
1064 call LoadPalettes
1065 pop hl
1066 bit OAMB_BANK1, e
1067 jr nz, .loadBGPalette
1068 ld e, OAMF_BANK1
1069 jr .loadObjPalette
1070 .loadBGPalette
1071 ;BG Palette
1072 ld c, [hl]
1073 ; b is already 0
1074 ld hl, Palettes
1075 add hl, bc
1076 ld d, 8
1077 jr LoadBGPalettes
1078
1079 LoadPalettesFromHRAM:
1080 ld hl, hBgPalettes
1081 ld d, hBgPalettesEnd - hBgPalettes
1082 LoadBGPalettes:
1083 ld e, 0
1084 ld c, LOW(rBGPI)
1085 LoadPalettes:
1086 ld a, $80
1087 or e
1088 ldh [c], a
1089 inc c
1090 .loop
1091 ld a, [hli]
1092 ldh [c], a
1093 dec d
1094 jr nz, .loop
1095 ret
1096
1097 ClearVRAMViaHDMA:
1098 ldh [rVBK], a
1099 ld hl, HDMAData
1100 _ClearVRAMViaHDMA:
1101 call WaitFrame ; Wait for vblank
1102 ld c, LOW(rHDMA1)
1103 ld b, 5
1104 .loop
1105 ld a, [hli]
1106 ldh [c], a
1107 inc c
1108 dec b
1109 jr nz, .loop
1110 ret
1111
1112 ; clobbers AF and HL
1113 GetInputPaletteIndex:
1114 ld a, P1F_GET_DPAD
1115 ldh [rJOYP], a
1116 ldh a, [rJOYP]
1117 cpl
1118 and $F
1119 ret z ; No direction keys pressed, no palette
1120
1121 ld l, 0
1122 .directionLoop
1123 inc l
1124 rra
1125 jr nc, .directionLoop
1126
1127 ; c = 1: Right, 2: Left, 3: Up, 4: Down
1128
1129 ld a, P1F_GET_BTN
1130 ldh [rJOYP], a
1131 ldh a, [rJOYP]
1132 cpl
1133 rla
1134 rla
1135 and $C
1136 add l
1137 ld l, a
1138 ldh a, [hInputPalette]
1139 cp l
1140 ret z ; No change, don't load
1141 ld a, l
1142 ldh [hInputPalette], a
1143 ; Slide into change Animation Palette
1144
1145 ChangeAnimationPalette:
1146 push bc
1147 push de
1148 call GetKeyComboPalette
1149 call GetPaletteCombo
1150 inc l
1151 inc l
1152 ld c, [hl]
1153 ld hl, Palettes + 1
1154 add hl, bc
1155 ld a, [hld]
1156 cp $7F ; Is white color?
1157 jr nz, .isWhite
1158 inc hl
1159 inc hl
1160 .isWhite
1161 push af
1162 ld a, [hli]
1163
1164 push hl
1165 ld hl, hBgPalettes ; First color, all palettes
1166 call ReplaceColorInAllPalettes
1167 ld l, LOW(hBgPalettes + 2) ; Second color, all palettes
1168 call ReplaceColorInAllPalettes
1169 pop hl
1170 ldh [hBgPalettes + 6], a ; Fourth color, first palette
1171
1172 ld a, [hli]
1173 push hl
1174 ld hl, hBgPalettes + 1 ; First color, all palettes
1175 call ReplaceColorInAllPalettes
1176 ld l, LOW(hBgPalettes + 3) ; Second color, all palettes
1177 call ReplaceColorInAllPalettes
1178 pop hl
1179 ldh [hBgPalettes + 7], a ; Fourth color, first palette
1180
1181 pop af
1182 jr z, .isNotWhite
1183 inc hl
1184 inc hl
1185 .isNotWhite
1186 ; Mixing code by ISSOtm
1187 ldh a, [hBgPalettes + 7 * 8 + 2]
1188 and ~$21
1189 ld b, a
1190 ld a, [hli]
1191 and ~$21
1192 add a, b
1193 ld b, a
1194 ld a, [hBgPalettes + 7 * 8 + 3]
1195 res 2, a ; and ~$04, but not touching carry
1196 ld c, [hl]
1197 res 2, c ; and ~$04, but not touching carry
1198 adc a, c
1199 rra ; Carry sort of "extends" the accumulator, we're bringing that bit back home
1200 ld [hBgPalettes + 7 * 8 + 3], a
1201 ld a, b
1202 rra
1203 ld [hBgPalettes + 7 * 8 + 2], a
1204 dec l
1205
1206 ld a, [hli]
1207 ldh [hBgPalettes + 7 * 8 + 6], a ; Fourth color, 7th palette
1208 ld a, [hli]
1209 ldh [hBgPalettes + 7 * 8 + 7], a ; Fourth color, 7th palette
1210
1211 ld a, [hli]
1212 ldh [hBgPalettes + 4], a ; Third color, first palette
1213 ld a, [hli]
1214 ldh [hBgPalettes + 5], a ; Third color, first palette
1215
1216
1217 call WaitFrame
1218 call LoadPalettesFromHRAM
1219 ; Delay the wait loop while the user is selecting a palette
1220 ld a, 48
1221 ldh [hWaitLoopCounter], a
1222 pop de
1223 pop bc
1224 ret
1225
1226 ReplaceColorInAllPalettes:
1227 ld de, 8
1228 ld c, e
1229 .loop
1230 ld [hl], a
1231 add hl, de
1232 dec c
1233 jr nz, .loop
1234 ret
1235
1236 LoadDMGTilemap:
1237 push af
1238 call WaitFrame
1239 ld a, $19 ; Trademark symbol tile ID
1240 ld [_SCRN0 + 8 * SCRN_VX_B + 16], a ; ... put in the superscript position
1241 ld hl, _SCRN0 + 9 * SCRN_VX_B + 15 ; Bottom right corner of the logo
1242 ld c, 12 ; Tiles in a logo row
1243 .tilemapLoop
1244 dec a
1245 jr z, .tilemapDone
1246 ldd [hl], a
1247 dec c
1248 jr nz, .tilemapLoop
1249 ld l, $0F ; Jump to top row
1250 jr .tilemapLoop
1251 .tilemapDone
1252 pop af
1253 ret
1254
1255 BootEnd:
1256 IF BootEnd > $0900
1257 FAIL "BootROM overflowed: {BootEnd}"
1258 ENDC
1259 ds $100 + $800 - @ ; Ensure that the ROM is padded up to standard size.
1260
1261 SECTION "HRAM", HRAM[_HRAM]
1262 hTitleChecksum:
1263 ds 1
1264 hBgPalettes:
1265 ds 8 * 4 * 2
1266 hBgPalettesEnd:
1267 hInputPalette:
1268 ds 1
1269 hWaitLoopCounter:
1270 ds 1
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.