mirror of https://github.com/inolen/redream.git
139 lines
4.3 KiB
Python
139 lines
4.3 KiB
Python
#!/usr/bin/env python
|
|
|
|
import argparse
|
|
import os.path
|
|
import re
|
|
import string
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
|
|
parser = argparse.ArgumentParser(description='Process an assembly source file and output it as an ASMTest constructor invocation.')
|
|
parser.add_argument('input', nargs='+', help='Specifies the input file(s).')
|
|
parser.add_argument('-as', help='sh-elf-as path.', required=True)
|
|
parser.add_argument('-ld', help='sh-elf-ld path.', required=True)
|
|
parser.add_argument('-nm', help='sh-elf-nm path.', required=True)
|
|
parser.add_argument('-objcopy', help='sh-elf-objcopy path.', required=True)
|
|
parser.add_argument('-o', help='Specifies the output file.', required=True)
|
|
args = parser.parse_args()
|
|
|
|
def compile_asm(input_path):
|
|
obj_file = tempfile.mktemp(suffix='.obj')
|
|
srec_file = tempfile.mktemp(suffix='.srec')
|
|
bin_file = tempfile.mktemp(suffix='.bin')
|
|
subprocess.call([vars(args)['as'], '-little', '-o', obj_file, input_path])
|
|
subprocess.call([vars(args)['ld'], '--oformat', 'srec', '-Ttext', '0x8c010000', '-e', '0x8c010000', '-o', srec_file, obj_file])
|
|
map = subprocess.check_output([vars(args)['nm'], obj_file])
|
|
subprocess.call([vars(args)['objcopy'], '-I', 'srec', '-O', 'binary', '-R', '.sec1', srec_file, bin_file])
|
|
with open(bin_file, 'r') as f:
|
|
bin = f.read()
|
|
return (map, bin)
|
|
|
|
def parse_value(value):
|
|
if value.startswith('0x'):
|
|
return int(value, 16);
|
|
return int(value)
|
|
|
|
def add_value(test, set, idx, value):
|
|
if idx == None:
|
|
test[set] = value
|
|
elif set.startswith('dr') or set.startswith('xd'):
|
|
# convert 64-bit dr / xd register values into the pairs of fr and xf
|
|
# registers that they alias
|
|
set = set.replace('dr', 'fr')
|
|
set = set.replace('xd', 'xf')
|
|
test[set][idx + 1] = (value & 0xffffffff);
|
|
test[set][idx] = ((value >> 32) & 0xffffffff);
|
|
else:
|
|
test[set][idx] = value
|
|
|
|
def format_values(values):
|
|
if (type(values) is list):
|
|
output = ''
|
|
for v in values:
|
|
output += hex(v & 0xffffffff) + ','
|
|
output = output.strip(',')
|
|
else:
|
|
output = hex(values & 0xffffffff)
|
|
return output
|
|
|
|
def format_test(test):
|
|
output = 'TEST_SH4('
|
|
output += test['name'] + ','
|
|
output += '(uint8_t *)"' + ''.join('\\x' + x.encode('hex') for x in test['bin']) + '",'
|
|
output += str(len(test['bin'])) + ','
|
|
output += hex(test['offset']) + ','
|
|
output += format_values(test['fpscr_in']) + ','
|
|
output += format_values(test['r_in']) + ','
|
|
output += format_values(test['fr_in']) + ','
|
|
output += format_values(test['xf_in']) + ','
|
|
output += format_values(test['fpscr_out']) + ','
|
|
output += format_values(test['r_out']) + ','
|
|
output += format_values(test['fr_out']) + ','
|
|
output += format_values(test['xf_out'])
|
|
output += ')'
|
|
return output
|
|
|
|
def new_test(name, bin, offset):
|
|
return {
|
|
'name': name,
|
|
'bin': bin,
|
|
'offset': offset,
|
|
'fpscr_in': 0xbaadf00d,
|
|
'r_in': [0xbaadf00d] * 16,
|
|
'fr_in': [0xbaadf00d] * 16,
|
|
'xf_in': [0xbaadf00d] * 16,
|
|
'fpscr_out': 0xbaadf00d,
|
|
'r_out': [0xbaadf00d] * 16,
|
|
'fr_out': [0xbaadf00d] * 16,
|
|
'xf_out': [0xbaadf00d] * 16
|
|
}
|
|
|
|
def parse_symbol_map(map, bin):
|
|
tests = {}
|
|
symbols = re.findall('([\d\w]+)\s+t\s+(test_.+)', map)
|
|
for i, symbol in enumerate(symbols):
|
|
offset = int(symbol[0], 16)
|
|
name = symbol[1]
|
|
tests[name] = new_test(name, bin, offset)
|
|
return tests
|
|
|
|
def asm_to_tests(input_path):
|
|
map, bin = compile_asm(input_path)
|
|
|
|
# generate a test for each symbol in the map
|
|
tests = parse_symbol_map(map, bin)
|
|
|
|
# parse input, generating input / output registers for each test
|
|
with open(input_path, 'r') as f:
|
|
lines = f.readlines()
|
|
|
|
# iterate source, using labels and comments as metadata describing
|
|
# each test
|
|
current_test = None
|
|
|
|
for line in lines:
|
|
m = re.match('(test_.+?):', line)
|
|
if m:
|
|
current_test = m.group(1)
|
|
continue
|
|
m = re.match('\s+# REGISTER_(IN|OUT)\s+(\w+?)(\d*?)\s+(.+)', line)
|
|
if m:
|
|
set = (m.group(2) + '_' + m.group(1)).lower()
|
|
idx = int(m.group(3)) if m.group(3) else None
|
|
value = parse_value(m.group(4))
|
|
add_value(tests[current_test], set, idx, value)
|
|
|
|
return tests
|
|
|
|
def list_to_inc(inputs, output_path):
|
|
with open(output_path, 'w') as f:
|
|
for input in inputs:
|
|
tests = asm_to_tests(input)
|
|
for name in tests:
|
|
test = format_test(tests[name])
|
|
f.write(test + '\n')
|
|
|
|
if __name__ == '__main__':
|
|
list_to_inc(args.input, args.o)
|