From 17b4ad5f56bf9ac0abc0196ffc82675bfa530530 Mon Sep 17 00:00:00 2001 From: Marc Robledo Date: Sat, 10 Feb 2024 10:22:06 +0100 Subject: [PATCH] fixed MBC1+ROM larger bigger than 1MB --- .../kid_dracula/settings.asm | 17 +++- .../kid_dracula/sgb_border.png | Bin .../kid_dracula/sgb_border_map.bin | Bin .../kid_dracula/sgb_border_palettes.bin | Bin .../kid_dracula/sgb_border_tiles.bin | Bin examples/zelda_links_awakening/settings.asm | 71 ++++++++++++++++ index.html | 2 +- src/main.asm | 10 +++ src/settings.asm | 19 ++++- web-injector/app/assembled-code.js | 49 ++++++++--- web-injector/app/main.js | 76 ++++++++++++------ 11 files changed, 203 insertions(+), 41 deletions(-) rename {example => examples}/kid_dracula/settings.asm (76%) rename {example => examples}/kid_dracula/sgb_border.png (100%) rename {example => examples}/kid_dracula/sgb_border_map.bin (100%) rename {example => examples}/kid_dracula/sgb_border_palettes.bin (100%) rename {example => examples}/kid_dracula/sgb_border_tiles.bin (100%) create mode 100644 examples/zelda_links_awakening/settings.asm diff --git a/example/kid_dracula/settings.asm b/examples/kid_dracula/settings.asm similarity index 76% rename from example/kid_dracula/settings.asm rename to examples/kid_dracula/settings.asm index 99656aa..77353e0 100644 --- a/example/kid_dracula/settings.asm +++ b/examples/kid_dracula/settings.asm @@ -26,6 +26,19 @@ DEF BANK0_FREE_SPACE EQU $3fd0 +; MBC type +; -------- +; (see more here: https://gbdev.io/pandocs/MBCs.html) +; MBC needs to be here specified in these special cases: +; - MBC1 + expanded ROM to 1Mb or bigger (Zelda Link's Awakening [non-DX]) +; - (to-do!) MBC5 + expanded ROM to 8Mb +; other cases will just ignore this value +; keep in mind that, in these special cases, the hook subroutine will grow +; from 16 bytes to 25 bytes! +DEF MBC EQU 5 + + + ; NEW CODE LOCATION ; ----------------- ; We need an empty bank to store all new code plus border data, which will be @@ -37,8 +50,8 @@ DEF BANK0_FREE_SPACE EQU $3fd0 ; - 64kb --> bank $04 ; - 128kb --> bank $08 ; - 256kb --> bank $10 -; - 512kb --> bank $20 -; - 1024kb --> bank $40 +; - 512kb --> bank $21 (bank $20 needs more code to be accessed in MBC1) +; - 1024kb --> bank $41 (bank $40 needs more code to be accessed in MBC1) DEF SGB_CODE_BANK EQU $10 diff --git a/example/kid_dracula/sgb_border.png b/examples/kid_dracula/sgb_border.png similarity index 100% rename from example/kid_dracula/sgb_border.png rename to examples/kid_dracula/sgb_border.png diff --git a/example/kid_dracula/sgb_border_map.bin b/examples/kid_dracula/sgb_border_map.bin similarity index 100% rename from example/kid_dracula/sgb_border_map.bin rename to examples/kid_dracula/sgb_border_map.bin diff --git a/example/kid_dracula/sgb_border_palettes.bin b/examples/kid_dracula/sgb_border_palettes.bin similarity index 100% rename from example/kid_dracula/sgb_border_palettes.bin rename to examples/kid_dracula/sgb_border_palettes.bin diff --git a/example/kid_dracula/sgb_border_tiles.bin b/examples/kid_dracula/sgb_border_tiles.bin similarity index 100% rename from example/kid_dracula/sgb_border_tiles.bin rename to examples/kid_dracula/sgb_border_tiles.bin diff --git a/examples/zelda_links_awakening/settings.asm b/examples/zelda_links_awakening/settings.asm new file mode 100644 index 0000000..456936d --- /dev/null +++ b/examples/zelda_links_awakening/settings.asm @@ -0,0 +1,71 @@ +; ------------------------------------------------------------------------------ +; Super Game Boy border injector for Zelda Link's Awakening (non-DX) +; by Marc Robledo 2024 +; +; More info at https://github.com/marcrobledo/super-game-boy-border-injector +; ------------------------------------------------------------------------------ + + + +; GAME BOOT OFFSET +; ---------------- +; Put here the game's boot jp offset found in in $0101. +; Usually $0150, but could be different depending on game. +DEF GAME_BOOT_OFFSET EQU $0150 + + + +; BANK 0 ROM FREE SPACE +; --------------------- +; 16 bytes in bank 0 are needed for the game's boot hook subroutine. +; Hopefully, there should be enough space at the end of bank 0 or in the +; interruption or rst vector ($0000-$00ff). +; In the worst scenario, you will need to carefully move some code/data to +; other banks. +DEF BANK0_FREE_SPACE EQU $0005 + + + +; MBC type +; -------- +; (see more here: https://gbdev.io/pandocs/MBCs.html) +; MBC needs to be here specified in these special cases: +; - MBC1 + expanded ROM to 1Mb or bigger (Zelda Link's Awakening [non-DX]) +; - (to-do!) MBC5 + expanded ROM to 8Mb +; other cases will just ignore this value +; keep in mind that, in these special cases, the hook subroutine will grow +; from 16 bytes to 25 bytes! +DEF MBC EQU 1 + + + +; NEW CODE LOCATION +; ----------------- +; We need an empty bank to store all new code plus border data, which will be +; quite big. +; If the game has no empty bank, just use a bank higher than the original +; game's bank number, RGBDS will expand the ROM and fix the header. +; Safe bank numbers, depending on original game's ROM size: +; - 32kb --> impossible to do it without changing MBC +; - 64kb --> bank $04 +; - 128kb --> bank $08 +; - 256kb --> bank $10 +; - 512kb --> bank $21 (bank $20 needs more code to be accessed in MBC1) +; - 1024kb --> bank $41 (bank $40 needs more code to be accessed in MBC1) +DEF SGB_CODE_BANK EQU $21 + + + +; CUSTOM GB PALETTE +; ----------------- +; set CUSTOM_GB_PALETTE_ENABLED to 1 if you want a custom GB palette for the +; entire game screen +; colors are RGB15 which means RGB components can go from 0 up to 31 +; warning: even if set to 0, do not delete BUILD_CUSTOM_GB_PALETTE macro! +DEF CUSTOM_GB_PALETTE_ENABLED EQU 1 +MACRO BUILD_CUSTOM_GB_PALETTE + RGB 27, 30, 25 ;color 0 (light) + RGB 17, 23, 14 ;color 1 + RGB 6, 13, 10 ;color 2 + RGB 1, 3, 4 ;color 3 (dark) +ENDM diff --git a/index.html b/index.html index eb9227b..6a8f226 100644 --- a/index.html +++ b/index.html @@ -106,7 +106,7 @@

Super Game Boy Border Injector

diff --git a/src/main.asm b/src/main.asm index 07acf95..52fa3ba 100644 --- a/src/main.asm +++ b/src/main.asm @@ -42,9 +42,19 @@ boot_hook: ld a, BANK(sgb_init) ld [rROMB0], a + IF MBC == 1 && SGB_CODE_BANK>=$20 + ld a, ((BANK(sgb_init) & %01100000) >> 5) + ld [rRAMB], a + ENDC + call sgb_init ld [rROMB0], a + IF MBC == 1 && SGB_CODE_BANK>=$20 + xor a + ld [rRAMB], a + ENDC + pop af jp boot_original diff --git a/src/settings.asm b/src/settings.asm index 5dab19a..75dd701 100644 --- a/src/settings.asm +++ b/src/settings.asm @@ -26,6 +26,19 @@ DEF BANK0_FREE_SPACE EQU $3ff0 +; MBC type +; -------- +; (see more here: https://gbdev.io/pandocs/MBCs.html) +; MBC needs to be here specified in these special cases: +; - MBC1 + expanded ROM to 1Mb or bigger (Zelda Link's Awakening [non-DX]) +; - (to-do!) MBC5 + expanded ROM to 8Mb +; other cases will just ignore this value +; keep in mind that, in these special cases, the hook subroutine will grow +; from 16 bytes to 25 bytes! +DEF MBC EQU 5 + + + ; NEW CODE LOCATION ; ----------------- ; We need an empty bank to store all new code plus border data, which will be @@ -37,9 +50,9 @@ DEF BANK0_FREE_SPACE EQU $3ff0 ; - 64kb --> bank $04 ; - 128kb --> bank $08 ; - 256kb --> bank $10 -; - 512kb --> bank $20 -; - 1024kb --> bank $40 -DEF SGB_CODE_BANK EQU $20 +; - 512kb --> bank $21 (bank $20 needs more code to be accessed in MBC1) +; - 1024kb --> bank $41 (bank $40 needs more code to be accessed in MBC1) +DEF SGB_CODE_BANK EQU $21 diff --git a/web-injector/app/assembled-code.js b/web-injector/app/assembled-code.js index 1d9d60b..1b53745 100644 --- a/web-injector/app/assembled-code.js +++ b/web-injector/app/assembled-code.js @@ -1,16 +1,41 @@ -export const ASSEMBLED_HOOK=[ - 0xf5, //push af - 0x3e, 'bank_number', //ld a, sgb_init_bank - 0xea, 0x00, 0x20, //ld [0x2000], a - 0xcd, 0x00, 0x40, //call 0x4000 - 0xea, 0x00, 0x20, //ld [0x2000], a - 0xf1, //pop af - 0xc3, 'entry_point_low', 'entry_point_high' //jp original_entry_point +export const ASSEMBLED_HOOK_INFO=[ + //common case + { + code:[ + 0xf5, //push af + 0x3e, 'rom_bank_number', //ld a, sgb_init_bank + 0xea, 0x00, 0x20, //ld [0x2000], a + 0xcd, 0x00, 0x40, //call 0x4000 + 0xea, 0x00, 0x20, //ld [0x2000], a + 0xf1, //pop af + 0xc3, 'entry_point_low', 'entry_point_high' //jp original_entry_point + ] + }, + //MBC1 + larger than 512kb + //requires additional code to write to $4000 (ROM bank upper bits) + { + code:[ + 0xf5, //push af + 0x3e, 'rom_bank_number', //ld a, sgb_init_bank_lowerbits + 0xea, 0x00, 0x20, //ld [0x2000], a + 0x3e, 'rom_bank_number_upperbits', //ld a, sgb_init_bank_upperbits + 0xea, 0x00, 0x40, //ld [0x4000], a + 0xcd, 0x00, 0x40, //call 0x4000 + 0xea, 0x00, 0x20, //ld [0x2000], a + 0xaf, //xor a + 0xea, 0x00, 0x40, //ld [0x4000], a + 0xf1, //pop af + 0xc3, 'entry_point_low', 'entry_point_high' //jp original_entry_point + ] + } ]; - - -export const ASSEMBLED_HOOK_BANK_NUMBER=ASSEMBLED_HOOK.indexOf('bank_number'); -export const ASSEMBLED_HOOK_ENTRY_POINT=ASSEMBLED_HOOK.indexOf('entry_point_low'); +ASSEMBLED_HOOK_INFO.forEach(function(assembledInfo){ + assembledInfo.patchOffsets={ + romBankNumber: assembledInfo.code.indexOf('rom_bank_number'), + romBankNumberUpperbits: assembledInfo.code.indexOf('rom_bank_number_upperbits'), + entryPoint: assembledInfo.code.indexOf('entry_point_low') + } +}); // assembled code from "SGB Bank - Code" SECTION in main.asm export const ASSEMBLED_SGB_CODE=[ diff --git a/web-injector/app/main.js b/web-injector/app/main.js index 85c8aa2..3981e31 100644 --- a/web-injector/app/main.js +++ b/web-injector/app/main.js @@ -1,7 +1,7 @@ import { FileParser } from './gb-parser.js' import { PaletteGB, PaletteSNES, ColorRGB15, Tile4BPP, MapSNES } from './console-graphics.js' import { EXAMPLE_GB_TILE_DATA, EXAMPLE_GB_MAP_DATA, SGB_DEFAULT_PALETTE } from './preview-example-data.js' -import { ASSEMBLED_HOOK, ASSEMBLED_HOOK_BANK_NUMBER, ASSEMBLED_HOOK_ENTRY_POINT, ASSEMBLED_SGB_CODE } from './assembled-code.js' +import { ASSEMBLED_HOOK_INFO, ASSEMBLED_SGB_CODE } from './assembled-code.js' /* @@ -25,6 +25,7 @@ var pickerStatus={ }; var bufferedFiles={}; var currentRomName; +var currentRomType; function setPickerStatus(id, status, message){ pickerStatus[id]=status; @@ -218,7 +219,8 @@ function checkFileRom(file){ var result={ supported:false, title:'Invalid or incompatible Game Boy ROM', - banks: nBanks + mbc:0, + banks: 0 } try{ @@ -248,7 +250,9 @@ function checkFileRom(file){ for(var i=0; i=0x20){ + console.log('using assembled code for MBC1+ROM bigger than 1MB'); + if(freeBankX===0x20 || freeBankX===0x40 || freeBankX===0x60){ + //banks $20, $40, $60 need additional code to be accesed + //use $21, $41 or $61 instead + freeBankX++; + } + + assembledHookInfo=ASSEMBLED_HOOK_INFO[1]; + }else{ + console.log('using common assembled code'); + assembledHookInfo=ASSEMBLED_HOOK_INFO[0]; + } + + + //find free space in bank 0 + var freeSpace0=findBytes(rom, {offset:0x4000, len:0x80, data:buildRepeatData(assembledHookInfo.code.length, 0xff), reverse: true}); + if(freeSpace0===null) + freeSpace0=findBytes(rom, {offset:0x0000, len:0xf0, data:buildRepeatData(assembledHookInfo.code.length, 0xff), reverse: false}); + if(freeSpace0===null) + freeSpace0=findBytes(rom, {offset:0x0000, len:0xf0, data:buildRepeatData(assembledHookInfo.code.length, 0x00), reverse: false}); + + if(freeSpace0===null) + throw new Error('Bank 0 has no free space (need '+assembledHookInfo.code.length+' bytes)'); + + console.log('free space found in bank 0: $'+freeSpace0.toString(16)); + //add SGB flags to header @@ -442,10 +469,13 @@ function buildROM(){ //patch entry point hook rom.seek(freeSpace0); - ASSEMBLED_HOOK[ASSEMBLED_HOOK_BANK_NUMBER]=freeBankX; - ASSEMBLED_HOOK[ASSEMBLED_HOOK_ENTRY_POINT]=originalEntryPoint & 0xff; - ASSEMBLED_HOOK[ASSEMBLED_HOOK_ENTRY_POINT + 1]=(originalEntryPoint >> 8) & 0xff; - rom.writeBytes(ASSEMBLED_HOOK); + assembledHookInfo.code[assembledHookInfo.patchOffsets.romBankNumber]=freeBankX; + assembledHookInfo.code[assembledHookInfo.patchOffsets.entryPoint]=originalEntryPoint & 0xff; + assembledHookInfo.code[assembledHookInfo.patchOffsets.entryPoint + 1]=(originalEntryPoint >> 8) & 0xff; + if(assembledHookInfo===ASSEMBLED_HOOK_INFO[1]){ //MBC1+1MB + assembledHookInfo.code[assembledHookInfo.patchOffsets.romBankNumberUpperbits]=(freeBankX & 0b01100000) >> 5; + } + rom.writeBytes(assembledHookInfo.code); //write SGB code rom.seek(freeBankX * 0x4000); @@ -496,7 +526,7 @@ function buildROM(){ rom.writeByte(newChecksum & 0xff); - var newRomName=currentRomName.replace(/\.(gbc?)$/, ' (SGB Compatible).$1'); + var newRomName=currentRomName.replace(/\.(gbc?)$/, ' (SGB Enhanced).$1'); var blob=new Blob([rom.getBuffer()], {type: 'application/octet-stream'}); saveAs(blob, newRomName);