donut-decomp/asmsplit.py

74 lines
2.3 KiB
Python
Executable file

#!/usr/bin/env nix-shell
#! nix-shell -i python3 -p python3
#
# Usage: ./asmsplit.py MAPFILE < ASMFILE
import os
import re
import sys
basedir = 'asm/'
macros = 'macros.inc'
filenames = {}
lastfile = None
with open(sys.argv[1]) as mapfile:
for mapline in mapfile:
match = re.match(' [0-9a-f]{8} [0-9a-f]{6} ([0-9a-f]{8}) [0-9a-f]{8} [ 0-9][0-9] [^ ]+ \t(.+)', mapline)
if match and match.group(2) != lastfile:
lastfile = match.group(2)
addr = int(match.group(1), 16)
fname = basedir + '/'.join(map(lambda s: os.path.splitext(s)[0], match.group(2).strip().split(' '))) + '.s'
filenames[addr] = fname
curfile = open(macros, 'w')
curaddr = 0
section = ''
remainder = None
while asmline := remainder or sys.stdin.readline():
remainder = None
trim = asmline.strip()
if trim.startswith('.section'):
curaddr = int(trim[-23:-13], 0)
section = asmline
curfile.close()
else:
if trim != "":
if curfile.closed:
fname = filenames[curaddr]
if os.path.exists(fname):
curfile = open(fname, 'a')
curfile.write('\n')
else:
os.makedirs(os.path.dirname(fname), exist_ok = True)
curfile = open(fname, 'x')
curfile.write('.include "' + macros + '"\n\n')
curfile.write(section)
if trim.startswith('.skip'):
curaddr += int(trim[6:], 0)
elif trim.startswith('.incbin'):
f, a, s = asmline.split(', ')
a = int(a, 0)
s = int(s, 0)
if s < 0: raise ValueError()
elif s == 0: continue
k = 1
while (curaddr + k) not in filenames and k < s: k += 1
curaddr += k
if k < s:
asmline = f + ', 0x' + format(a, 'X') + ', 0x' + format(k, 'X') + '\n'
remainder = f + ', 0x' + format(a + k, 'X') + ', 0x' + format(s - k, 'X') + '\n'
elif not trim.startswith('.global') and not trim.endswith(':'):
curaddr += 4
if not curfile.closed: curfile.write(asmline)
if curaddr in filenames and filenames[curaddr] != curfile.name:
curfile.close()