ref: 5feb5fd208d68a3d8f4d0ce4d925512a8fbe3b97
parent: 14567c2beeeb9272bcd98dfc68e0729ac3b3929e
parent: 5521aa5ce0ad5249ff0d369dd33b4f63cd804b73
author: Bryan Bishop <[email protected]>
date: Wed May 15 08:09:31 EDT 2013
Merge pull request #137 from yenatch/master gbz80disasm reads wram/gbhw/hram and spaces blocks of asm
--- a/extras/gbz80disasm.py
+++ b/extras/gbz80disasm.py
@@ -6,16 +6,15 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
#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
@@ -834,6 +833,9 @@
label_line = byte_labels[label_line]
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:
--- /dev/null
+++ b/extras/wram.py
@@ -1,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())
+
--- a/main.asm
+++ b/main.asm
@@ -1281,7 +1281,7 @@
cp $15
jp z, $117b
cp $4f
- jp z, Char4f
+ jp z, Char4F
cp $4e
jp z, $12a7
cp $16
@@ -1291,7 +1291,7 @@
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 @@
INCBIN "baserom.gbc", $117b, $1203 - $117b
-Char5D:
+Char5D: ; 1203
ld a, [hBattleTurn]
push de
and a
@@ -1404,7 +1404,7 @@
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 @@
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 @@
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 @@
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 @@
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
-Char55: ; $1345
+Char4B: ; 131f
+ ld a, [InLinkBattle]
+ or a
+ jr nz, .asm_1328
+ call $13c7
+
+.asm_1328
+ call $13b6
+
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 @@
call $1cfd
ld hl, $c550
ld de, YesNo117ccc
- call $1078
+ call PlaceString
ld hl, $c54f
ld a, "▶"
ld [hl], a
--- a/preprocessor.py
+++ b/preprocessor.py
@@ -314,26 +314,19 @@
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):