diff options
| -rw-r--r-- | docs/reference/mpyfiles.rst | 27 | ||||
| -rw-r--r-- | mpy-cross/main.c | 1 | ||||
| -rw-r--r-- | py/bc.h | 1 | ||||
| -rw-r--r-- | py/persistentcode.c | 15 | ||||
| -rw-r--r-- | py/persistentcode.h | 6 | ||||
| -rwxr-xr-x | tools/mpy-tool.py | 37 |
6 files changed, 80 insertions, 7 deletions
diff --git a/docs/reference/mpyfiles.rst b/docs/reference/mpyfiles.rst index cd4db623f..b2d552d09 100644 --- a/docs/reference/mpyfiles.rst +++ b/docs/reference/mpyfiles.rst @@ -80,6 +80,10 @@ If importing an .mpy file fails then try the following: above, or by inspecting the ``MPY_CROSS_FLAGS`` Makefile variable for the port that you are using. +* If the third byte of the .mpy file has bit #6 set, then check whether the + encoded architecture-specific flag bits vuint is compatible with the + target you're importing the file on. + The following table shows the correspondence between MicroPython release and .mpy version. @@ -153,10 +157,31 @@ size field ====== ================================ byte value 0x4d (ASCII 'M') byte .mpy major version number -byte native arch and minor version number (was feature flags in older versions) +byte feature flags, native arch, minor version number (was feature flags in older versions) byte number of bits in a small int ====== ================================ +The third byte is split as follows (MSB first): + +====== ================================ +bit meaning +====== ================================ +7 reserved, must be 0 +6 an architecture-specific flags vuint follows the header +5..2 native arch number +1..0 minor version number +====== ================================ + +Architecture-specific flags +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If bit #6 of the header's feature flags byte is set, then a vuint containing +optional architecture-specific information will follow the header. The contents +of this integer depends on which native architecture the file is meant for. + +See also ``mpy-tool.py``'s ``-march-flags`` command-line option to set this +value when creating MPY files. + The global qstr and constant tables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 51e338bbc..0415eb664 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -93,6 +93,7 @@ static int compile_and_save(const char *file, const char *output_file, const cha mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); mp_compiled_module_t cm; cm.context = m_new_obj(mp_module_context_t); + cm.arch_flags = 0; mp_compile_to_raw_code(&parse_tree, source_name, false, &cm); if ((output_file != NULL && strcmp(output_file, "-") == 0) || @@ -220,6 +220,7 @@ typedef struct _mp_compiled_module_t { bool has_native; size_t n_qstr; size_t n_obj; + size_t arch_flags; #endif } mp_compiled_module_t; diff --git a/py/persistentcode.c b/py/persistentcode.c index 6ec0717f9..7d71cfd98 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -471,7 +471,7 @@ void mp_raw_code_load(mp_reader_t *reader, mp_compiled_module_t *cm) { || header[3] > MP_SMALL_INT_BITS) { mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file")); } - if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE) { + if (arch != MP_NATIVE_ARCH_NONE) { if (!MPY_FEATURE_ARCH_TEST(arch)) { if (MPY_FEATURE_ARCH_TEST(MP_NATIVE_ARCH_NONE)) { // On supported ports this can be resolved by enabling feature, eg @@ -483,6 +483,12 @@ void mp_raw_code_load(mp_reader_t *reader, mp_compiled_module_t *cm) { } } + size_t arch_flags = 0; + if (MPY_FEATURE_ARCH_FLAGS_TEST(header[2])) { + (void)arch_flags; + mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file")); + } + size_t n_qstr = read_uint(reader); size_t n_obj = read_uint(reader); mp_module_context_alloc_tables(cm->context, n_qstr, n_obj); @@ -504,6 +510,7 @@ void mp_raw_code_load(mp_reader_t *reader, mp_compiled_module_t *cm) { cm->has_native = MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE; cm->n_qstr = n_qstr; cm->n_obj = n_obj; + cm->arch_flags = arch_flags; #endif // Deregister exception handler and close the reader. @@ -672,7 +679,7 @@ void mp_raw_code_save(mp_compiled_module_t *cm, mp_print_t *print) { byte header[4] = { 'M', MPY_VERSION, - cm->has_native ? MPY_FEATURE_ENCODE_SUB_VERSION(MPY_SUB_VERSION) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH_DYNAMIC) : 0, + (cm->arch_flags != 0 ? MPY_FEATURE_ARCH_FLAGS : 0) | (cm->has_native ? MPY_FEATURE_ENCODE_SUB_VERSION(MPY_SUB_VERSION) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH_DYNAMIC) : 0), #if MICROPY_DYNAMIC_COMPILER mp_dynamic_compiler.small_int_bits, #else @@ -681,6 +688,10 @@ void mp_raw_code_save(mp_compiled_module_t *cm, mp_print_t *print) { }; mp_print_bytes(print, header, sizeof(header)); + if (cm->arch_flags) { + mp_print_uint(print, cm->arch_flags); + } + // Number of entries in constant table. mp_print_uint(print, cm->n_qstr); mp_print_uint(print, cm->n_obj); diff --git a/py/persistentcode.h b/py/persistentcode.h index a45d5fd18..8fd7068e3 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -45,7 +45,7 @@ // Macros to encode/decode native architecture to/from the feature byte #define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2) -#define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2) +#define MPY_FEATURE_DECODE_ARCH(feat) (((feat) >> 2) & 0x2F) // Define the host architecture #if MICROPY_EMIT_X86 @@ -85,6 +85,10 @@ #define MPY_FILE_HEADER_INT (MPY_VERSION \ | (MPY_FEATURE_ENCODE_SUB_VERSION(MPY_SUB_VERSION) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH)) << 8) +// Architecture-specific flags are present in the .mpy file +#define MPY_FEATURE_ARCH_FLAGS (0x40) +#define MPY_FEATURE_ARCH_FLAGS_TEST(x) (((x) & MPY_FEATURE_ARCH_FLAGS) == MPY_FEATURE_ARCH_FLAGS) + enum { MP_NATIVE_ARCH_NONE = 0, MP_NATIVE_ARCH_X86, diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index df918e153..c68f17913 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -120,6 +120,8 @@ MP_BC_FORMAT_QSTR = 1 MP_BC_FORMAT_VAR_UINT = 2 MP_BC_FORMAT_OFFSET = 3 +MP_NATIVE_ARCH_FLAGS_PRESENT = 0x40 + mp_unary_op_method_name = ( "__pos__", "__neg__", @@ -542,6 +544,7 @@ class CompiledModule: mpy_source_file, mpy_segments, header, + arch_flags, qstr_table, obj_table, raw_code, @@ -554,6 +557,7 @@ class CompiledModule: self.mpy_segments = mpy_segments self.source_file = qstr_table[0] self.header = header + self.arch_flags = arch_flags self.qstr_table = qstr_table self.obj_table = obj_table self.raw_code = raw_code @@ -1339,7 +1343,7 @@ def read_mpy(filename): if header[1] != config.MPY_VERSION: raise MPYReadError(filename, "incompatible .mpy version") feature_byte = header[2] - mpy_native_arch = feature_byte >> 2 + mpy_native_arch = (feature_byte >> 2) & 0x2F if mpy_native_arch != MP_NATIVE_ARCH_NONE: mpy_sub_version = feature_byte & 3 if mpy_sub_version != config.MPY_SUB_VERSION: @@ -1350,6 +1354,11 @@ def read_mpy(filename): raise MPYReadError(filename, "native architecture mismatch") config.mp_small_int_bits = header[3] + arch_flags = 0 + # Read the architecture-specific flag bits if present. + if (feature_byte & MP_NATIVE_ARCH_FLAGS_PRESENT) != 0: + arch_flags = reader.read_uint() + # Read number of qstrs, and number of objects. n_qstr = reader.read_uint() n_obj = reader.read_uint() @@ -1378,6 +1387,7 @@ def read_mpy(filename): filename, segments, header, + arch_flags, qstr_table, obj_table, raw_code, @@ -1673,25 +1683,39 @@ def merge_mpy(compiled_modules, output_file): merged_mpy.extend(f.read()) else: main_cm_idx = None + arch_flags = 0 for idx, cm in enumerate(compiled_modules): feature_byte = cm.header[2] - mpy_native_arch = feature_byte >> 2 + mpy_native_arch = (feature_byte >> 2) & 0x2F if mpy_native_arch: # Must use qstr_table and obj_table from this raw_code if main_cm_idx is not None: raise Exception("can't merge files when more than one contains native code") main_cm_idx = idx + arch_flags = cm.arch_flags if main_cm_idx is not None: # Shift main_cm to front of list. compiled_modules.insert(0, compiled_modules.pop(main_cm_idx)) + if config.arch_flags is not None: + arch_flags = config.arch_flags + header = bytearray(4) header[0] = ord("M") header[1] = config.MPY_VERSION - header[2] = config.native_arch << 2 | config.MPY_SUB_VERSION if config.native_arch else 0 + header[2] = ( + (MP_NATIVE_ARCH_FLAGS_PRESENT if arch_flags != 0 else 0) + | config.native_arch << 2 + | config.MPY_SUB_VERSION + if config.native_arch + else 0 + ) header[3] = config.mp_small_int_bits merged_mpy.extend(header) + if arch_flags != 0: + merged_mpy.extend(mp_encode_uint(arch_flags)) + n_qstr = 0 n_obj = 0 for cm in compiled_modules: @@ -1823,6 +1847,12 @@ def main(args=None): default=16, help="mpz digit size used by target (default 16)", ) + cmd_parser.add_argument( + "-march-flags", + metavar="F", + type=int, + help="architecture flags value to set in the output file (strips existing flags if not present)", + ) cmd_parser.add_argument("-o", "--output", default=None, help="output file") cmd_parser.add_argument("files", nargs="+", help="input .mpy files") args = cmd_parser.parse_args(args) @@ -1835,6 +1865,7 @@ def main(args=None): }[args.mlongint_impl] config.MPZ_DIG_SIZE = args.mmpz_dig_size config.native_arch = MP_NATIVE_ARCH_NONE + config.arch_flags = args.march_flags # set config values for qstrs, and get the existing base set of qstrs # already in the firmware |
