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 <a.gatti@frob.it>
This commit is contained in:
Alessandro Gatti
2025-10-28 05:03:44 +01:00
committed by Damien George
parent d938d5af4e
commit 1df86516e0
4 changed files with 44 additions and 9 deletions

View File

@@ -145,8 +145,8 @@ static int usage(char **argv) {
"-march=<arch> : set architecture for native emitter;\n"
" x86, x64, armv6, armv6m, armv7m, armv7em, armv7emsp,\n"
" armv7emdp, xtensa, xtensawin, rv32imc, rv64imc, host, debug\n"
"-march-flags=<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=<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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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):