From 1df86516e0b4515c4d9b94811ca7da969de6dbc0 Mon Sep 17 00:00:00 2001 From: Alessandro Gatti Date: Tue, 28 Oct 2025 05:03:44 +0100 Subject: [PATCH] py/asmrv32: Reserve a flag for the Zcmp RV32 CPU extension. This commit performs the necessary changes to handle an additional RV32 CPU extension flag, for the Zcmp extension in this case. The changes are not limited to RV32-only code, as other parts of the tooling need to be modified for this: the testing framework has to be made aware that an extra bit can be set in sys.implementation._mpy and needs to know how it is called, and "mpy-cross" must be able to actually set that flag bit in the first place via the appropriate command line argument. Signed-off-by: Alessandro Gatti --- mpy-cross/main.c | 37 +++++++++++++++++++++++++++++++------ py/asmrv32.h | 6 ++++-- py/mpconfig.h | 5 +++++ tests/run-tests.py | 5 ++++- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 38190671c6..c9109788fb 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -145,8 +145,8 @@ static int usage(char **argv) { "-march= : set architecture for native emitter;\n" " x86, x64, armv6, armv6m, armv7m, armv7em, armv7emsp,\n" " armv7emdp, xtensa, xtensawin, rv32imc, rv64imc, host, debug\n" - "-march-flags= : set architecture-specific flags (can be either a dec/hex/bin value or a string)\n" - " supported flags for rv32imc: zba\n" + "-march-flags= : set architecture-specific flags (can be either a dec/hex/bin value or a comma-separated flags string)\n" + " supported flags for rv32imc: zba, zcmp\n" "\n" "Implementation specific options:\n", argv[0] ); @@ -259,6 +259,34 @@ static bool parse_integer(const char *value, mp_uint_t *integer) { return valid; } +#if MICROPY_EMIT_NATIVE && MICROPY_EMIT_RV32 +static bool parse_rv32_flags_string(const char *source, mp_uint_t *flags) { + assert(source && "Flag arguments string is NULL."); + assert(flags && "Collected flags pointer is NULL."); + + const char *current = source; + const char *end = source + strlen(source); + mp_uint_t collected_flags = 0; + while (current < end) { + const char *separator = strchr(current, ','); + if (separator == NULL) { + separator = end; + } + ptrdiff_t length = separator - current; + if (length == (sizeof("zba") - 1) && memcmp(current, "zba", length) == 0) { + collected_flags |= RV32_EXT_ZBA; + } else if (length == (sizeof("zcmp") - 1) && memcmp(current, "zcmp", length) == 0) { + collected_flags |= RV32_EXT_ZCMP; + } else { + return false; + } + current = separator + 1; + } + *flags = collected_flags; + return collected_flags != 0; +} +#endif + MP_NOINLINE int main_(int argc, char **argv) { pre_process_options(argc, argv); @@ -412,14 +440,11 @@ MP_NOINLINE int main_(int argc, char **argv) { if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_RV32IMC) { mp_dynamic_compiler.backend_options = (void *)&rv32_options; mp_uint_t raw_flags = 0; - if (parse_integer(arch_flags, &raw_flags)) { + if (parse_integer(arch_flags, &raw_flags) || parse_rv32_flags_string(arch_flags, &raw_flags)) { if ((raw_flags & ~((mp_uint_t)RV32_EXT_ALL)) == 0) { rv32_options.allowed_extensions = raw_flags; processed = true; } - } else if (strncmp(arch_flags, "zba", sizeof("zba") - 1) == 0) { - rv32_options.allowed_extensions |= RV32_EXT_ZBA; - processed = true; } } #endif diff --git a/py/asmrv32.h b/py/asmrv32.h index 1100d09801..ed1b5a835c 100644 --- a/py/asmrv32.h +++ b/py/asmrv32.h @@ -125,8 +125,9 @@ typedef struct _asm_rv32_t { enum { RV32_EXT_NONE = 0, RV32_EXT_ZBA = 1 << 0, + RV32_EXT_ZCMP = 1 << 1, - RV32_EXT_ALL = RV32_EXT_ZBA + RV32_EXT_ALL = RV32_EXT_ZBA | RV32_EXT_ZCMP }; typedef struct _asm_rv32_backend_options_t { @@ -710,7 +711,8 @@ static inline void asm_rv32_opcode_xori(asm_rv32_t *state, mp_uint_t rd, mp_uint } #define MICROPY_RV32_EXTENSIONS \ - (MICROPY_EMIT_RV32_ZBA ? RV32_EXT_ZBA : 0) + ((MICROPY_EMIT_RV32_ZBA ? RV32_EXT_ZBA : 0) | \ + (MICROPY_EMIT_RV32_ZCMP ? RV32_EXT_ZCMP : 0)) static inline uint8_t asm_rv32_allowed_extensions(void) { uint8_t extensions = MICROPY_RV32_EXTENSIONS; diff --git a/py/mpconfig.h b/py/mpconfig.h index 666b15573d..e272564a7f 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -507,6 +507,11 @@ typedef uint64_t mp_uint_t; #define MICROPY_EMIT_RV32_ZBA (0) #endif +// Whether to emit RISC-V RV32 Zcmp opcodes in native code +#ifndef MICROPY_EMIT_RV32_ZCMP +#define MICROPY_EMIT_RV32_ZCMP (0) +#endif + // Whether to enable the RISC-V RV32 inline assembler #ifndef MICROPY_EMIT_INLINE_RV32 #define MICROPY_EMIT_INLINE_RV32 (0) diff --git a/tests/run-tests.py b/tests/run-tests.py index d4c6d445e9..7f666e09b5 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -22,7 +22,10 @@ TEST_TIMEOUT = float(os.environ.get("MICROPY_TEST_TIMEOUT", 30)) # are guaranteed to always work, this one should though. BASEPATH = os.path.dirname(os.path.abspath(inspect.getsourcefile(lambda: None))) -RV32_ARCH_FLAGS = {"zba": 1 << 0} +RV32_ARCH_FLAGS = { + "zba": 1 << 0, + "zcmp": 1 << 1, +} def base_path(*p):