Skip to content

Commit b87d73f

Browse files
committed
tools/mpy_ld.py: Write architecture flags to output natmod if needed.
This commit lets "tools/mpy_ld.py" store architecture flags in generated MPY files if explicitly requested, like "mpy-cross" does. To achieve this, a new command-line option ("--arch-flags") was added to receive the architecture flags value, accepting the same arguments' format as "mpy-cross", and performing the same input validation. The rest of the MPY toolchain was also modified to let the user pass the arch flags to standard native module makefiles. Given that there's already a well-established "ARCH" argument, "ARCH_FLAGS" was chosen to pass the optional flags to "mpy_ld.py". Finally, documentation was updated to mention the new variable. Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
1 parent 0fd0843 commit b87d73f

4 files changed

Lines changed: 62 additions & 11 deletions

File tree

docs/develop/natmod.rst

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,14 @@ options for the ``ARCH`` variable, see below):
4343
* ``rv32imc`` (RISC-V 32 bits with compressed instructions, eg ESP32C3, ESP32C6)
4444
* ``rv64imc`` (RISC-V 64 bits with compressed instructions)
4545

46+
If the chosen platform supports explicit architecture flags and you want to let
47+
the output .mpy file carry those flags' value, you must pass them to the
48+
``ARCH_FLAGS`` flags variable when building the .mpy file.
49+
4650
When compiling and linking the native .mpy file the architecture must be chosen
47-
and the corresponding file can only be imported on that architecture. For more
48-
details about .mpy files see :ref:`mpy_files`.
51+
and the corresponding file can only be imported on that architecture (and if
52+
architecture flags are present, only if they match the target's capabilities).
53+
For more details about .mpy files see :ref:`mpy_files`.
4954

5055
Native code must be compiled as position independent code (PIC) and use a global
5156
offset table (GOT), although the details of this varies from architecture to
@@ -124,7 +129,8 @@ The filesystem layout consists of two main parts, the source files and the Makef
124129
location of the MicroPython repository (to find header files, the relevant Makefile
125130
fragment, and the ``mpy_ld.py`` tool), ``MOD`` as the name of the module, ``SRC``
126131
as the list of source files, optionally specify the machine architecture via ``ARCH``,
127-
and then include ``py/dynruntime.mk``.
132+
along with optional machine architecture flags specified via ``ARCH_FLAGS``, and
133+
then include ``py/dynruntime.mk``.
128134

129135
Minimal example
130136
---------------
@@ -217,6 +223,10 @@ Without modifying the Makefile you can specify the target architecture via::
217223

218224
$ make ARCH=armv7m
219225

226+
Same applies for optional architecture flags via::
227+
228+
$ make ARCH=rv32imc ARCH_FLAGS=zba
229+
220230
Module usage in MicroPython
221231
---------------------------
222232

docs/reference/mpyfiles.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ MPY files is used to indicate that no specific extensions are needed, and saves
193193
one byte in the final output binary.
194194

195195
See also the ``-march-flags`` command-line option in both ``mpy-tool.py`` and
196-
``mpy-cross`` to set this value when creating MPY files.
196+
``mpy-cross``, and the ``--arch-flags`` command-line option in ``mpy_ld.py`` to
197+
set this value when creating MPY files.
197198

198199
The global qstr and constant tables
199200
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

py/dynruntime.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ endif
194194
ifneq ($(MPY_EXTERN_SYM_FILE),)
195195
MPY_LD_FLAGS += --externs "$(realpath $(MPY_EXTERN_SYM_FILE))"
196196
endif
197+
ifneq ($(ARCH_FLAGS),)
198+
MPY_LD_FLAGS += --arch-flags "$(ARCH_FLAGS)"
199+
endif
197200

198201
CFLAGS += $(CFLAGS_EXTRA)
199202

tools/mpy_ld.py

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
# MicroPython constants
3939
MPY_VERSION = 6
4040
MPY_SUB_VERSION = 3
41+
MPY_ARCH_FLAGS = 0x40
4142
MP_CODE_BYTECODE = 2
4243
MP_CODE_NATIVE_VIPER = 4
4344
MP_NATIVE_ARCH_X86 = 1
@@ -1379,7 +1380,7 @@ def write_reloc(self, base, offset, dest, n):
13791380
self.write_uint(n)
13801381

13811382

1382-
def build_mpy(env, fmpy, native_qstr_vals):
1383+
def build_mpy(env, fmpy, native_qstr_vals, arch_flags):
13831384
# Rewrite the entry trampoline if the proper value isn't known earlier, and
13841385
# ensure the trampoline size remains the same.
13851386
if env.arch.delayed_entry_offset:
@@ -1399,12 +1400,16 @@ def build_mpy(env, fmpy, native_qstr_vals):
13991400
out = MPYOutput()
14001401
out.open(fmpy)
14011402

1403+
header_flags = env.arch.mpy_feature | MPY_SUB_VERSION
1404+
if arch_flags != 0:
1405+
header_flags |= MPY_ARCH_FLAGS
1406+
14021407
# MPY: header
1403-
out.write_bytes(
1404-
bytearray(
1405-
[ord("M"), MPY_VERSION, env.arch.mpy_feature | MPY_SUB_VERSION, MP_SMALL_INT_BITS]
1406-
)
1407-
)
1408+
out.write_bytes(bytearray([ord("M"), MPY_VERSION, header_flags, MP_SMALL_INT_BITS]))
1409+
1410+
# MPY: arch flags
1411+
if arch_flags != 0:
1412+
out.write_uint(arch_flags)
14081413

14091414
# MPY: n_qstr
14101415
out.write_uint(1 + len(native_qstr_vals))
@@ -1553,7 +1558,7 @@ def do_link(args):
15531558
load_object_file(env, f, obj_name)
15541559

15551560
link_objects(env, len(native_qstr_vals))
1556-
build_mpy(env, args.output, native_qstr_vals)
1561+
build_mpy(env, args.output, native_qstr_vals, args.arch_flags)
15571562
except LinkError as er:
15581563
print("LinkError:", er.args[0])
15591564
sys.exit(1)
@@ -1603,6 +1608,35 @@ def parse_linkerscript(source):
16031608
return symbols
16041609

16051610

1611+
RV32_EXTENSIONS = {
1612+
"zba": 1 << 0,
1613+
"zcmp": 1 << 1,
1614+
}
1615+
1616+
1617+
def validate_arch_flags(args):
1618+
if args.arch_flags is None:
1619+
args.arch_flags = 0
1620+
return
1621+
if args.arch != "rv32imc":
1622+
raise ValueError('Architecture "{}" does not support extra flags'.format(args.arch))
1623+
if (args.arch_flags.startswith("0") and len(args.arch_flags) > 2) or args.arch_flags.isdigit():
1624+
if args.arch_flags[1] in "bB":
1625+
base = 2
1626+
elif args.arch_flags[1] in "xX":
1627+
base = 16
1628+
else:
1629+
base = 10
1630+
args.arch_flags = int(args.arch_flags, base)
1631+
else:
1632+
flags_value = 0
1633+
for flag in args.arch_flags.lower().split(","):
1634+
if flag not in RV32_EXTENSIONS:
1635+
raise ValueError('Invalid architecture flags value "{}"'.format(flag))
1636+
flags_value |= RV32_EXTENSIONS[flag]
1637+
args.arch_flags = flags_value
1638+
1639+
16061640
def main():
16071641
import argparse
16081642

@@ -1611,6 +1645,7 @@ def main():
16111645
"--verbose", "-v", action="count", default=1, help="increase verbosity"
16121646
)
16131647
cmd_parser.add_argument("--arch", default="x64", help="architecture")
1648+
cmd_parser.add_argument("--arch-flags", default=None, help="optional architecture flags")
16141649
cmd_parser.add_argument("--preprocess", action="store_true", help="preprocess source files")
16151650
cmd_parser.add_argument("--qstrs", default=None, help="file defining additional qstrs")
16161651
cmd_parser.add_argument(
@@ -1632,6 +1667,8 @@ def main():
16321667
global log_level
16331668
log_level = args.verbose
16341669

1670+
validate_arch_flags(args)
1671+
16351672
if args.preprocess:
16361673
do_preprocess(args)
16371674
else:

0 commit comments

Comments
 (0)