Merge pull request #137 from yenatch/master

gbz80disasm reads wram/gbhw/hram and spaces blocks of asm
This commit is contained in:
Bryan Bishop 2013-05-15 12:09:31 -07:00
commit 5feb5fd208
4 changed files with 177 additions and 94 deletions

View File

@ -6,16 +6,15 @@ from copy import copy, deepcopy
from ctypes import c_int8
import random
import json
from wram import *
# New versions of json don't have read anymore.
if not hasattr(json, "read"):
json.read = json.loads
from romstr import RomStr
def load_rom(filename="../baserom.gbc"):
global rom
rom = RomStr.load(filename=filename)
rom = bytearray(open(filename,'rb').read())
return rom
spacing = "\t"
@ -543,10 +542,11 @@ for line in temp_opt_table:
del line
end_08_scripts_with = [
0xc9, #ret
0xd9, #reti
0xe9, #jp hl
#0xc3, #jp
##0x18, #jr
0xc9, #ret
###0xda, 0xe9, 0xd2, 0xc2, 0xca, 0xc3, 0x38, 0x30, 0x20, 0x28, 0x18, 0xd8, 0xd0, 0xc0, 0xc8, 0xc9
]
relative_jumps = [0x38, 0x30, 0x20, 0x28, 0x18, 0xc3, 0xda, 0xc2]
@ -565,27 +565,20 @@ def load_labels(filename="labels.json"):
crystal.scan_for_predefined_labels()
def find_label(local_address, bank_id=0):
global all_labels
# keep an integer
if type(local_address) == str:
local_address1 = int(local_address.replace("$", "0x"), 16)
else: local_address1 = local_address
local_address = int(local_address.replace("$", "0x"), 16)
# turn local_address into an integer
if type(local_address) == str:
if "0x" in local_address:
local_address = local_address.replace("0x", "$")
elif "$" in local_address:
local_address = local_address.replace("$", "")
if type(local_address) == str:
local_address = int(local_address, 16)
for label_entry in all_labels:
if label_entry["address"] == local_address:
if label_entry["bank"] == bank_id or (local_address1 < 0x8000 and (label_entry["bank"] == 0 or label_entry["bank"] == 1)):
return label_entry["label"]
if local_address < 0x8000:
for label_entry in all_labels:
if label_entry["address"] == local_address:
if label_entry["bank"] == bank_id or label_entry["bank"] == 0:
return label_entry["label"]
if local_address in wram_labels.keys():
return wram_labels[local_address][-1]
for constants in [gbhw_constants, hram_constants]:
if local_address in constants.keys():
return constants[local_address]
return None
def asm_label(address):
@ -608,9 +601,7 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
load_labels()
load_rom()
bank_id = 0
if original_offset > 0x8000:
bank_id = original_offset / 0x4000
bank_id = original_offset / 0x4000
if debug: print "bank id is: " + str(bank_id)
last_hl_address = None #for when we're scanning the main map script
@ -630,7 +621,7 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
output = ""
keep_reading = True
while offset <= end_address and keep_reading:
current_byte = ord(rom[offset])
current_byte = rom[offset]
is_data = False
maybe_byte = current_byte
@ -645,6 +636,7 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
if offset in byte_labels.keys():
line_label = byte_labels[offset]["name"]
byte_labels[offset]["usage"] += 1
output += "\n"
else:
line_label = asm_label(offset)
byte_labels[offset] = {}
@ -655,13 +647,13 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
#find out if there's a two byte key like this
temp_maybe = maybe_byte
temp_maybe += ( ord(rom[offset+1]) << 8)
if temp_maybe in opt_table.keys() and ord(rom[offset+1])!=0:
temp_maybe += ( rom[offset+1] << 8)
if temp_maybe in opt_table.keys() and rom[offset+1]!=0:
opstr = opt_table[temp_maybe][0].lower()
if "x" in opstr:
for x in range(0, opstr.count("x")):
insertion = ord(rom[offset + 1])
insertion = rom[offset + 1]
insertion = "$" + hex(insertion)[2:]
opstr = opstr[:opstr.find("x")].lower() + insertion + opstr[opstr.find("x")+1:].lower()
@ -670,8 +662,8 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
offset += 1
if "?" in opstr:
for y in range(0, opstr.count("?")):
byte1 = ord(rom[offset + 1])
byte2 = ord(rom[offset + 2])
byte1 = rom[offset + 1]
byte2 = rom[offset + 2]
number = byte1
number += byte2 << 8;
@ -695,7 +687,7 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
#type = -1 when it's the E op
#if op_code_type != -1:
if op_code_type == 0 and ord(rom[offset]) == op_code_byte:
if op_code_type == 0 and rom[offset] == op_code_byte:
op_str = op_code[0].lower()
output += spacing + op_code[0].lower() #+ " ; " + hex(offset)
@ -703,18 +695,18 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
offset += 1
current_byte_number += 1
elif op_code_type == 1 and ord(rom[offset]) == op_code_byte:
elif op_code_type == 1 and rom[offset] == op_code_byte:
oplen = len(op_code[0])
opstr = copy(op_code[0])
xes = op_code[0].count("x")
include_comment = False
for x in range(0, xes):
insertion = ord(rom[offset + 1])
insertion = rom[offset + 1]
insertion = "$" + hex(insertion)[2:]
if current_byte == 0x18 or current_byte==0x20 or current_byte in relative_jumps: #jr or jr nz
#generate a label for the byte we're jumping to
target_address = offset + 2 + c_int8(ord(rom[offset + 1])).value
target_address = offset + 2 + c_int8(rom[offset + 1]).value
if target_address in byte_labels.keys():
byte_labels[target_address]["usage"] = 1 + byte_labels[target_address]["usage"]
line_label2 = byte_labels[target_address]["name"]
@ -726,29 +718,34 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
byte_labels[target_address]["definition"] = False
insertion = line_label2.lower()
include_comment = True
if has_outstanding_labels(byte_labels) and all_outstanding_labels_are_reverse(byte_labels, offset):
include_comment = True
elif current_byte == 0x3e:
last_a_address = ord(rom[offset + 1])
last_a_address = rom[offset + 1]
opstr = opstr[:opstr.find("x")].lower() + insertion + opstr[opstr.find("x")+1:].lower()
# because the $ff00+$ff syntax is silly
if opstr.count("$") > 0 and "+" in opstr:
first_orig = opstr.split("$")[1].split("+")[0]
first_num = "0x"+first_orig
first_val = int(first_num, 16)
second_orig = opstr.split("+$")[1].split("]")[0]
second_num = "0x"+second_orig
second_val = int(second_num, 16)
combined_val = "$" + hex(first_val + second_val)[2:]
replacetron = "[$"+first_orig+"+$"+second_orig+"]"
opstr = opstr.replace(replacetron, "["+combined_val+"]")
if opstr.count("$") > 1 and "+" in opstr:
first_orig = opstr[opstr.find("$"):opstr.find("+")]
first_val = eval(first_orig.replace("$","0x"))
second_orig = opstr[opstr.find("+$")+1:opstr.find("]")]
second_val = eval(second_orig.replace("$","0x"))
combined_val = "$%.4x" % (first_val + second_val)
result = find_label(combined_val, bank_id)
if result != None:
combined_val = result
replacetron = "[%s+%s]" % (first_orig, second_orig)
opstr = opstr.replace(replacetron, "[%s]" % combined_val)
output += spacing + opstr
if include_comment:
output += " ; " + hex(offset)
if current_byte in relative_jumps:
output += " $" + hex(ord(rom[offset + 1]))[2:]
output += " $" + hex(rom[offset + 1])[2:]
output += "\n"
current_byte_number += 1
@ -758,22 +755,21 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
current_byte_number += 1
offset += 1
include_comment = False
elif op_code_type == 2 and ord(rom[offset]) == op_code_byte:
elif op_code_type == 2 and rom[offset] == op_code_byte:
oplen = len(op_code[0])
opstr = copy(op_code[0])
qes = op_code[0].count("?")
for x in range(0, qes):
byte1 = ord(rom[offset + 1])
byte2 = ord(rom[offset + 2])
byte1 = rom[offset + 1]
byte2 = rom[offset + 2]
number = byte1
number += byte2 << 8;
number += byte2 << 8
insertion = "$%.4x" % (number)
if maybe_byte in call_commands or current_byte in relative_unconditional_jumps or current_byte in relative_jumps:
result = find_label(insertion, bank_id)
if result != None:
insertion = result
result = find_label(insertion, bank_id)
if result != None:
insertion = result
opstr = opstr[:opstr.find("?")].lower() + insertion + opstr[opstr.find("?")+1:].lower()
output += spacing + opstr #+ " ; " + hex(offset)
@ -804,7 +800,7 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
#stop reading at a jump, relative jump or return
if current_byte in end_08_scripts_with:
if not has_outstanding_labels(byte_labels) and all_outstanding_labels_are_reverse(byte_labels, offset):
if not has_outstanding_labels(byte_labels) or all_outstanding_labels_are_reverse(byte_labels, offset):
keep_reading = False
is_data = False #cleanup
break
@ -816,7 +812,7 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
keep_reading = True
else:
#if is_data and keep_reading:
output += spacing + "db $" + hex(ord(rom[offset]))[2:] #+ " ; " + hex(offset)
output += spacing + "db $" + hex(rom[offset])[2:] #+ " ; " + hex(offset)
output += "\n"
offset += 1
current_byte_number += 1
@ -826,6 +822,9 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
#offset += 1
#current_byte_number += 1
if current_byte in relative_unconditional_jumps + end_08_scripts_with:
output += "\n"
first_loop = False
#clean up unused labels
@ -835,6 +834,9 @@ def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_add
if label_line["usage"] == 0:
output = output.replace((label_line["name"] + "\n").lower(), "")
#tone down excessive spacing
output = output.replace("\n\n\n","\n\n")
#add the offset of the final location
if include_last_address:
output += "; " + hex(offset)

61
extras/wram.py Normal file
View File

@ -0,0 +1,61 @@
# coding: utf-8
# RGBDS BSS section and constant parsing.
def read_bss_sections(bss):
sections = []
section = {}
address = None
if type(bss) is not list: bss = bss.split('\n')
for line in bss:
line = line.lstrip()
if 'SECTION' in line:
if section: sections.append(section) # last section
address = eval(line[line.find('[')+1:line.find(']')].replace('$','0x'))
section = {
'name': line.split('"')[1],
#'type': line.split(',')[1].split('[')[0].strip(),
'start': address,
'labels': [],
}
elif ':' in line:
# the only labels that don't use :s so far are enders,
# which we typically don't want to end up in the output
label = line[:line.find(':')]
if ';' not in label:
section['labels'] += [{'label': label, 'address': address, 'length': 0}]
elif line[:3] == 'ds ':
length = eval(line[3:line.find(';')].replace('$','0x'))
address += length
if section['labels']:
section['labels'][-1]['length'] += length
sections.append(section)
return sections
wram_sections = read_bss_sections(open('../wram.asm', 'r').readlines())
def make_wram_labels():
wram_labels = {}
for section in wram_sections:
for label in section['labels']:
if label['address'] not in wram_labels.keys():
wram_labels[label['address']] = []
wram_labels[label['address']] += [label['label']]
return wram_labels
wram_labels = make_wram_labels()
def constants_to_dict(constants):
return dict((eval(constant[constant.find('EQU')+3:constant.find(';')].replace('$','0x')), constant[:constant.find('EQU')].strip()) for constant in constants)
def scrape_constants(text):
if type(text) is not list:
text = text.split('\n')
return constants_to_dict([line for line in text if 'EQU' in line[:line.find(';')]])
hram_constants = scrape_constants(open('../hram.asm','r').readlines())
gbhw_constants = scrape_constants(open('../gbhw.asm','r').readlines())

View File

@ -1281,7 +1281,7 @@ CheckDict: ; 1087
cp $15
jp z, $117b
cp $4f
jp z, Char4f
jp z, Char4F
cp $4e
jp z, $12a7
cp $16
@ -1291,7 +1291,7 @@ CheckDict: ; 1087
cp $4c
jp z, $1337
cp $4b
jp z, $131f
jp z, Char4B
cp $51 ; Player name
jp z, $12f2
cp $49
@ -1395,7 +1395,7 @@ CheckDict: ; 1087
INCBIN "baserom.gbc", $117b, $1203 - $117b
Char5D:
Char5D: ; 1203
ld a, [hBattleTurn]
push de
and a
@ -1404,7 +1404,7 @@ Char5D:
jr .asm_126a ; 0x120c $5c
.asm_120e
ld de, Char5AText ; Enemy
call $1078
call PlaceString
ld h, b
ld l, c
ld de, $c616
@ -1419,11 +1419,11 @@ Char5D:
cp $2a
jr z, .asm_1248 ; 0x122b $1b
ld de, $c656
call $1078
call PlaceString
ld h, b
ld l, c
ld de, $12a2
call $1078
call PlaceString
push bc
ld hl, $5939
ld a, $e
@ -1439,7 +1439,7 @@ Char5D:
jr .asm_126a ; 0x1250 $18
push de
ld de, PlayerName
call $1078
call PlaceString
ld h, b
ld l, c
ld a, [$d472]
@ -1449,7 +1449,7 @@ Char5D:
ld de, $12a6
jr .asm_126a ; 0x1268 $0
.asm_126a
call $1078
call PlaceString
ld h, b
ld l, c
pop de
@ -1473,36 +1473,63 @@ Char5AText: ; 0x1295
INCBIN "baserom.gbc", $129c, $12ea - $129c
Char4f: ; 12ea
Char4F: ; 12ea
pop hl
ld hl, $c5e1
hlcoord 1, 16
push hl
jp NextChar
; 0x12f2
INCBIN "baserom.gbc", $12f2, $1345 - $12f2
INCBIN "baserom.gbc", $12f2, $131f - $12f2
Char4B: ; 131f
ld a, [InLinkBattle]
or a
jr nz, .asm_1328
call $13c7
.asm_1328
call $13b6
Char55: ; $1345
push de
ld de, $1354
call $aaf
pop de
ld a, [InLinkBattle]
or a
call z, $13cd
push de
call $138c
call $138c
hlcoord 1, 16
pop de
jp NextChar
; 1345
Char55: ; 1345
push de
ld de, .text_1354
ld b, h
ld c, l
call $1078
call PlaceString
ld h, b
ld l, c
pop de
jp NextChar
; 0x1354
; ???
ld c, e
ld d, b
.text_1354
db $4b, "@"
; 1356
Char5F: ; 0x1356
Char5F: ; 1356
; ends a Pokédex entry
ld [hl],"."
ld [hl], "."
pop hl
ret
; 135a
INCBIN "baserom.gbc", $135a, $15d8 - $135a
@ -17859,7 +17886,7 @@ Function117b31:
call $1cfd
ld hl, $c550
ld de, YesNo117ccc
call $1078
call PlaceString
ld hl, $c54f
ld a, "▶"
ld [hl], a

View File

@ -314,26 +314,19 @@ def separate_comment(l):
asm = ""
comment = None
in_quotes = False
in_comment = False
# token either belongs to the line or to the comment
for token in l:
if in_comment:
if comment:
comment += token
elif in_quotes and token != "\"":
else:
if not in_quotes:
if token == ";":
comment = ";"
continue
if token == "\"":
in_quotes = not in_quotes
asm += token
elif in_quotes and token == "\"":
in_quotes = False
asm += token
elif not in_quotes and token == "\"":
in_quotes = True
asm += token
elif not in_quotes and token != "\"":
if token == ";":
in_comment = True
comment = ";"
else:
asm += token
return asm, comment
def quote_translator(asm):