summaryrefslogtreecommitdiff
path: root/gbromgen.py
diff options
context:
space:
mode:
Diffstat (limited to 'gbromgen.py')
-rw-r--r--gbromgen.py96
1 files changed, 88 insertions, 8 deletions
diff --git a/gbromgen.py b/gbromgen.py
index bd56a5b..509fba2 100644
--- a/gbromgen.py
+++ b/gbromgen.py
@@ -17,9 +17,10 @@
##
from argparse import Action, ArgumentParser
+from gbimg import Tileset
from json import load
from os import getpid, makedirs, remove
-from os.path import abspath, exists, join
+from os.path import abspath, dirname, exists, join
from shutil import copy, rmtree
from subprocess import call
from sys import argv, stderr, stdin
@@ -76,6 +77,21 @@ COMP_ADDR = 0x14D
ROMBANKS_ADDR = 0x148
RAMBANKS_ADDR = 0x149
VBLANK_ADDR = 0x40
+SWITCHABLE_ROM_ADDR = 0x4000
+
+class UnsignedIntegerField:
+ def __init__(self, value, size):
+ self._value = int(value)
+ self._size = int(size)
+
+ def __bytes__(self):
+ b = []
+ for i in range(self._size):
+ shift = i * 8
+ mask = 0xFF << shift
+ b.append((self._value & mask) >> shift)
+
+ return bytes(b)
class VersionAction(Action):
def __call__(self, parser, values, namespace, option_string):
@@ -117,6 +133,11 @@ def get_symbol_pos(noi_path, s):
return None
+def add_field(fields, field, pos):
+ b = bytes(field)
+ for i in range(len(b)):
+ fields[pos + i] = b[i]
+
def get_mbc_type(mbc_str):
specs = [s.lower() for s in mbc_str.split('+')]
specs.sort()
@@ -156,10 +177,12 @@ def flush_bank(outfile, written):
return written
-def write_bank(n, outfile, verbose=False):
+def write_bank(n, outfile, data, verbose=False):
size = 0
- # TODO: determine write schedule and actually write
+ for d in data:
+ outfile.write(d.data)
+ size += len(d.data)
print_bank_info(n, size, verbose)
flush_bank(outfile, size)
@@ -184,7 +207,7 @@ def main(args=argv[1:]):
if type(spec) is not dict:
fail('Input specification syntax error')
- RELATIVE_PATH = abspath(args.spec)
+ RELATIVE_PATH = dirname(abspath(args.spec))
if 'hex' not in spec:
fail("'hex' file not specified in input specification")
@@ -250,6 +273,65 @@ def main(args=argv[1:]):
if 'ram-banks' not in spec:
spec['ram-banks'] = 0
+ bank_data = []
+ for _ in range(spec['rom-banks'] - 1):
+ bank_data.append([])
+
+ unalloc_data = []
+
+ if 'tilesets' in spec:
+ for tileset in spec['tilesets']:
+ if 'bank' not in tileset:
+ tileset['bank'] = None
+
+ tileset = Tileset(tileset['img'], tileset['data'], tileset['bank'])
+ if tileset.bank_num:
+ bank_data[tileset.bank_num - 1].append(tileset)
+ else:
+ unalloc_data.append(tileset)
+
+ for ud in unalloc_data:
+ ulen = len(ud)
+ allocated = False
+
+ for i in range(len(bank_data)):
+ b = bank_data[i]
+ blen = 0
+ for d in b:
+ blen += len(d)
+
+ if ROMBANK_SIZE - blen >= ulen:
+ ud.set_bank_num(i + 1)
+ b.append(ud)
+ allocated = True
+ break
+
+ if not allocated:
+ fail('No ROM space for ' + str(ud))
+
+ del ud
+
+ for b in bank_data:
+ pointer = 0
+
+ for d in b:
+ pos = get_symbol_pos(noi_path, d.data_var)
+ if pos:
+ field = UnsignedIntegerField(SWITCHABLE_ROM_ADDR + pointer, 2)
+ add_field(fields, field, pos)
+ else:
+ warn('Could not locate field {}'.format(d.data_var))
+
+ if d.bank_var:
+ pos = get_symbol_pos(noi_path, d.bank_var)
+ if pos:
+ field = UnsignedIntegerField(d.bank_num, 1)
+ add_field(fields, field, pos)
+ else:
+ warn('Could not locate field {}'.format(d.data_var))
+
+ pointer += len(d)
+
try:
temp_gb = join(TEMPDIR, 'temp.gb')
rc = call(['makebin', '-Z', '-p', '-yn', spec['name'], spec['hex'],
@@ -314,10 +396,8 @@ def main(args=argv[1:]):
flush_bank(outfile, size)
- banks_written = 1
- while banks_written < spec['rom-banks']:
- write_bank(banks_written, outfile, args.verbose)
- banks_written += 1
+ for i in range(spec['rom-banks'] - 1):
+ write_bank(i + 1, outfile, bank_data[i], args.verbose)
except Exception as e:
if exists(gb_path):
remove(gb_path)