Merge pull request #59 from yenatch/dependencies

Use a mapfile instead of labels.json; object dependency handling
This commit is contained in:
Bryan Bishop 2013-12-09 17:48:11 -08:00
commit 58de3846c7
5 changed files with 111 additions and 44 deletions

View File

@ -8,33 +8,39 @@ import json
import logging
import pointers
import sym
class Labels(object):
"""
Store all labels.
"""
filename = "labels.json"
def __init__(self, config):
def __init__(self, config, filename="pokecrystal.map"):
"""
Setup the instance.
"""
self.config = config
self.path = os.path.join(self.config.path, Labels.filename)
self.filename = filename
self.path = os.path.join(self.config.path, self.filename)
def initialize(self):
"""
Handle anything requiring file-loading and such.
"""
# Look for a mapfile if it's not given
if not os.path.exists(self.path):
logging.info(
"Running crystal.scan_for_predefined_labels to create \"{0}\". Trying.."
.format(Labels.filename)
)
import crystal
crystal.scan_for_predefined_labels()
self.filename = find_mapfile_in_dir(self.config.path)
if self.filename == None:
raise Exception, "Couldn't find any mapfiles. Run rgblink -m to create a mapfile."
self.path = os.path.join(self.config.path, self.filename)
self.labels = json.read(open(self.path, "r").read())
self.labels = sym.read_mapfile(self.path)
def find_mapfile_in_dir(path):
for filename in os.listdir(path):
if os.path.splitext(filename)[1] == '.map':
return filename
return None
def remove_quoted_text(line):
"""get rid of content inside quotes

View File

@ -483,22 +483,18 @@ class Preprocessor(object):
for l in lines:
self.read_line(l)
self.update_globals()
def update_globals(self):
"""
Add any labels not already in globals.asm.
"""
# TODO: pokered needs to be fixed
try:
globes = open(os.path.join(self.config.path, 'globals.asm'), 'r+')
path = os.path.join(self.config.path, 'globals.asm')
if os.path.exists(path):
globes = open(path, 'r+')
lines = globes.readlines()
for globe in self.globes:
line = 'GLOBAL ' + globe + '\n'
if line not in lines:
globes.write(line)
except Exception as exception:
pass # don't care if it's not there...
def read_line(self, l):
"""

View File

@ -0,0 +1,36 @@
# coding: utf-8
"""
Recursively scan an asm file for rgbasm INCLUDEs and INCBINs.
Used to generate dependencies for each rgbasm object.
"""
import os
import sys
import configuration
conf = configuration.Config()
def recursive_scan(filename, includes = []):
if (filename[-4:] == '.asm' or filename[-3] == '.tx') and os.path.exists(filename):
lines = open(filename).readlines()
for line in lines:
for directive in ('INCLUDE', 'INCBIN'):
if directive in line:
line = line[:line.find(';')]
if directive in line:
include = line.split('"')[1]
if include not in includes:
includes += [include]
includes = recursive_scan(os.path.join(conf.path, include), includes)
break
return includes
if __name__ == '__main__':
filenames = sys.argv[1:]
dependencies = []
for filename in filenames:
dependencies += recursive_scan(os.path.join(conf.path, filename))
dependencies = list(set(dependencies))
sys.stdout.write(' '.join(dependencies))

View File

@ -4,7 +4,7 @@ import os
import sys
import json
def make_sym_from_json(filename = '../pokecrystal.sym', j = 'labels.json'):
def make_sym_from_json(filename = 'pokecrystal.sym', j = 'labels.json'):
output = ''
labels = json.load(open(j))
for label in labels:
@ -12,13 +12,13 @@ def make_sym_from_json(filename = '../pokecrystal.sym', j = 'labels.json'):
with open(filename, 'w') as sym:
sym.write(output)
def make_json_from_mapfile(filename='labels.json', mapfile='../pokecrystal.map'):
def make_json_from_mapfile(filename='labels.json', mapfile='pokecrystal.map'):
output = []
labels = filter_wram_addresses(read_mapfile(mapfile))
with open(filename, 'w') as out:
out.write(json.dumps(labels))
def read_mapfile(filename='../pokecrystal.map'):
def read_mapfile(filename='pokecrystal.map'):
"""
Scrape label addresses from an rgbds mapfile.
"""
@ -29,9 +29,15 @@ def read_mapfile(filename='../pokecrystal.map'):
lines = mapfile.readlines()
for line in lines:
# bank #
if 'Bank #' in line:
cur_bank = int(line.lstrip('Bank #').strip(';\n').strip(' (HOME)'))
if line[0].strip(): # section type def
section_type = line.split(' ')[0]
if section_type == 'Bank': # ROM
cur_bank = int(line.split(' ')[1].split(':')[0][1:])
elif section_type in ['WRAM0', 'HRAM']:
cur_bank = 0
elif section_type in ['WRAM, VRAM']:
cur_bank = int(line.split(' ')[2].split(':')[0][1:])
cur_bank = int(line.split(' ')[2].split(':')[0][1:])
# label definition
elif '=' in line:
@ -39,21 +45,10 @@ def read_mapfile(filename='../pokecrystal.map'):
address = int(address.lstrip().replace('$', '0x'), 16)
label = label.strip()
# rgbds doesn't support ram banks yet
bank = cur_bank
offset = address
ranges = [
0x8000 <= address < 0xa000,
0xa000 <= address < 0xc000,
0xc000 <= address < 0xd000,
0xd000 <= address < 0xe000,
]
if any(ranges):
bank = 0
else:
offset += (bank * 0x4000 - 0x4000) if bank > 0 else 0
if address < 0x8000 and bank: # ROM
offset += (bank - 1) * 0x4000
labels += [{
'label': label,

View File

@ -18,22 +18,56 @@ def make_wram_labels(wram_sections):
wram_labels[label['address']] += [label['label']]
return wram_labels
def bracket_value(string, i=0):
return string.split('[')[1 + i*2].split(']')[0]
def read_bss_sections(bss):
sections = []
section = {
"labels": [],
'name': None,
'type': None,
'bank': None,
'start': None,
'labels': [],
}
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'))
comment_index = line.find(';')
line, comment = line[:comment_index].lstrip(), line[comment_index:]
if 'SECTION' == line[:7]:
if section: # previous
sections += [section]
section_def = line.split(',')
name = section_def[0].split('"')[1]
type_ = section_def[1].strip()
if len(section_def) > 2:
bank = bracket_value(section_def[2])
else:
bank = None
if '[' in type_:
address = int(bracket_value(type_).replace('$','0x'), 16)
else:
if address == None or bank != section['bank']:
for type__, addr in [
('VRAM', 0x8000),
('SRAM', 0xa000),
('WRAM0', 0xc000),
('WRAMX', 0xd000),
('HRAM', 0xff80),
]:
if type__ == type_ and section['type'] == type__:
address = addr
# else: keep going from this address
section = {
'name': line.split('"')[1],
#'type': line.split(',')[1].split('[')[0].strip(),
'name': name,
'type': type_,
'bank': bank,
'start': address,
'labels': [],
}
@ -49,7 +83,7 @@ def read_bss_sections(bss):
}]
elif line[:3] == 'ds ':
length = eval(line[3:line.find(';')].replace('$','0x'))
length = eval(line[3:].replace('$','0x'))
address += length
# adjacent labels use the same space
for label in section['labels'][::-1]: