You are not logged in.
Pages: 1
I wrote a disassembler for GameBoy Z80 code in Python 3.
Here it is on GitHub: disasm.py
You run it with:
$ ./disasm.py a.bin > a.asm
Or to specify an entry point other than the start of the file, e.g. address $10ab:
$ ./disasm.py a.bin 10ab > a.asm
One GameBoy-specific feature is that it uses the hardware register names from gbhw.asm.
It can parse the entire gbc_bios.bin bootloader responsible for displaying this screen:
Here's a sample of its output:
ENTRY_POINT:
ld sp, $fffe ; 000000: 31 fe ff
ld a, $02 ; 000003: 3e 02
jp Function007c ; 000005: c3 7c 00
db $d3, $00, $98, $a0, $12, $d3, $00, $80 ; 000008-00000f
db $00, $40, $1e, $53, $d0, $00, $1f, $42 ; 000010-000017
db $1c, $00, $14, $2a, $4d, $19, $8c, $7e ; 000018-00001f
...
Function0200:
ld hl, $8000 ; 000200: 21 00 80
Function0203:
xor a ; 000203: af
Function0204:
ld [hli], a ; 000204: 22
bit 5, h ; 000205: cb 6c
jr z, Function0204 ; 000207: 28 fb
ret ; 000209: c9
Function020a:
ld a, [hli] ; 00020a: 2a
ld [de], a ; 00020b: 12
inc de ; 00020c: 13
dec c ; 00020d: 0d
jr nz, Function020a ; 00020e: 20 fa
ret ; 000210: c9
Function0211:
push hl ; 000211: e5
ld hl, $ff0f ; 000212: 21 0f ff
res 0, [hl] ; 000215: cb 86
Function0217:
bit 0, [hl] ; 000217: cb 46
jr z, Function0217 ; 000219: 28 fc
pop hl ; 00021b: e1
ret ; 00021c: c9
Function021d:
ld de, $ff00 ; 00021d: 11 00 ff
ld hl, $d003 ; 000220: 21 03 d0
ld c, $0f ; 000223: 0e 0f
ld a, $30 ; 000225: 3e 30
ld [de], a ; 000227: 12
ld a, $20 ; 000228: 3e 20
ld [de], a ; 00022a: 12
ld a, [de] ; 00022b: 1a
cpl ; 00022c: 2f
and c ; 00022d: a1
swap a ; 00022e: cb 37
ld b, a ; 000230: 47
ld a, $10 ; 000231: 3e 10
ld [de], a ; 000233: 12
ld a, [de] ; 000234: 1a
cpl ; 000235: 2f
and c ; 000236: a1
or b ; 000237: b0
ld c, a ; 000238: 4f
ld a, [hl] ; 000239: 7e
xor c ; 00023a: a9
and $f0 ; 00023b: e6 f0
ld b, a ; 00023d: 47
ld a, [hli] ; 00023e: 2a
xor c ; 00023f: a9
and c ; 000240: a1
or b ; 000241: b0
ld [hld], a ; 000242: 32
ld b, a ; 000243: 47
ld a, c ; 000244: 79
ld [hl], a ; 000245: 77
ld a, $30 ; 000246: 3e 30
ld [de], a ; 000248: 12
ret ; 000249: c9
(The line breaks were added by me. Everything else was auto-generated.)
Last edited by Rangi (2017-06-26 18:08:23)
My projects on GitHub:
• Polished Map 4.7.1 or 2.7.1++
• Tilemap Studio 4.0.1
• Pokémon Polished Crystal 2.2.0 or 3.0.0 beta
• Pokémon Red★/Blue★: Space World Edition 2020-11-01
Offline
Unfortunately it cannot be used to disassemble whole games. I was able to disassemble Pokémon Crystal, but only these 1,500 lines were recognized as code, and the rest became raw db data.
The problem is that jump tables, and other forms of indirect calling, are not understood. So code like this in pokecrystal's engine/intro_menu.asm:
StartTitleScreen: ; 6219
...
ld e, a
ld d, 0
ld hl, .dw
add hl, de
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a
jp [hl]
; 626a
.dw
dw _MainMenu
dw DeleteSaveData
dw CrystalIntroSequence
dw CrystalIntroSequence
dw ResetClock
is disassembled to this by my program:
Function6219:
...
ld e, a ; 00625e: 5f
ld d, $00 ; 00625f: 16 00
ld hl, $626a ; 006261: 21 6a 62
add hl, de ; 006264: 19
add hl, de ; 006265: 19
ld a, [hli] ; 006266: 2a
ld h, [hl] ; 006267: 66
ld l, a ; 006268: 6f
jp hl ; 006269: e9
db $e8, $5a, $89, $63, $0b, $62, $0b, $62 ; 00626a-006271
db $92, $63 ; 006272-006273
Last edited by Rangi (2017-06-26 19:20:17)
My projects on GitHub:
• Polished Map 4.7.1 or 2.7.1++
• Tilemap Studio 4.0.1
• Pokémon Polished Crystal 2.2.0 or 3.0.0 beta
• Pokémon Red★/Blue★: Space World Edition 2020-11-01
Offline
Pages: 1