From 19126df7f4b69ca8001b6d2ca6b2c703b7625195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20K=C4=85dzio=C5=82ka?= Date: Sun, 3 May 2020 22:41:56 +0200 Subject: [PATCH 01/10] Save 8 bytes in the CGB boot ROM --- BootROMs/cgb_boot.asm | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/BootROMs/cgb_boot.asm b/BootROMs/cgb_boot.asm index 6ae869b2..618e11a4 100644 --- a/BootROMs/cgb_boot.asm +++ b/BootROMs/cgb_boot.asm @@ -984,14 +984,13 @@ BrightenColor: and $1F cp $1F jr nz, .blueNotMaxed - res 0, c + dec c .blueNotMaxed ; Is green maxed? ld a, e - and $E0 cp $E0 - jr nz, .greenNotMaxed + jr c, .greenNotMaxed ld a, d and $3 cp $3 @@ -1007,18 +1006,13 @@ BrightenColor: res 2, b .redNotMaxed - ; Add de to bc - push hl - ld h, d - ld l, e - add hl, bc - ld d, h - ld e, l - pop hl - + ; add de, bc + ; ld [hli], de ld a, e + add c ld [hli], a ld a, d + adc b ld [hli], a ret @@ -1155,7 +1149,7 @@ ReplaceColorInAllPalettes: dec c jr nz, .loop ret - + LoadDMGTilemap: push af call WaitFrame From cb738190be6abca03d1cd3265440908107168a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20K=C4=85dzio=C5=82ka?= Date: Sun, 3 May 2020 22:44:13 +0200 Subject: [PATCH 02/10] Add a 2bpp CGB boot ROM logo, pending palettes --- BootROMs/SameBoyLogo.png | Bin 14763 -> 479 bytes BootROMs/cgb_boot.asm | 116 ++++++++++++++++++++++++++------------- BootROMs/pb12.py | 68 +++++++++++++++++++++++ Makefile | 13 ++--- 4 files changed, 152 insertions(+), 45 deletions(-) create mode 100644 BootROMs/pb12.py diff --git a/BootROMs/SameBoyLogo.png b/BootROMs/SameBoyLogo.png index 4bc9706080a1d5e161d506f2d2be6d9c8e1446d4..c7cfc087dbf7a26a2969fc463d116b9e28eb58ac 100644 GIT binary patch delta 465 zcmV;?0WSWlbKe7y7=Ho-0000_WgT_^000b7OjJex|Nnn~fBygg000170)~4400E9k zL_t(2&yA8XZo@DPMHzU|sHMA(LKiteI>gABqv&c1I&`dpB6F{x05ZBr`2CFIphJcl zW-MEeXKQ3lQsjN*%!4hpQ&S3sG} z^6VxHz^3k}8BhsS(Jj@7f)Dc4Cz~FVo7>Rf2rx_^Q}w%=4I_(c^4B(0xOv*U`OvMd zuWE)kbmkB!&3|3Hv*;eF4m9Dn!u~ zO32V{^YirP=K~A~#fBD}H?nKUF%Iq4y9kbaYQ6(34paiPDNr^e8o<%(0$d4jOWOm$ zj=5L>FZ$J|Bc1pQc=KLvfL`!fZ&qn_HC(2BxEwLy5=#35u>6jP-U$>M#%2~9leL~x z*UVWtYJLF4^3nnX&}Ra14CW{k86!XU`$=!6=YQ&Hl>c47@!eI<`B+HV00000NkvXX Hu0mjf?upU~ literal 14763 zcmeI3Z)_7~9LEp;L>R#cCPQJ-vp}L?dw1P+TaUJ6w1ZCQoTJDl5V+kv-7ahIj=S61 zO_L2wTtG2om>^;#z5o=>e1nl_l!QP+{1Y%lvWyUvCyV*4SD>(o!B#*4lw5lhSP$6yrGkYelFckP%>l6tF}(lS-*eTLzlZbrYHPhO(_WV28J1(XYB%Q>cwS&xI`?sf zDqs{a#dBt|E+X}i|_CWbh?!HobejwG%v4a$ujHol5hh@r{WGU~_yN#qX zHCbXn5~P4?nb60T^+BYuSl(K8xKygF)3h3T;2q?Mly#c%UL7zkz|^`82{iP;nJg+d zdA(D!G_zBi=DzdY)84(MBnpdDG!?sNS{ukH)7b2utj#Hf>xFfR zB*`jEa>QWu%c3RTPnIHWX&y~h62148rJzJ|$dZuIjFf1Fl$6*37+viMFoi}$>6D$& zsG63jN}w?kf(;%;kp(Fs*Cu!%x@&ljck@1$b&C?uyA$m-{yMP+NIt2~!4Zq0_9>|& zn$&GqelE5AfT>p3Ou#MB%-lr|DZ#ZNi$`rsA9re>qTl1R-$t*tpnSNTPHh` zigUi`qG1Ai`vqN-`!9bW<TSb#(f(3z!Ma{mtdKW1TuC$Hvd`Zvj&<-+0fcINzG`29DQzxwG%Fd9Y>g;z=bLst zb6$8@IHuB`vd*@G)61hqq$6j{t}*go-6?@=D|}{vk1I_6d8N2I@_XnZ2ZcL&$cfQ( zWDt}FHYT{Rh)@B+h0?&r1Q!+&Dj>K}8rYcN!XiQi1Q$vJ8xveuM5ut^LTO-Qf(wfX z6%bq~4QxzsVG*GMf(xaAjR`I+B2++dp){~D!G%SH3J5Ng1~w+Ru!v9r!G+Sm#sn7@ z5h@_KP#V~n;KCw81q2sL0~-@uSVX9R;6iC&V}c8d2o(@qC=F~(aA6Ul0)h*rfsF|+ zEFx4uaG^A?F~NmJgbD~Qlm<2?xUh&&0l|gRz{Ug@77;2SxKJ9{nBc-9LIngDN&_3; z6IVsy4M3p6*Z$J*{k}Iw7w&=Y2GUZrB}P$w@Lj@zw<&7kUwFMnQQa&>UEfMk!iN+! zUmMzTdKJ{(X^hmzGozc%p4k0#ebwokXYXF{E~GCF9sKjqqe};_ZU10k-ppA~y?4qN zd1Bepi)fZq`s#8JI9X?ogR5z*!0Mf_cwl)ur4faY3mu=I6C;s&nthpddy#4 zIeYNp`MYzMpW6M$@R9Ycx0jE6KKtg~TjJwu+?Q8h*{7WJ4d1%W&;9Gn#NR)yT<}X| q|J65BRq~ZvM=n-=HTda`G&Q(G{(bH7&EG-_RAWO^WO(J)9sdD_A1D9- diff --git a/BootROMs/cgb_boot.asm b/BootROMs/cgb_boot.asm index 618e11a4..68376150 100644 --- a/BootROMs/cgb_boot.asm +++ b/BootROMs/cgb_boot.asm @@ -87,20 +87,24 @@ ELSE .tilemapRowLoop + call .write_with_palette + + ; Repeat the 3 tiles common between E and B. This saves 27 bytes after + ; compression, with a cost of 17 bytes of code. push af - ; Switch to second VRAM Bank - ld a, 1 - ldh [$4F], a - ld [hl], 8 - ; Switch to back first VRAM Bank - xor a - ldh [$4F], a + sub $20 + sub $3 + jr nc, .notspecial + add $20 + call .write_with_palette + dec c +.notspecial pop af - ldi [hl], a - add d + + add d ; d = 3 for SameBoy logo, d = 1 for Nintendo logo dec c jr nz, .tilemapRowLoop - sub 47 + sub 44 push de ld de, $10 add hl, de @@ -116,6 +120,19 @@ ELSE ld l, $a7 ld bc, $0107 jr .tilemapRowLoop + +.write_with_palette + push af + ; Switch to second VRAM Bank + ld a, 1 + ldh [$4F], a + ld [hl], 8 + ; Switch to back first VRAM Bank + xor a + ldh [$4F], a + pop af + ldi [hl], a + ret .endTilemap ENDC @@ -532,7 +549,7 @@ TrademarkSymbol: db $3c,$42,$b9,$a5,$b9,$a5,$42,$3c SameBoyLogo: - incbin "SameBoyLogo.pb8" + incbin "SameBoyLogo.pb12" AnimationColors: dw $7FFF ; White @@ -634,30 +651,28 @@ ReadCGBLogoHalfTile: ld a, e ret -; LoadTileset using PB8 codec, 2019 Damian Yerrick -; -; The logo is compressed using PB8, a form of RLE with unary-coded -; run lengths. Each block representing 8 bytes consists of a control -; byte, where each bit (MSB to LSB) is 0 for literal or 1 for repeat -; previous, followed by the literals in that block. +; LoadTileset using PB12 codec, 2020 Jakub Kądziołka +; (based on PB8 codec, 2019 Damian Yerrick) SameBoyLogo_dst = $8080 SameBoyLogo_length = (128 * 24) / 64 LoadTileset: ld hl, SameBoyLogo - ld de, SameBoyLogo_dst + ld de, SameBoyLogo_dst - 1 ld c, SameBoyLogo_length -.pb8BlockLoop: - ; Register map for PB8 decompression +.refill + ; Register map for PB12 decompression ; HL: source address in boot ROM ; DE: destination address in VRAM ; A: Current literal value ; B: Repeat bits, terminated by 1000... - ; C: Number of 8-byte blocks left in this block ; Source address in HL lets the repeat bits go straight to B, ; bypassing A and avoiding spilling registers to the stack. ld b, [hl] + dec b + jr z, .sameboyLogoEnd + inc b inc hl ; Shift a 1 into lower bit of shift value. Once this bit @@ -665,26 +680,53 @@ LoadTileset: scf rl b -.pb8BitLoop: +.loop ; If not a repeat, load a literal byte - jr c,.pb8Repeat - ld a, [hli] -.pb8Repeat: - ; Decompressed data uses colors 0 and 1, so write once, inc twice - ld [de], a - inc de - inc de + jr c, .simple_repeat sla b - jr nz, .pb8BitLoop - - dec c - jr nz, .pb8BlockLoop - -; End PB8 decoding. The rest uses HL as the destination - ld h, d - ld l, e + jr c, .shifty_repeat + ld a, [hli] + jr .got_byte +.shifty_repeat + sla b + jr nz, .no_refill_during_shift + ld b, [hl] ; see above. Also, no, factoring it out into a callable + inc hl ; routine doesn't save bytes, even with conditional calls + scf + rl b +.no_refill_during_shift + ld c, a + jr nc, .shift_left + srl a + db $fe ; eat the add a with cp d8 +.shift_left + add a + sla b + jr c, .go_and + or c + db $fe ; eat the and c with cp d8 +.go_and + and c + jr .got_byte +.simple_repeat + sla b + jr c, .got_byte + ; far repeat + dec de + ld a, [de] + inc de +.got_byte + inc de + ld [de], a + sla b + jr nz, .loop + jr .refill +; End PB12 decoding. The rest uses HL as the destination .sameboyLogoEnd + ld h, d + ld l, $80 + ; Copy (unresized) ROM logo ld de, $104 .CGBROMLogoLoop diff --git a/BootROMs/pb12.py b/BootROMs/pb12.py new file mode 100644 index 00000000..0c06538c --- /dev/null +++ b/BootROMs/pb12.py @@ -0,0 +1,68 @@ +import sys + +def opts(byte): + # top bit: 0 = left, 1 = right + # bottom bit: 0 = or, 1 = and + if byte is None: return [] + return [ + byte | (byte << 1) & 0xff, + byte & (byte << 1), + byte | (byte >> 1) & 0xff, + byte & (byte >> 1), + ] + +def pb12(data): + data = iter(data) + + literals = bytearray() + bits = 0 + control = 0 + prev = [None, None] + gotta_end = False + + chunk = bytearray() + while True: + try: + byte = next(data) + except StopIteration: + if bits == 0: break + byte = 0 + chunk.append(byte) + + if byte in prev: + bits += 2 + control <<= 1 + control |= 1 + control <<= 1 + if prev[1] == byte: + control |= 1 # 10 = out[-2], 11 = out[-1] + else: + bits += 2 + control <<= 2 + options = opts(prev[1]) + if byte in options: + # 01 = modify + control |= 1 + + bits += 2 + control <<= 2 + control |= options.index(byte) + else: + # 00 = literal + literals.append(byte) + prev = [prev[1], byte] + if bits >= 8: + outctl = control >> (bits - 8) + assert outctl != 1 # that's the end byte + yield bytes([outctl]) + literals + bits -= 8 + control &= (1 << bits) - 1 + literals = bytearray() + chunk = bytearray() + yield b'\x01' + +_, infile, outfile = sys.argv +with open(infile, 'rb') as f: + data = f.read() +with open(outfile, 'wb') as f: + f.writelines(pb12(data)) diff --git a/Makefile b/Makefile index afc8d897..1f818628 100644 --- a/Makefile +++ b/Makefile @@ -382,21 +382,18 @@ $(BIN)/SDL/Shaders: Shaders # Boot ROMs -$(OBJ)/%.1bpp: %.png +$(OBJ)/%.2bpp: %.png -@$(MKDIR) -p $(dir $@) - rgbgfx -d 1 -h -o $@ $< + rgbgfx -h -u -o $@ $< -$(OBJ)/BootROMs/SameBoyLogo.pb8: $(OBJ)/BootROMs/SameBoyLogo.1bpp $(PB8_COMPRESS) - $(realpath $(PB8_COMPRESS)) -l 384 $< $@ - -$(PB8_COMPRESS): BootROMs/pb8.c - $(CC) $< -o $@ +$(OBJ)/BootROMs/SameBoyLogo.pb12: $(OBJ)/BootROMs/SameBoyLogo.2bpp BootROMs/pb12.py + python3 BootROMs/pb12.py $< $@ $(BIN)/BootROMs/agb_boot.bin: BootROMs/cgb_boot.asm $(BIN)/BootROMs/cgb_boot_fast.bin: BootROMs/cgb_boot.asm $(BIN)/BootROMs/sgb2_boot: BootROMs/sgb_boot.asm -$(BIN)/BootROMs/%.bin: BootROMs/%.asm $(OBJ)/BootROMs/SameBoyLogo.pb8 +$(BIN)/BootROMs/%.bin: BootROMs/%.asm $(OBJ)/BootROMs/SameBoyLogo.pb12 -@$(MKDIR) -p $(dir $@) rgbasm -i $(OBJ)/BootROMs/ -i BootROMs/ -o $@.tmp $< rgblink -o $@.tmp2 $@.tmp From b057e0d10af8394671e2af8d463c2f948e860f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20K=C4=85dzio=C5=82ka?= Date: Sun, 3 May 2020 23:07:53 +0200 Subject: [PATCH 03/10] Save 4 more bytes in the CGB boot ROM --- BootROMs/cgb_boot.asm | 52 ++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/BootROMs/cgb_boot.asm b/BootROMs/cgb_boot.asm index 68376150..1d9cc6a8 100644 --- a/BootROMs/cgb_boot.asm +++ b/BootROMs/cgb_boot.asm @@ -21,7 +21,7 @@ Start: ldh [InputPalette], a ; Clear title checksum ldh [TitleChecksum], a - + ; Clear OAM ld h, $fe ld c, $a0 @@ -753,29 +753,6 @@ ReadTrademarkSymbol: jr nz, .loadTrademarkSymbolLoop ret -LoadObjPalettes: - ld c, $6A - jr LoadPalettes - -LoadBGPalettes64: - ld d, 64 - -LoadBGPalettes: - ld e, 0 - ld c, $68 - -LoadPalettes: - ld a, $80 - or e - ld [c], a - inc c -.loop - ld a, [hli] - ld [c], a - dec d - jr nz, .loop - ret - DoIntroAnimation: ; Animate the intro ld a, 1 @@ -902,8 +879,7 @@ EmulateDMG: call LoadPalettesFromIndex ld a, 4 ; Set the final values for DMG mode - ld d, 0 - ld e, $8 + ld de, 8 ld l, $7c ret @@ -997,7 +973,8 @@ LoadPalettesFromIndex: ; a = index of combination ld c, a add hl, bc ld d, 8 - call LoadObjPalettes + ld c, $6A + call LoadPalettes pop hl bit 3, e jr nz, .loadBGPalette @@ -1011,7 +988,26 @@ LoadPalettesFromIndex: ; a = index of combination ld c, a add hl, bc ld d, 8 - jp LoadBGPalettes + jr LoadBGPalettes + +LoadBGPalettes64: + ld d, 64 + +LoadBGPalettes: + ld e, 0 + ld c, $68 + +LoadPalettes: + ld a, $80 + or e + ld [c], a + inc c +.loop + ld a, [hli] + ld [c], a + dec d + jr nz, .loop + ret BrightenColor: ld a, [hli] From 2225fd114c795a4a607fa54267a2a695c80a83d6 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Mon, 4 May 2020 02:07:19 +0300 Subject: [PATCH 04/10] Handle 2bpp palettes --- BootROMs/cgb_boot.asm | 74 +++++++++++++++++++------------------------ BootROMs/pb12.py | 2 +- 2 files changed, 33 insertions(+), 43 deletions(-) diff --git a/BootROMs/cgb_boot.asm b/BootROMs/cgb_boot.asm index 1d9cc6a8..94087884 100644 --- a/BootROMs/cgb_boot.asm +++ b/BootROMs/cgb_boot.asm @@ -138,41 +138,24 @@ ENDC ; Expand Palettes ld de, AnimationColors - ld c, 8 + ld c, 16 ld hl, BgPalettes xor a .expandPalettesLoop: -IF !DEF(FAST) cpl -ENDC - ; One white + ; One white or black ldi [hl], a ldi [hl], a - -IF DEF(FAST) - ; 3 more whites - ldi [hl], a - ldi [hl], a - ldi [hl], a - ldi [hl], a - ldi [hl], a - ldi [hl], a -ELSE - ; The actual color + + ; One color + push af ld a, [de] inc de ldi [hl], a ld a, [de] inc de ldi [hl], a - - xor a - ; Two blacks - ldi [hl], a - ldi [hl], a - ldi [hl], a - ldi [hl], a -ENDC + pop af dec c jr nz, .expandPalettesLoop @@ -551,19 +534,20 @@ TrademarkSymbol: SameBoyLogo: incbin "SameBoyLogo.pb12" -AnimationColors: - dw $7FFF ; White - dw $774F ; Cyan - dw $22C7 ; Green - dw $039F ; Yellow - dw $017D ; Orange - dw $241D ; Red - dw $6D38 ; Purple - dw $7102 ; Blue -AnimationColorsEnd: +animation_color: MACRO + dw ((\1) >> 1) | $4210, (\1) +ENDM -DMGPalettes: - dw $7FFF, $32BF, $00D0, $0000 +AnimationColors: + animation_color $7FFF, ($7FFF >> 1) ; White + animation_color $774F, ($774F >> 1) ; Cyan + animation_color $22C7, ($22C7 >> 1) ; Green + animation_color $039F, ($039F >> 1) ; Yellow + animation_color $017D, ($017D >> 1) ; Orange + animation_color $241D, ($241D >> 1) ; Red + animation_color $6D38, ($6D38 >> 1) ; Purple + animation_color $7102, ($7102 >> 1) ; Blue +AnimationColorsEnd: ; Helper Functions DoubleBitsAndWriteRowTwice: @@ -1140,27 +1124,33 @@ ChangeAnimationPalette: .isWhite push af ld a, [hli] + push hl - ld hl, BgPalettes ; First color, all palette + ld hl, BgPalettes ; First color, all palettes + call ReplaceColorInAllPalettes + ld l, LOW(BgPalettes + 2) ; Second color, all palettes call ReplaceColorInAllPalettes pop hl - ldh [BgPalettes + 2], a ; Second color, first palette + ldh [BgPalettes + 6], a ; Fourth color, first palette ld a, [hli] push hl - ld hl, BgPalettes + 1 ; First color, all palette + ld hl, BgPalettes + 1 ; First color, all palettes + call ReplaceColorInAllPalettes + ld l, LOW(BgPalettes + 3) ; Second color, all palettes call ReplaceColorInAllPalettes pop hl - ldh [BgPalettes + 3], a ; Second color, first palette + ldh [BgPalettes + 7], a ; Fourth color, first palette + pop af jr z, .isNotWhite inc hl inc hl .isNotWhite ld a, [hli] - ldh [BgPalettes + 7 * 8 + 2], a ; Second color, 7th palette + ldh [BgPalettes + 7 * 8 + 6], a ; Fourth color, 7th palette ld a, [hli] - ldh [BgPalettes + 7 * 8 + 3], a ; Second color, 7th palette + ldh [BgPalettes + 7 * 8 + 7], a ; Fourth color, 7th palette ld a, [hli] ldh [BgPalettes + 4], a ; Third color, first palette ld a, [hl] @@ -1180,7 +1170,7 @@ ChangeAnimationPalette: ReplaceColorInAllPalettes: ld de, 8 - ld c, 8 + ld c, e .loop ld [hl], a add hl, de diff --git a/BootROMs/pb12.py b/BootROMs/pb12.py index 0c06538c..dc53d6b9 100644 --- a/BootROMs/pb12.py +++ b/BootROMs/pb12.py @@ -63,6 +63,6 @@ def pb12(data): _, infile, outfile = sys.argv with open(infile, 'rb') as f: - data = f.read() + data = f.read().rstrip(b'\x00') with open(outfile, 'wb') as f: f.writelines(pb12(data)) From 72a90ba91c8b8ee07859fc25f6b536a5f5afaaad Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Mon, 4 May 2020 02:17:03 +0300 Subject: [PATCH 05/10] Hacky color blending --- BootROMs/cgb_boot.asm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/BootROMs/cgb_boot.asm b/BootROMs/cgb_boot.asm index 94087884..cbbcf962 100644 --- a/BootROMs/cgb_boot.asm +++ b/BootROMs/cgb_boot.asm @@ -1093,12 +1093,11 @@ GetInputPaletteIndex: ; Slide into change Animation Palette ChangeAnimationPalette: - push af push hl push bc push de ld hl, KeyCombinationPalettes - 1 ; Input palettes are 1-based, 0 means nothing down - ld c ,a + ld c, a ld b, 0 add hl, bc ld a, [hl] @@ -1149,6 +1148,7 @@ ChangeAnimationPalette: .isNotWhite ld a, [hli] ldh [BgPalettes + 7 * 8 + 6], a ; Fourth color, 7th palette + ldh [BgPalettes + 7 * 8 + 2], a ; Second color, half, 7th palette; rough color mixing ld a, [hli] ldh [BgPalettes + 7 * 8 + 7], a ; Fourth color, 7th palette ld a, [hli] @@ -1165,7 +1165,6 @@ ChangeAnimationPalette: pop de pop bc pop hl - pop af ret ReplaceColorInAllPalettes: From f46f138e9fbda089a1a9f71b88d608b38b932315 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Mon, 4 May 2020 23:54:43 +0300 Subject: [PATCH 06/10] Clear VRAM correctly --- BootROMs/cgb_boot.asm | 155 ++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 81 deletions(-) diff --git a/BootROMs/cgb_boot.asm b/BootROMs/cgb_boot.asm index cbbcf962..33e18e56 100644 --- a/BootROMs/cgb_boot.asm +++ b/BootROMs/cgb_boot.asm @@ -16,6 +16,15 @@ Start: xor a call ClearMemoryPage ld [c], a + + ld hl, $FF30 +; Init waveform + ld c, $10 +.waveformLoop + ldi [hl], a + cpl + dec c + jr nz, .waveformLoop ; Clear chosen input palette ldh [InputPalette], a @@ -40,8 +49,6 @@ Start: ld a, $77 ldh [$24], a - call InitWaveform - ; Init BG palette ld a, $fc ldh [$47], a @@ -776,25 +783,68 @@ IF !DEF(FAST) ld hl, BgPalettes .frameLoop push bc - call BrightenColor + + ; Brighten Color + ld a, [hli] + ld e, a + ld a, [hld] + ld d, a + ; RGB(1,1,1) + ld bc, $421 + + ; Is blue maxed? + ld a, e + and $1F + cp $1F + jr nz, .blueNotMaxed + dec c +.blueNotMaxed + + ; Is green maxed? + ld a, e + cp $E0 + jr c, .greenNotMaxed + ld a, d + and $3 + cp $3 + jr nz, .greenNotMaxed + res 5, c +.greenNotMaxed + + ; Is red maxed? + ld a, d + and $7C + cp $7C + jr nz, .redNotMaxed + res 2, b +.redNotMaxed + + ; add de, bc + ; ld [hli], de + ld a, e + add c + ld [hli], a + ld a, d + adc b + ld [hli], a pop bc + dec c jr nz, .frameLoop - call WaitFrame call WaitFrame ld hl, BgPalettes call LoadBGPalettes64 + call WaitFrame dec b jr nz, .fadeLoop ENDC + ld a, 1 call ClearVRAMViaHDMA - ; Select the first bank - xor a - ldh [$4F], a - cpl + call _ClearVRAMViaHDMA + call ClearVRAMViaHDMA ; A = $40, so it's bank 0 + ; A should be $FF ldh [$00], a - call ClearVRAMViaHDMA ; Final values for CGB mode ld de, $ff56 @@ -993,70 +1043,24 @@ LoadPalettes: jr nz, .loop ret -BrightenColor: - ld a, [hli] - ld e, a - ld a, [hld] - ld d, a - ; RGB(1,1,1) - ld bc, $421 - - ; Is blue maxed? - ld a, e - and $1F - cp $1F - jr nz, .blueNotMaxed - dec c -.blueNotMaxed - - ; Is green maxed? - ld a, e - cp $E0 - jr c, .greenNotMaxed - ld a, d - and $3 - cp $3 - jr nz, .greenNotMaxed - res 5, c -.greenNotMaxed - - ; Is red maxed? - ld a, d - and $7C - cp $7C - jr nz, .redNotMaxed - res 2, b -.redNotMaxed - - ; add de, bc - ; ld [hli], de - ld a, e - add c - ld [hli], a - ld a, d - adc b - ld [hli], a - ret - ClearVRAMViaHDMA: - ld hl, $FF51 - - ; Src - ld a, $88 - ld [hli], a - xor a - ld [hli], a - - ; Dest - ld a, $98 - ld [hli], a - ld a, $A0 - ld [hli], a - - ; Do it - ld [hl], $12 + ldh [$4F], a + ld hl, HDMAData +_ClearVRAMViaHDMA: + ld c, $51 + ld b, 5 +.loop + ld a, [hli] + ldh [c], a + inc c + dec b + jr nz, .loop ret +HDMAData: + db $88, $00, $98, $A0, $12 + db $88, $00, $80, $00, $40 + GetInputPaletteIndex: ld a, $20 ; Select directions ldh [$00], a @@ -1196,17 +1200,6 @@ LoadDMGTilemap: pop af ret -InitWaveform: - ld hl, $FF30 -; Init waveform - xor a - ld c, $10 -.waveformLoop - ldi [hl], a - cpl - dec c - jr nz, .waveformLoop - ret SECTION "ROMMax", ROM0[$900] ; Prevent us from overflowing From a3f261184d2a732b32eb30d6b3538b04fba31988 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Tue, 5 May 2020 01:44:48 +0300 Subject: [PATCH 07/10] Optimize more --- BootROMs/cgb_boot.asm | 65 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/BootROMs/cgb_boot.asm b/BootROMs/cgb_boot.asm index 33e18e56..a83c27a3 100644 --- a/BootROMs/cgb_boot.asm +++ b/BootROMs/cgb_boot.asm @@ -6,8 +6,7 @@ Start: ld sp, $fffe ; Clear memory VRAM - ld hl, $8000 - call ClearMemoryPage + call ClearMemoryPage8000 ld a, 2 ld c, $70 ld [c], a @@ -74,9 +73,7 @@ Start: ; Clear the second VRAM bank ld a, 1 ldh [$4F], a - xor a - ld hl, $8000 - call ClearMemoryPage + call ClearMemoryPage8000 call LoadTileset ld b, 3 @@ -177,8 +174,10 @@ ENDC IF !DEF(FAST) call DoIntroAnimation + ld a, 45 + ldh [WaitLoopCounter], a ; Wait ~0.75 seconds - ld b, 45 + ld b, a call WaitBFrames ; Play first sound @@ -189,10 +188,6 @@ IF !DEF(FAST) ; Play second sound ld a, $c1 call PlaySound - -; Wait ~0.5 seconds - ld a, 30 - ldh [WaitLoopCounter], a .waitLoop call GetInputPaletteIndex @@ -602,8 +597,11 @@ PlaySound: ldh [$14], a ret +ClearMemoryPage8000: + ld hl, $8000 ; Clear from HL to HL | 0x2000 ClearMemoryPage: + xor a ldi [hl], a bit 5, h jr z, ClearMemoryPage @@ -781,6 +779,7 @@ IF !DEF(FAST) .fadeLoop ld c, 32 ; 32 colors to fade ld hl, BgPalettes + push hl .frameLoop push bc @@ -833,7 +832,7 @@ IF !DEF(FAST) jr nz, .frameLoop call WaitFrame - ld hl, BgPalettes + pop hl call LoadBGPalettes64 call WaitFrame dec b @@ -888,6 +887,14 @@ ENDC ldh [$4C], a ld a, $1 ret + +GetKeyComboPalette: + ld hl, KeyCombinationPalettes - 1 ; Return value is 1-based, 0 means nothing down + ld c ,a + ld b, 0 + add hl, bc + ld a, [hl] + ret EmulateDMG: ld a, 1 @@ -900,11 +907,7 @@ EmulateDMG: ldh a, [InputPalette] and a jr z, .nothingDown - ld hl, KeyCombinationPalettes - 1 ; Return value is 1-based, 0 means nothing down - ld c ,a - ld b, 0 - add hl, bc - ld a, [hl] + call GetKeyComboPalette jr .paletteFromKeys .nothingDown ld a, b @@ -985,17 +988,21 @@ GetPaletteIndex: .notNintendo xor a ret - -LoadPalettesFromIndex: ; a = index of combination + +GetPaletteCombo: ld b, a ; Multiply by 3 add b add b - + ld hl, PaletteCombinations ld b, 0 ld c, a add hl, bc + ret + +LoadPalettesFromIndex: ; a = index of combination + call GetPaletteCombo ; Obj Palettes ld e, 0 @@ -1100,20 +1107,10 @@ ChangeAnimationPalette: push hl push bc push de - ld hl, KeyCombinationPalettes - 1 ; Input palettes are 1-based, 0 means nothing down - ld c, a - ld b, 0 - add hl, bc - ld a, [hl] - ld b, a - ; Multiply by 3 - add b - add b - - ld hl, PaletteCombinations + 2; Background Palette - ld b, 0 - ld c, a - add hl, bc + call GetKeyComboPalette + call GetPaletteCombo + inc l + inc l ld a, [hl] ld hl, Palettes + 1 ld b, 0 @@ -1164,7 +1161,7 @@ ChangeAnimationPalette: ld hl, BgPalettes call LoadBGPalettes64 ; Delay the wait loop while the user is selecting a palette - ld a, 30 + ld a, 45 ldh [WaitLoopCounter], a pop de pop bc From 730567dc609a1213d6395ca92d4be00c072a2817 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Wed, 6 May 2020 01:06:22 +0300 Subject: [PATCH 08/10] Proper color mixing --- BootROMs/cgb_boot.asm | 198 ++++++++++++++++++++++++------------------ 1 file changed, 115 insertions(+), 83 deletions(-) diff --git a/BootROMs/cgb_boot.asm b/BootROMs/cgb_boot.asm index a83c27a3..332279ca 100644 --- a/BootROMs/cgb_boot.asm +++ b/BootROMs/cgb_boot.asm @@ -10,35 +10,16 @@ Start: ld a, 2 ld c, $70 ld [c], a -; Clear RAM Bank 2 (Like the original boot ROM +; Clear RAM Bank 2 (Like the original boot ROM) ld h, $D0 - xor a call ClearMemoryPage ld [c], a - ld hl, $FF30 -; Init waveform - ld c, $10 -.waveformLoop - ldi [hl], a - cpl - dec c - jr nz, .waveformLoop - ; Clear chosen input palette ldh [InputPalette], a ; Clear title checksum ldh [TitleChecksum], a - -; Clear OAM - ld h, $fe - ld c, $a0 -.clearOAMLoop - ldi [hl], a - dec c - jr nz, .clearOAMLoop - -; Init Audio + ld a, $80 ldh [$26], a ldh [$11], a @@ -47,6 +28,23 @@ Start: ldh [$25], a ld a, $77 ldh [$24], a + ld hl, $FF30 +; Init waveform + ld c, $10 +.waveformLoop + ldi [hl], a + cpl + dec c + jr nz, .waveformLoop + + +; Clear OAM + ld h, $fe + ld c, $a0 +.clearOAMLoop + ldi [hl], a + dec c + jr nz, .clearOAMLoop ; Init BG palette ld a, $fc @@ -142,25 +140,44 @@ ENDC ; Expand Palettes ld de, AnimationColors - ld c, 16 + ld c, 8 ld hl, BgPalettes xor a .expandPalettesLoop: cpl - ; One white or black - ldi [hl], a - ldi [hl], a + ; One white + ld [hli], a + ld [hli], a + + ; Mixed with white + ld a, [de] + inc e + or $20 + ld b, a + + ld a, [de] + dec e + or $84 + rra + rr b + ld [hl], b + inc l + ld [hli], a + + ; One black + xor a + ld [hli], a + ld [hli], a ; One color - push af ld a, [de] - inc de - ldi [hl], a + inc e + ld [hli], a ld a, [de] - inc de - ldi [hl], a - pop af - + inc e + ld [hli], a + + xor a dec c jr nz, .expandPalettesLoop @@ -200,6 +217,9 @@ ELSE call PlaySound ENDC call Preboot +IF DEF(AGB) + ld b, 1 +ENDC ; Will be filled with NOPs @@ -208,7 +228,6 @@ BootGame: ldh [$50], a SECTION "MoreStuff", ROM0[$200] - ; Game Palettes Data TitleChecksums: db $00 ; Default @@ -512,43 +531,40 @@ Palettes: dw $4778, $3290, $1D87, $0861 ; DMG LCD KeyCombinationPalettes - db 1 ; Right - db 48 ; Left - db 5 ; Up - db 8 ; Down - db 0 ; Right + A - db 40 ; Left + A - db 43 ; Up + A - db 3 ; Down + A - db 6 ; Right + B - db 7 ; Left + B - db 28 ; Up + B - db 49 ; Down + B + db 1 * 3 ; Right + db 48 * 3 ; Left + db 5 * 3 ; Up + db 8 * 3 ; Down + db 0 * 3 ; Right + A + db 40 * 3 ; Left + A + db 43 * 3 ; Up + A + db 3 * 3 ; Down + A + db 6 * 3 ; Right + B + db 7 * 3 ; Left + B + db 28 * 3 ; Up + B + db 49 * 3 ; Down + B ; SameBoy "Exclusives" - db 51 ; Right + A + B - db 52 ; Left + A + B - db 53 ; Up + A + B - db 54 ; Down + A + B - + db 51 * 3 ; Right + A + B + db 52 * 3 ; Left + A + B + db 53 * 3 ; Up + A + B + db 54 * 3 ; Down + A + B + TrademarkSymbol: db $3c,$42,$b9,$a5,$b9,$a5,$42,$3c SameBoyLogo: incbin "SameBoyLogo.pb12" -animation_color: MACRO - dw ((\1) >> 1) | $4210, (\1) -ENDM AnimationColors: - animation_color $7FFF, ($7FFF >> 1) ; White - animation_color $774F, ($774F >> 1) ; Cyan - animation_color $22C7, ($22C7 >> 1) ; Green - animation_color $039F, ($039F >> 1) ; Yellow - animation_color $017D, ($017D >> 1) ; Orange - animation_color $241D, ($241D >> 1) ; Red - animation_color $6D38, ($6D38 >> 1) ; Purple - animation_color $7102, ($7102 >> 1) ; Blue + dw $7FFF ; White + dw $774F ; Cyan + dw $22C7 ; Green + dw $039F ; Yellow + dw $017D ; Orange + dw $241D ; Red + dw $6D38 ; Purple + dw $7102 ; Blue AnimationColorsEnd: ; Helper Functions @@ -842,11 +858,13 @@ ENDC call ClearVRAMViaHDMA call _ClearVRAMViaHDMA call ClearVRAMViaHDMA ; A = $40, so it's bank 0 + cpl ; A should be $FF ldh [$00], a ; Final values for CGB mode - ld de, $ff56 + ld d, a + ld e, c ld l, $0d ld a, [$143] @@ -870,7 +888,7 @@ IF DEF(AGB) ld c, a add a, $11 ld h, c - ld b, 1 + ; B is set to 1 after ret ELSE ; Set registers to match the original CGB boot ; AF = $1180, C = 0 @@ -990,11 +1008,6 @@ GetPaletteIndex: ret GetPaletteCombo: - ld b, a - ; Multiply by 3 - add b - add b - ld hl, PaletteCombinations ld b, 0 ld c, a @@ -1064,10 +1077,6 @@ _ClearVRAMViaHDMA: jr nz, .loop ret -HDMAData: - db $88, $00, $98, $A0, $12 - db $88, $00, $80, $00, $40 - GetInputPaletteIndex: ld a, $20 ; Select directions ldh [$00], a @@ -1104,7 +1113,6 @@ GetInputPaletteIndex: ; Slide into change Animation Palette ChangeAnimationPalette: - push hl push bc push de call GetKeyComboPalette @@ -1147,16 +1155,37 @@ ChangeAnimationPalette: inc hl inc hl .isNotWhite + ; Mixing code by ISSOtm + ldh a, [BgPalettes + 7 * 8 + 2] + and ~$21 + ld b, a + ld a, [hli] + and ~$21 + add a, b + ld b, a + ld a, [BgPalettes + 7 * 8 + 3] + res 2, a ; and ~$04, but not touching carry + ld c, [hl] + res 2, c ; and ~$04, but not touching carry + adc a, c + rra ; Carry sort of "extends" the accumulator, we're bringing that bit back home + ld [BgPalettes + 7 * 8 + 3], a + ld a, b + rra + ld [BgPalettes + 7 * 8 + 2], a + dec l + ld a, [hli] ldh [BgPalettes + 7 * 8 + 6], a ; Fourth color, 7th palette - ldh [BgPalettes + 7 * 8 + 2], a ; Second color, half, 7th palette; rough color mixing ld a, [hli] ldh [BgPalettes + 7 * 8 + 7], a ; Fourth color, 7th palette + ld a, [hli] ldh [BgPalettes + 4], a ; Third color, first palette - ld a, [hl] + ld a, [hli] ldh [BgPalettes + 5], a ; Third color, first palette + call WaitFrame ld hl, BgPalettes call LoadBGPalettes64 @@ -1165,7 +1194,6 @@ ChangeAnimationPalette: ldh [WaitLoopCounter], a pop de pop bc - pop hl ret ReplaceColorInAllPalettes: @@ -1181,7 +1209,7 @@ ReplaceColorInAllPalettes: LoadDMGTilemap: push af call WaitFrame - ld a,$19 ; Trademark symbol + ld a, $19 ; Trademark symbol ld [$9910], a ; ... put in the superscript position ld hl,$992f ; Bottom right corner of the logo ld c,$c ; Tiles in a logo row @@ -1191,16 +1219,20 @@ LoadDMGTilemap: ldd [hl], a dec c jr nz, .tilemapLoop - ld l,$0f ; Jump to top row + ld l, $0f ; Jump to top row jr .tilemapLoop .tilemapDone pop af ret - - -SECTION "ROMMax", ROM0[$900] - ; Prevent us from overflowing - ds 1 + +HDMAData: + db $88, $00, $98, $A0, $12 + db $88, $00, $80, $00, $40 + +BootEnd: +IF BootEnd > $900 + FAIL "BootROM overflowed: {BootEnd}" +ENDC SECTION "HRAM", HRAM[$FF80] TitleChecksum: From 184743637eebf34f5fc673057dbca954037f3599 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Wed, 6 May 2020 01:10:46 +0300 Subject: [PATCH 09/10] Fix silly regression --- BootROMs/cgb_boot.asm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/BootROMs/cgb_boot.asm b/BootROMs/cgb_boot.asm index 332279ca..f07fbcfd 100644 --- a/BootROMs/cgb_boot.asm +++ b/BootROMs/cgb_boot.asm @@ -858,8 +858,7 @@ ENDC call ClearVRAMViaHDMA call _ClearVRAMViaHDMA call ClearVRAMViaHDMA ; A = $40, so it's bank 0 - cpl - ; A should be $FF + ld a, $ff ldh [$00], a ; Final values for CGB mode From 7cff35368d26e87a0638e9be2d56642665af0ac0 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Wed, 6 May 2020 23:30:01 +0300 Subject: [PATCH 10/10] Port to C to remove the Python dep, remove leftovers --- BootROMs/pb12.c | 95 +++++++++++++ BootROMs/pb12.py | 68 ---------- BootROMs/pb8.c | 341 ----------------------------------------------- Makefile | 9 +- 4 files changed, 101 insertions(+), 412 deletions(-) create mode 100644 BootROMs/pb12.c delete mode 100644 BootROMs/pb12.py delete mode 100644 BootROMs/pb8.c diff --git a/BootROMs/pb12.c b/BootROMs/pb12.c new file mode 100644 index 00000000..878dd0d2 --- /dev/null +++ b/BootROMs/pb12.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include + +void opts(uint8_t byte, uint8_t *options) +{ + *(options++) = byte | ((byte << 1) & 0xff); + *(options++) = byte & (byte << 1); + *(options++) = byte | ((byte >> 1) & 0xff); + *(options++) = byte & (byte >> 1); +} + +int main() +{ + static uint8_t source[0x4000]; + size_t size = read(STDIN_FILENO, &source, sizeof(source)); + unsigned pos = 0; + assert(size <= 0x4000); + while (size && source[size - 1] == 0) { + size--; + } + + uint8_t *literals = NULL; + size_t literals_size = 0; + unsigned bits = 0; + unsigned control = 0; + unsigned prev[2] = {-1, -1}; // Unsigned to allow "not set" values + + while (true) { + + uint8_t byte = 0; + if (pos == size){ + if (bits == 0) break; + } + else { + byte = source[pos++]; + } + + if (byte == prev[0] || byte == prev[1]) { + bits += 2; + control <<= 1; + control |= 1; + control <<= 1; + if (byte == prev[1]) { + control |= 1; + } + } + else { + bits += 2; + control <<= 2; + uint8_t options[4]; + opts(prev[1], options); + bool found = false; + for (unsigned i = 0; i < 4; i++) { + if (options[i] == byte) { + // 01 = modify + control |= 1; + + bits += 2; + control <<= 2; + control |= i; + found = true; + break; + } + } + if (!found) { + literals = realloc(literals, literals_size++); + literals[literals_size - 1] = byte; + } + } + + prev[0] = prev[1]; + prev[1] = byte; + if (bits >= 8) { + uint8_t outctl = control >> (bits - 8); + assert(outctl != 1); + write(STDOUT_FILENO, &outctl, 1); + write(STDOUT_FILENO, literals, literals_size); + bits -= 8; + control &= (1 << bits) - 1; + literals_size = 0; + } + } + uint8_t end_byte = 1; + write(STDOUT_FILENO, &end_byte, 1); + + if (literals) { + free(literals); + } + + return 0; +} diff --git a/BootROMs/pb12.py b/BootROMs/pb12.py deleted file mode 100644 index dc53d6b9..00000000 --- a/BootROMs/pb12.py +++ /dev/null @@ -1,68 +0,0 @@ -import sys - -def opts(byte): - # top bit: 0 = left, 1 = right - # bottom bit: 0 = or, 1 = and - if byte is None: return [] - return [ - byte | (byte << 1) & 0xff, - byte & (byte << 1), - byte | (byte >> 1) & 0xff, - byte & (byte >> 1), - ] - -def pb12(data): - data = iter(data) - - literals = bytearray() - bits = 0 - control = 0 - prev = [None, None] - gotta_end = False - - chunk = bytearray() - while True: - try: - byte = next(data) - except StopIteration: - if bits == 0: break - byte = 0 - chunk.append(byte) - - if byte in prev: - bits += 2 - control <<= 1 - control |= 1 - control <<= 1 - if prev[1] == byte: - control |= 1 # 10 = out[-2], 11 = out[-1] - else: - bits += 2 - control <<= 2 - options = opts(prev[1]) - if byte in options: - # 01 = modify - control |= 1 - - bits += 2 - control <<= 2 - control |= options.index(byte) - else: - # 00 = literal - literals.append(byte) - prev = [prev[1], byte] - if bits >= 8: - outctl = control >> (bits - 8) - assert outctl != 1 # that's the end byte - yield bytes([outctl]) + literals - bits -= 8 - control &= (1 << bits) - 1 - literals = bytearray() - chunk = bytearray() - yield b'\x01' - -_, infile, outfile = sys.argv -with open(infile, 'rb') as f: - data = f.read().rstrip(b'\x00') -with open(outfile, 'wb') as f: - f.writelines(pb12(data)) diff --git a/BootROMs/pb8.c b/BootROMs/pb8.c deleted file mode 100644 index 4ee4524e..00000000 --- a/BootROMs/pb8.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - -PB8 compressor and decompressor - -Copyright 2019 Damian Yerrick - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - -*/ - -#include -#include -#include -#include -#include -#include - -// For setting stdin/stdout to binary mode -#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__)) -#include -#define fd_isatty isatty -#elif defined (_WIN32) -#include -#include -#define fd_isatty _isatty -#endif - -/* - -; The logo is compressed using PB8, a form of RLE with unary-coded -; run lengths. Each block representing 8 bytes consists of a control -; byte, where each bit (MSB to LSB) is 0 for literal or 1 for repeat -; previous, followed by the literals in that block. - -SameBoyLogo_dst = $8080 -SameBoyLogo_length = (128 * 24) / 64 - -LoadTileset: - ld hl, SameBoyLogo - ld de, SameBoyLogo_dst - ld c, SameBoyLogo_length -.pb8BlockLoop: - ; Register map for PB8 decompression - ; HL: source address in boot ROM - ; DE: destination address in VRAM - ; A: Current literal value - ; B: Repeat bits, terminated by 1000... - ; C: Number of 8-byte blocks left in this block - ; Source address in HL lets the repeat bits go straight to B, - ; bypassing A and avoiding spilling registers to the stack. - ld b, [hl] - inc hl - - ; Shift a 1 into lower bit of shift value. Once this bit - ; reaches the carry, B becomes 0 and the byte is over - scf - rl b - -.pb8BitLoop: - ; If not a repeat, load a literal byte - jr c,.pb8Repeat - ld a, [hli] -.pb8Repeat: - ; Decompressed data uses colors 0 and 1, so write once, inc twice - ld [de], a - inc de - inc de - sla b - jr nz, .pb8BitLoop - - dec c - jr nz, .pb8BlockLoop - ret - -*/ - -/* Compressor and decompressor *************************************/ - -/** - * Compresses an input stream to PB8 data on an output stream. - * @param infp input stream - * @param outfp output stream - * @param blocklength size of an independent input block in bytes - * @return 0 for reaching infp end of file, or EOF for error - */ -int pb8(FILE *infp, FILE *outfp, size_t blocklength) -{ - blocklength >>= 3; // convert bytes to blocks - assert(blocklength > 0); - while (1) { - int last_byte = EOF; // value that never occurs in a file - for (size_t blkleft = blocklength; blkleft > 0; --blkleft) { - unsigned int control_byte = 0x0001; - unsigned char literals[8]; - size_t nliterals = 0; - while (control_byte < 0x100) { - int c = fgetc(infp); - if (c == EOF) break; - - control_byte <<= 1; - if (c == last_byte) { - control_byte |= 0x01; - } - else { - literals[nliterals++] = last_byte = c; - } - } - if (control_byte > 1) { - // Fill partial block with repeats - while (control_byte < 0x100) { - control_byte = (control_byte << 1) | 1; - } - - // Write control byte and check for write failure - int ok = fputc(control_byte & 0xFF, outfp); - if (ok == EOF) return EOF; - size_t ok2 = fwrite(literals, 1, nliterals, outfp); - if (ok2 < nliterals) return EOF; - } - - // If finished, return success or failure - if (ferror(infp) || ferror(outfp)) return EOF; - if (feof(infp)) return 0; - } // End 8-byte block - } // End packet, resetting last_byte -} - -/** - * Decompresses PB8 data on an input stream to an output stream. - * @param infp input stream - * @param outfp output stream - * @return 0 for reaching infp end of file, or EOF for error - */ -int unpb8(FILE *infp, FILE *outfp) -{ - int last_byte = 0; - while (1) { - int control_byte = fgetc(infp); - if (control_byte == EOF) { - return feof(infp) ? 0 : EOF; - } - control_byte &= 0xFF; - for (size_t bytesleft = 8; bytesleft > 0; --bytesleft) { - if (!(control_byte & 0x80)) { - last_byte = fgetc(infp); - if (last_byte == EOF) return EOF; // read error - } - control_byte <<= 1; - int ok = fputc(last_byte, outfp); - if (ok == EOF) return EOF; - } - } -} - -/* CLI frontend ****************************************************/ - -static inline void set_fd_binary(unsigned int fd) -{ -#ifdef _WIN32 - _setmode(fd, _O_BINARY); -#else - (void) fd; -#endif -} - -static const char *usage_msg = -"usage: pb8 [-d] [-l blocklength] [infile [outfile]]\n" -"Compresses a file using RLE with unary run and literal lengths.\n" -"\n" -"options:\n" -" -d decompress\n" -" -l blocklength allow RLE packets to span up to blocklength\n" -" input bytes (multiple of 8; default 8)\n" -" -h, -?, --help show this usage page\n" -" --version show copyright info\n" -"\n" -"If infile is - or missing, it is standard input.\n" -"If outfile is - or missing, it is standard output.\n" -"You cannot compress to or decompress from a terminal.\n" -; -static const char *version_msg = -"PB8 compressor (C version) v0.01\n" -"Copyright 2019 Damian Yerrick \n" -"This software is provided 'as-is', without any express or implied\n" -"warranty.\n" -; -static const char *toomanyfilenames_msg = -"pb8: too many filenames; try pb8 --help\n"; - -int main(int argc, char **argv) -{ - const char *infilename = NULL; - const char *outfilename = NULL; - bool decompress = false; - size_t blocklength = 8; - - for (int i = 1; i < argc; ++i) { - if (argv[i][0] == '-' && argv[i][1] != 0) { - if (!strcmp(argv[i], "--help")) { - fputs(usage_msg, stdout); - return 0; - } - if (!strcmp(argv[i], "--version")) { - fputs(version_msg, stdout); - return 0; - } - - // -t1 or -t 1 - int argtype = argv[i][1]; - switch (argtype) { - case 'h': - case '?': - fputs(usage_msg, stdout); - return 0; - - case 'd': - decompress = true; - break; - - case 'l': { - const char *argvalue = argv[i][2] ? argv[i] + 2 : argv[++i]; - const char *endptr = NULL; - - unsigned long tvalue = strtoul(argvalue, (char **)&endptr, 10); - if (endptr == argvalue || tvalue == 0 || tvalue > SIZE_MAX) { - fprintf(stderr, "pb8: block length %s not a positive integer\n", - argvalue); - return EXIT_FAILURE; - } - if (tvalue % 8 != 0) { - fprintf(stderr, "pb8: block length %s not a multiple of 8\n", - argvalue); - return EXIT_FAILURE; - } - blocklength = tvalue; - } break; - - default: - fprintf(stderr, "pb8: unknown option -%c\n", argtype); - return EXIT_FAILURE; - } - } - else if (!infilename) { - infilename = argv[i]; - } - else if (!outfilename) { - outfilename = argv[i]; - } - else { - fputs(toomanyfilenames_msg, stderr); - return EXIT_FAILURE; - } - } - if (infilename && !strcmp(infilename, "-")) { - infilename = NULL; - } - if (!infilename && decompress && fd_isatty(0)) { - fputs("pb8: cannot decompress from terminal; try redirecting stdin\n", - stderr); - return EXIT_FAILURE; - } - if (outfilename && !strcmp(outfilename, "-")) { - outfilename = NULL; - } - if (!outfilename && !decompress && fd_isatty(1)) { - fputs("pb8: cannot compress to terminal; try redirecting stdout or pb8 --help\n", - stderr); - return EXIT_FAILURE; - } - - FILE *infp = NULL; - if (infilename) { - infp = fopen(infilename, "rb"); - if (!infp) { - fprintf(stderr, "pb8: error opening %s ", infilename); - perror("for reading"); - return EXIT_FAILURE; - } - } - else { - infp = stdin; - set_fd_binary(0); - } - - FILE *outfp = NULL; - if (outfilename) { - outfp = fopen(outfilename, "wb"); - if (!outfp) { - fprintf(stderr, "pb8: error opening %s ", outfilename); - perror("for writing"); - fclose(infp); - return EXIT_FAILURE; - } - } - else { - outfp = stdout; - set_fd_binary(1); - } - - int compfailed = 0; - int has_ferror = 0; - if (decompress) { - compfailed = unpb8(infp, outfp); - } - else { - compfailed = pb8(infp, outfp, blocklength); - } - fflush(outfp); - if (ferror(infp)) { - fprintf(stderr, "pb8: error reading %s\n", - infilename ? infilename : ""); - has_ferror = EOF; - } - fclose(infp); - if (ferror(outfp)) { - fprintf(stderr, "pb8: error writing %s\n", - outfilename ? outfilename : ""); - has_ferror = EOF; - } - fclose(outfp); - - if (compfailed && !has_ferror) { - fputs("pb8: unknown compression failure\n", stderr); - } - - return (compfailed || has_ferror) ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/Makefile b/Makefile index 1f818628..78978e49 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ else EXESUFFIX:= endif -PB8_COMPRESS := build/pb8$(EXESUFFIX) +PB12_COMPRESS := build/pb12$(EXESUFFIX) ifeq ($(PLATFORM),Darwin) DEFAULT := cocoa @@ -386,8 +386,11 @@ $(OBJ)/%.2bpp: %.png -@$(MKDIR) -p $(dir $@) rgbgfx -h -u -o $@ $< -$(OBJ)/BootROMs/SameBoyLogo.pb12: $(OBJ)/BootROMs/SameBoyLogo.2bpp BootROMs/pb12.py - python3 BootROMs/pb12.py $< $@ +$(OBJ)/BootROMs/SameBoyLogo.pb12: $(OBJ)/BootROMs/SameBoyLogo.2bpp $(PB12_COMPRESS) + $(PB12_COMPRESS) < $< > $@ + +$(PB12_COMPRESS): BootROMs/pb12.c + $(CC) -Wall -Werror $< -o $@ $(BIN)/BootROMs/agb_boot.bin: BootROMs/cgb_boot.asm $(BIN)/BootROMs/cgb_boot_fast.bin: BootROMs/cgb_boot.asm