redream/test/test_sh4.py

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)