diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/boardgen.py | 8 | ||||
-rwxr-xr-x | tools/ci.sh | 84 | ||||
-rwxr-xr-x | tools/mpy_ld.py | 91 |
3 files changed, 139 insertions, 44 deletions
diff --git a/tools/boardgen.py b/tools/boardgen.py index 39bedf71cd..3723e7ce31 100644 --- a/tools/boardgen.py +++ b/tools/boardgen.py @@ -108,6 +108,10 @@ class Pin: ) ) + # Iterate over board pin names in consistent sorted order. + def board_pin_names(self): + return sorted(self._board_pin_names, key=lambda x: x[0]) + # Override this to handle an af specified in af.csv. def add_af(self, af_idx, af_name, af): raise NotImplementedError @@ -295,7 +299,7 @@ class PinGenerator: file=out_source, ) for pin in self.available_pins(): - for board_pin_name, board_hidden in pin._board_pin_names: + for board_pin_name, board_hidden in pin.board_pin_names(): if board_hidden: # Don't include hidden pins in Pins.board. continue @@ -389,7 +393,7 @@ class PinGenerator: # #define pin_BOARDNAME (pin_CPUNAME) if board: - for board_pin_name, _board_hidden in pin._board_pin_names: + for board_pin_name, _board_hidden in pin.board_pin_names(): # Note: Hidden board pins are still available to C via the macro. # Note: The RHS isn't wrapped in (), which is necessary to make the # STATIC_AF_ macro work on STM32. diff --git a/tools/ci.sh b/tools/ci.sh index d12b4bcd31..a5cd326c1c 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -93,23 +93,30 @@ function ci_code_size_build { function code_size_build_step { COMMIT=$1 OUTFILE=$2 - IGNORE_ERRORS=$3 echo "Building ${COMMIT}..." git checkout --detach $COMMIT git submodule update --init $SUBMODULES git show -s tools/metrics.py clean $PORTS_TO_CHECK - tools/metrics.py build $PORTS_TO_CHECK | tee $OUTFILE || $IGNORE_ERRORS + tools/metrics.py build $PORTS_TO_CHECK | tee $OUTFILE + return $? } + # Allow errors from tools/metrics.py to propagate out of the pipe above. + set -o pipefail + # build reference, save to size0 # ignore any errors with this build, in case master is failing - code_size_build_step $REFERENCE ~/size0 true + code_size_build_step $REFERENCE ~/size0 # build PR/branch, save to size1 - code_size_build_step $COMPARISON ~/size1 false + code_size_build_step $COMPARISON ~/size1 + STATUS=$? + set +o pipefail unset -f code_size_build_step + + return $STATUS } ######################################################################################## @@ -317,13 +324,24 @@ function ci_qemu_setup_rv32 { qemu-system-riscv32 --version } -function ci_qemu_build_arm { +function ci_qemu_build_arm_prepare { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/qemu submodules +} + +function ci_qemu_build_arm_bigendian { + ci_qemu_build_arm_prepare make ${MAKEOPTS} -C ports/qemu CFLAGS_EXTRA=-DMP_ENDIANNESS_BIG=1 - make ${MAKEOPTS} -C ports/qemu clean - make ${MAKEOPTS} -C ports/qemu test_full +} + +function ci_qemu_build_arm_sabrelite { + ci_qemu_build_arm_prepare make ${MAKEOPTS} -C ports/qemu BOARD=SABRELITE test_full +} + +function ci_qemu_build_arm_thumb { + ci_qemu_build_arm_prepare + make ${MAKEOPTS} -C ports/qemu test_full # Test building and running native .mpy with armv7m architecture. ci_native_mpy_modules_build armv7m @@ -509,13 +527,26 @@ function ci_unix_run_tests_helper { make -C ports/unix "$@" test } +function ci_unix_run_tests_full_extra { + micropython=$1 + (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=$micropython ./run-multitests.py multi_net/*.py) + (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=$micropython ./run-perfbench.py 1000 1000) +} + +function ci_unix_run_tests_full_no_native_helper { + variant=$1 + shift + micropython=../ports/unix/build-$variant/micropython + make -C ports/unix VARIANT=$variant "$@" test_full_no_native + ci_unix_run_tests_full_extra $micropython +} + function ci_unix_run_tests_full_helper { variant=$1 shift micropython=../ports/unix/build-$variant/micropython make -C ports/unix VARIANT=$variant "$@" test_full - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=$micropython ./run-multitests.py multi_net/*.py) - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=$micropython ./run-perfbench.py 1000 1000) + ci_unix_run_tests_full_extra $micropython } function ci_native_mpy_modules_build { @@ -524,38 +555,23 @@ function ci_native_mpy_modules_build { else arch=$1 fi - for natmod in features1 features3 features4 heapq re + for natmod in deflate features1 features3 features4 framebuf heapq random re do - make -C examples/natmod/$natmod clean + make -C examples/natmod/$natmod ARCH=$arch clean make -C examples/natmod/$natmod ARCH=$arch done - # deflate, framebuf, and random currently cannot build on xtensa due to - # some symbols that have been removed from the compiler's runtime, in - # favour of being provided from ROM. - if [ $arch != "xtensa" ]; then - for natmod in deflate framebuf random - do - make -C examples/natmod/$natmod clean - make -C examples/natmod/$natmod ARCH=$arch - done - fi - - # features2 requires soft-float on armv7m, rv32imc, and xtensa. On armv6m - # the compiler generates absolute relocations in the object file - # referencing soft-float functions, which is not supported at the moment. - make -C examples/natmod/features2 clean - if [ $arch = "rv32imc" ] || [ $arch = "armv7m" ] || [ $arch = "xtensa" ]; then + # features2 requires soft-float on rv32imc and xtensa. + make -C examples/natmod/features2 ARCH=$arch clean + if [ $arch = "rv32imc" ] || [ $arch = "xtensa" ]; then make -C examples/natmod/features2 ARCH=$arch MICROPY_FLOAT_IMPL=float - elif [ $arch != "armv6m" ]; then + else make -C examples/natmod/features2 ARCH=$arch fi - # btree requires thread local storage support on rv32imc, whilst on xtensa - # it relies on symbols that are provided from ROM but not exposed to - # natmods at the moment. - if [ $arch != "rv32imc" ] && [ $arch != "xtensa" ]; then - make -C examples/natmod/btree clean + # btree requires thread local storage support on rv32imc. + if [ $arch != "rv32imc" ]; then + make -C examples/natmod/btree ARCH=$arch clean make -C examples/natmod/btree ARCH=$arch fi } @@ -668,7 +684,7 @@ function ci_unix_nanbox_build { } function ci_unix_nanbox_run_tests { - ci_unix_run_tests_full_helper nanbox PYTHON=python2.7 + ci_unix_run_tests_full_no_native_helper nanbox PYTHON=python2.7 } function ci_unix_float_build { diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index a47653f900..a600ec12c3 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -402,6 +402,7 @@ class LinkEnv: self.known_syms = {} # dict of symbols that are defined self.unresolved_syms = [] # list of unresolved symbols self.mpy_relocs = [] # list of relocations needed in the output .mpy file + self.externs = {} # dict of externally-defined symbols def check_arch(self, arch_name): if arch_name != self.arch.name: @@ -491,10 +492,14 @@ def populate_got(env): sym = got_entry.sym if hasattr(sym, "resolved"): sym = sym.resolved - sec = sym.section - addr = sym["st_value"] - got_entry.sec_name = sec.name - got_entry.link_addr += sec.addr + addr + if sym.name in env.externs: + got_entry.sec_name = ".external.fixed_addr" + got_entry.link_addr = env.externs[sym.name] + else: + sec = sym.section + addr = sym["st_value"] + got_entry.sec_name = sec.name + got_entry.link_addr += sec.addr + addr # Get sorted GOT, sorted by external, text, rodata, bss so relocations can be combined got_list = sorted( @@ -520,6 +525,9 @@ def populate_got(env): dest = int(got_entry.name.split("+")[1], 16) // env.arch.word_size elif got_entry.sec_name == ".external.mp_fun_table": dest = got_entry.sym.mp_fun_table_offset + elif got_entry.sec_name == ".external.fixed_addr": + # Fixed-address symbols should not be relocated. + continue elif got_entry.sec_name.startswith(".text"): dest = ".text" elif got_entry.sec_name.startswith(".rodata"): @@ -703,8 +711,9 @@ def do_relocation_text(env, text_addr, r): (addr, value) = process_riscv32_relocation(env, text_addr, r) elif env.arch.name == "EM_ARM" and r_info_type == R_ARM_ABS32: - # happens for soft-float on armv6m - raise ValueError("Absolute relocations not supported on ARM") + # Absolute relocation, handled as a data relocation. + do_relocation_data(env, text_addr, r) + return else: # Unknown/unsupported relocation @@ -773,9 +782,9 @@ def do_relocation_data(env, text_addr, r): ): # Relocation in data.rel.ro to internal/external symbol if env.arch.word_size == 4: - struct_type = "<I" + struct_type = "<i" elif env.arch.word_size == 8: - struct_type = "<Q" + struct_type = "<q" if hasattr(s, "resolved"): s = s.resolved sec = s.section @@ -1207,6 +1216,9 @@ def link_objects(env, native_qstr_vals_len): sym.section = env.obj_table_section elif sym.name in env.known_syms: sym.resolved = env.known_syms[sym.name] + elif sym.name in env.externs: + # Fixed-address symbols do not need pre-processing. + continue else: if sym.name in fun_table: sym.section = mp_fun_table_sec @@ -1214,6 +1226,15 @@ def link_objects(env, native_qstr_vals_len): else: undef_errors.append("{}: undefined symbol: {}".format(sym.filename, sym.name)) + for sym in env.externs: + if sym in env.known_syms: + log( + LOG_LEVEL_1, + "Symbol {} is a fixed-address symbol at {:08x} and is also provided from an object file".format( + sym, env.externs[sym] + ), + ) + if undef_errors: raise LinkError("\n".join(undef_errors)) @@ -1456,6 +1477,9 @@ def do_link(args): log(LOG_LEVEL_2, "qstr vals: " + ", ".join(native_qstr_vals)) env = LinkEnv(args.arch) try: + if args.externs: + env.externs = parse_linkerscript(args.externs) + # Load object files for fn in args.files: with open(fn, "rb") as f: @@ -1484,6 +1508,50 @@ def do_link(args): sys.exit(1) +def parse_linkerscript(source): + # This extracts fixed-address symbol lists from linkerscripts, only parsing + # a small subset of all possible directives. Right now the only + # linkerscript file this is really tested against is the ESP8266's builtin + # ROM functions list ($SDK/ld/eagle.rom.addr.v6.ld). + # + # The parser should be able to handle symbol entries inside ESP-IDF's ROM + # symbol lists for the ESP32 range of MCUs as well (see *.ld files in + # $SDK/components/esp_rom/<name>/). + + symbols = {} + + LINE_REGEX = re.compile( + r'^(?P<weak>PROVIDE\()?' # optional weak marker start + r'(?P<symbol>[a-zA-Z_]\w*)' # symbol name + r'=0x(?P<address>[\da-fA-F]{1,8})*' # symbol address + r'(?(weak)\));$', # optional weak marker end and line terminator + re.ASCII, + ) + + inside_comment = False + for line in (line.strip() for line in source.readlines()): + if line.startswith('/*') and not inside_comment: + if not line.endswith('*/'): + inside_comment = True + continue + if inside_comment: + if line.endswith('*/'): + inside_comment = False + continue + if line.startswith('//'): + continue + match = LINE_REGEX.match(''.join(line.split())) + if not match: + continue + tokens = match.groupdict() + symbol = tokens['symbol'] + address = int(tokens['address'], 16) + if symbol in symbols: + raise ValueError(f"Symbol {symbol} already defined") + symbols[symbol] = address + return symbols + + def main(): import argparse @@ -1500,6 +1568,13 @@ def main(): cmd_parser.add_argument( "--output", "-o", default=None, help="output .mpy file (default to input with .o->.mpy)" ) + cmd_parser.add_argument( + "--externs", + "-e", + type=argparse.FileType("rt"), + default=None, + help="linkerscript providing fixed-address symbols to augment symbol resolution", + ) cmd_parser.add_argument("files", nargs="+", help="input files") args = cmd_parser.parse_args() |