mirror of https://github.com/Nonannet/copapy.git
Compare commits
2 Commits
34834faac7
...
f3a27b66fb
| Author | SHA1 | Date |
|---|---|---|
|
|
f3a27b66fb | |
|
|
0e3812e0c6 |
|
|
@ -414,9 +414,13 @@ def compile_to_dag(node_list: Iterable[Node], sdb: stencil_database) -> tuple[bi
|
||||||
elif reloc.target_symbol_name.startswith('result_'):
|
elif reloc.target_symbol_name.startswith('result_'):
|
||||||
# Set return jump address to address of following stencil
|
# Set return jump address to address of following stencil
|
||||||
patch = sdb.get_patch(reloc, offset + len(data), offset, binw.Command.PATCH_FUNC.value)
|
patch = sdb.get_patch(reloc, offset + len(data), offset, binw.Command.PATCH_FUNC.value)
|
||||||
|
elif reloc.pelfy_reloc.type == 'R_TRICORE_RELAX':
|
||||||
|
pass
|
||||||
|
elif reloc.pelfy_reloc.symbol.index == 0:
|
||||||
|
assert reloc.pelfy_reloc.type == 'R_TRICORE_15REL'
|
||||||
else:
|
else:
|
||||||
# Patch constants addresses on heap
|
# Patch constants addresses on heap
|
||||||
assert reloc.target_section_index in section_addr_lookup, f"- Function or object in {node.name} missing: {reloc.pelfy_reloc.symbol.name}"
|
assert reloc.target_section_index in section_addr_lookup, f"- Function or object in {node.name} missing: {reloc.pelfy_reloc.symbol.name} ({reloc.pelfy_reloc.type})"
|
||||||
obj_addr = reloc.target_symbol_offset + section_addr_lookup[reloc.target_section_index]
|
obj_addr = reloc.target_symbol_offset + section_addr_lookup[reloc.target_section_index]
|
||||||
patch = sdb.get_patch(reloc, obj_addr, offset, binw.Command.PATCH_OBJECT.value)
|
patch = sdb.get_patch(reloc, obj_addr, offset, binw.Command.PATCH_OBJECT.value)
|
||||||
#print('* constants stancils', patch.type, patch.patch_address, binw.Command.PATCH_OBJECT, node.name)
|
#print('* constants stancils', patch.type, patch.patch_address, binw.Command.PATCH_OBJECT, node.name)
|
||||||
|
|
@ -453,7 +457,8 @@ def compile_to_dag(node_list: Iterable[Node], sdb: stencil_database) -> tuple[bi
|
||||||
for reloc in sdb.get_relocations(name):
|
for reloc in sdb.get_relocations(name):
|
||||||
|
|
||||||
if not reloc.target_section_index:
|
if not reloc.target_section_index:
|
||||||
assert reloc.pelfy_reloc.type == 'R_ARM_V4BX', (reloc.pelfy_reloc.type, name, reloc.pelfy_reloc.symbol.name)
|
if reloc.pelfy_reloc.symbol.name != '__errno': # TODO: Temporary workaround for tricore
|
||||||
|
assert reloc.pelfy_reloc.type in ('R_ARM_V4BX', 'R_TRICORE_RELAX', 'R_TRICORE_15REL', 'R_TRICORE_24REL'), (reloc.pelfy_reloc.type, name, reloc.pelfy_reloc.symbol.name)
|
||||||
|
|
||||||
elif reloc.target_symbol_info in {'STT_OBJECT', 'STT_NOTYPE', 'STT_SECTION'}:
|
elif reloc.target_symbol_info in {'STT_OBJECT', 'STT_NOTYPE', 'STT_SECTION'}:
|
||||||
# Patch constants/variable addresses on heap
|
# Patch constants/variable addresses on heap
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,28 @@ class stencil_database():
|
||||||
scale = 0x10000
|
scale = 0x10000
|
||||||
#print(f" *> {pr.type} {patch_value=} {symbol_address=}, {function_offset=}, {pr.fields['r_addend']=}")
|
#print(f" *> {pr.type} {patch_value=} {symbol_address=}, {function_offset=}, {pr.fields['r_addend']=}")
|
||||||
|
|
||||||
|
elif pr.type == 'R_TRICORE_HIADJ':
|
||||||
|
# S + A + 0x8000 >> 16
|
||||||
|
mask = 0xFFFF
|
||||||
|
patch_value = symbol_address + pr.fields['r_addend'] + 0x8000
|
||||||
|
symbol_type = symbol_type + 0x04 # Absolut value
|
||||||
|
scale = 0x10000
|
||||||
|
#print(f" *> {pr.type} {patch_value=} {symbol_address=}, {function_offset=}")
|
||||||
|
|
||||||
|
elif pr.type == 'R_TRICORE_LO2':
|
||||||
|
# S + A & 0xFFFF
|
||||||
|
mask = 0xFFFF
|
||||||
|
patch_value = symbol_address + pr.fields['r_addend']
|
||||||
|
symbol_type = symbol_type + 0x04 # Absolut value
|
||||||
|
#print(f" *> {pr.type} {patch_value=} {symbol_address=}, {function_offset=}")
|
||||||
|
|
||||||
|
elif pr.type == 'R_TRICORE_24REL':
|
||||||
|
# S + A - P
|
||||||
|
mask = 0xffffff # 24 bit
|
||||||
|
patch_value = symbol_address + pr.fields['r_addend'] - patch_offset
|
||||||
|
assert not patch_value & 0x01, hex(patch_value)
|
||||||
|
scale = 2
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(f"Relocation type {pr.type} in {relocation.pelfy_reloc.target_section.name} pointing to {relocation.pelfy_reloc.symbol.name} not implemented")
|
raise NotImplementedError(f"Relocation type {pr.type} in {relocation.pelfy_reloc.target_section.name} pointing to {relocation.pelfy_reloc.symbol.name} not implemented")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,175 @@
|
||||||
|
from copapy import NumLike, iif, value
|
||||||
|
from copapy.backend import Store, compile_to_dag, add_read_value_remote
|
||||||
|
import subprocess
|
||||||
|
from copapy import _binwrite
|
||||||
|
import copapy.backend as backend
|
||||||
|
import os
|
||||||
|
import warnings
|
||||||
|
import re
|
||||||
|
import struct
|
||||||
|
import pytest
|
||||||
|
import copapy as cp
|
||||||
|
|
||||||
|
if os.name == 'nt':
|
||||||
|
# On Windows wsl and qemu-user is required:
|
||||||
|
# sudo apt install qemu-user
|
||||||
|
qemu_command = ['wsl', '/opt/tricore/bin//qemu-system-tricore', '-M', 'tricore_testboard']
|
||||||
|
else:
|
||||||
|
qemu_command = ['qemu-system-tricore']
|
||||||
|
|
||||||
|
|
||||||
|
def parse_results(log_text: str) -> dict[int, bytes]:
|
||||||
|
regex = r"^READ_DATA offs=(\d*) size=(\d*) data=(.*)$"
|
||||||
|
matches = re.finditer(regex, log_text, re.MULTILINE)
|
||||||
|
var_dict: dict[int, bytes] = {}
|
||||||
|
|
||||||
|
for match in matches:
|
||||||
|
value_str: list[str] = match.group(3).strip().split(' ')
|
||||||
|
#print('--', value_str)
|
||||||
|
value = bytes(int(v, base=16) for v in value_str)
|
||||||
|
if len(value) <= 8:
|
||||||
|
var_dict[int(match.group(1))] = value
|
||||||
|
|
||||||
|
return var_dict
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(command: list[str]) -> str:
|
||||||
|
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf8', check=False)
|
||||||
|
assert result.returncode != 11, f"SIGSEGV (segmentation fault)\n -Error occurred: {result.stderr}\n -Output: {result.stdout}"
|
||||||
|
assert result.returncode == 0, f"\n -Error occurred: {result.stderr}\n -Output: {result.stdout}"
|
||||||
|
return result.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def check_for_qemu() -> bool:
|
||||||
|
command = qemu_command + ['--version']
|
||||||
|
try:
|
||||||
|
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=False)
|
||||||
|
print(result)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
return result.returncode == 0
|
||||||
|
|
||||||
|
|
||||||
|
def function1(c1: NumLike) -> list[NumLike]:
|
||||||
|
return [c1 / 4, c1 / -4, c1 // 4, c1 // -4, (c1 * -1) // 4,
|
||||||
|
c1 * 4, c1 * -4,
|
||||||
|
c1 + 4, c1 - 4,
|
||||||
|
c1 > 2, c1 > 100, c1 < 4, c1 < 100]
|
||||||
|
|
||||||
|
def function1ex(c1: NumLike) -> list[NumLike]:
|
||||||
|
return [c1 // 4]
|
||||||
|
|
||||||
|
|
||||||
|
def function2(c1: NumLike) -> list[NumLike]:
|
||||||
|
return [c1 * 4.44, c1 * -4.44]
|
||||||
|
|
||||||
|
|
||||||
|
def function3(c1: NumLike) -> list[NumLike]:
|
||||||
|
return [c1 / 4]
|
||||||
|
|
||||||
|
|
||||||
|
def function4(c1: NumLike) -> list[NumLike]:
|
||||||
|
return [c1 == 9, c1 == 4, c1 != 9, c1 != 4]
|
||||||
|
|
||||||
|
|
||||||
|
def function5(c1: NumLike) -> list[NumLike]:
|
||||||
|
return [c1 == True, c1 == False, c1 != True, c1 != False, c1 / 2, c1 + 2]
|
||||||
|
|
||||||
|
|
||||||
|
def function6(c1: NumLike) -> list[NumLike]:
|
||||||
|
return [c1 == True]
|
||||||
|
|
||||||
|
|
||||||
|
def iiftests(c1: NumLike) -> list[NumLike]:
|
||||||
|
return [iif(c1 > 5, 8, 9),
|
||||||
|
iif(c1 < 5, 8.5, 9.5),
|
||||||
|
iif(1 > 5, 3.3, 8.8) + c1,
|
||||||
|
iif(1 < 5, c1 * 3.3, 8.8),
|
||||||
|
iif(c1 < 5, c1 * 3.3, 8.8)]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.runner
|
||||||
|
def test_compile():
|
||||||
|
c_i = value(9)
|
||||||
|
c_f = value(1.111)
|
||||||
|
c_b = value(True)
|
||||||
|
|
||||||
|
ret_test = function1(c_i) + function1(c_f) + function2(c_i) + function2(c_f) + function3(c_i) + function4(c_i) + function5(c_b) + [value(9) % 2] + iiftests(c_i) + iiftests(c_f) + [cp.asin(c_i/10)]
|
||||||
|
ret_ref = function1(9) + function1(1.111) + function2(9) + function2(1.111) + function3(9) + function4(9) + function5(True) + [9 % 2] + iiftests(9) + iiftests(1.111) + [cp.asin(9/10)]
|
||||||
|
|
||||||
|
out = [Store(r) for r in ret_test]
|
||||||
|
|
||||||
|
sdb = backend.stencil_db_from_package('tricore')
|
||||||
|
dw, variables = compile_to_dag(out, sdb)
|
||||||
|
|
||||||
|
#dw.write_com(_binwrite.Command.READ_DATA)
|
||||||
|
#dw.write_int(0)
|
||||||
|
#dw.write_int(28)
|
||||||
|
|
||||||
|
du = dw.copy()
|
||||||
|
dw.write_com(_binwrite.Command.RUN_PROG)
|
||||||
|
du.write_com(_binwrite.Command.DUMP_CODE)
|
||||||
|
|
||||||
|
for v in ret_test:
|
||||||
|
assert isinstance(v, value)
|
||||||
|
add_read_value_remote(dw, variables, v.net)
|
||||||
|
|
||||||
|
#dw.write_com(_binwrite.Command.READ_DATA)
|
||||||
|
#dw.write_int(0)
|
||||||
|
#dw.write_int(28)
|
||||||
|
|
||||||
|
dw.write_com(_binwrite.Command.END_COM)
|
||||||
|
du.write_com(_binwrite.Command.END_COM)
|
||||||
|
|
||||||
|
#print('* Data to runner:')
|
||||||
|
#dw.print()
|
||||||
|
|
||||||
|
dw.to_file('build/runner/test-tricore.copapy')
|
||||||
|
du.to_file('build/runner/test-tricore-dump.copapy')
|
||||||
|
|
||||||
|
if not check_for_qemu():
|
||||||
|
warnings.warn("qemu-system-tricore not found, armv7 test skipped!", UserWarning)
|
||||||
|
return
|
||||||
|
if not os.path.isfile('build/runner/coparun-armv7'):
|
||||||
|
warnings.warn("armv7 runner not found, armv7 test skipped!", UserWarning)
|
||||||
|
return
|
||||||
|
|
||||||
|
print('----- Dump code...')
|
||||||
|
command = qemu_command + ['build/runner/coparun-armv7', 'build/runner/test-tricore-dump.copapy', 'build/runner/test.copapy-tricore.bin']
|
||||||
|
result = run_command(command)
|
||||||
|
|
||||||
|
print('----- Run code...')
|
||||||
|
command = qemu_command + ['build/runner/coparun-armv7', 'build/runner/test-tricore.copapy']
|
||||||
|
result = run_command(command)
|
||||||
|
|
||||||
|
|
||||||
|
print('* Output from runner:\n--')
|
||||||
|
print(result)
|
||||||
|
print('--')
|
||||||
|
|
||||||
|
assert 'Return value: 1' in result
|
||||||
|
|
||||||
|
result_data = parse_results(result)
|
||||||
|
|
||||||
|
for test, ref in zip(ret_test, ret_ref):
|
||||||
|
assert isinstance(test, value)
|
||||||
|
address = variables[test.net][0]
|
||||||
|
data = result_data[address]
|
||||||
|
if test.dtype == 'int':
|
||||||
|
val = int.from_bytes(data, sdb.byteorder, signed=True)
|
||||||
|
elif test.dtype == 'bool':
|
||||||
|
val = bool.from_bytes(data, sdb.byteorder)
|
||||||
|
elif test.dtype == 'float':
|
||||||
|
en = {'little': '<', 'big': '>'}[sdb.byteorder]
|
||||||
|
val = struct.unpack(en + 'f', data)[0]
|
||||||
|
assert isinstance(val, float)
|
||||||
|
else:
|
||||||
|
raise Exception(f"Unknown type: {test.dtype}")
|
||||||
|
print('+', val, ref, test.dtype, f" addr={address}")
|
||||||
|
for t in (int, float, bool):
|
||||||
|
assert isinstance(val, t) == isinstance(ref, t), f"Result type does not match for {val} and {ref}"
|
||||||
|
assert val == pytest.approx(ref, 1e-5), f"Result does not match: {val} and reference: {ref}" # pyright: ignore[reportUnknownMemberType]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_compile()
|
||||||
Loading…
Reference in New Issue