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 | 
