diff --git a/docs/develop/natmod.rst b/docs/develop/natmod.rst index 072d78b207..142e475366 100644 --- a/docs/develop/natmod.rst +++ b/docs/develop/natmod.rst @@ -41,6 +41,7 @@ options for the ``ARCH`` variable, see below): * ``xtensa`` (non-windowed, eg ESP8266) * ``xtensawin`` (windowed with window size 8, eg ESP32, ESP32S3) * ``rv32imc`` (RISC-V 32 bits with compressed instructions, eg ESP32C3, ESP32C6) +* ``rv64imc`` (RISC-V 64 bits with compressed instructions) When compiling and linking the native .mpy file the architecture must be chosen and the corresponding file can only be imported on that architecture. For more @@ -190,7 +191,7 @@ The file ``Makefile`` contains: # Source files (.c or .py) SRC = factorial.c - # Architecture to build for (x86, x64, armv6m, armv7m, xtensa, xtensawin, rv32imc) + # Architecture to build for (x86, x64, armv6m, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 # Include to get the rules for compiling and linking the module @@ -232,15 +233,15 @@ Using Picolibc when building modules ------------------------------------ Using `Picolibc `_ as your C standard -library is not only supported, but in fact it is the default for the rv32imc -platform. However, there are a couple of things worth mentioning to make sure -you don't run into problems later when building code. +library is not only supported, but in fact it is the default for the rv32imc and +rv64imc platforms. However, there are a couple of things worth mentioning to make +sure you don't run into problems later when building code. Some pre-built Picolibc versions (for example, those provided by Ubuntu Linux as the ``picolibc-arm-none-eabi``, ``picolibc-riscv64-unknown-elf``, and ``picolibc-xtensa-lx106-elf`` packages) assume thread-local storage (TLS) is available at runtime, but unfortunately MicroPython modules do not support that -on some architectures (namely ``rv32imc``). This means that some +on some architectures (namely ``rv32imc`` and ``rv64imc``). This means that some functionalities provided by Picolibc will default to use TLS, returning an error either during compilation or during linking. diff --git a/examples/natmod/btree/Makefile b/examples/natmod/btree/Makefile index 1910c67c1f..4ded62bafd 100644 --- a/examples/natmod/btree/Makefile +++ b/examples/natmod/btree/Makefile @@ -7,7 +7,7 @@ MOD = btree_$(ARCH) # Source files (.c or .py) SRC = btree_c.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH ?= x64 BTREE_DIR = $(MPY_DIR)/lib/berkeley-db-1.xx diff --git a/examples/natmod/deflate/Makefile b/examples/natmod/deflate/Makefile index 5823aa4d45..0574bbaf41 100644 --- a/examples/natmod/deflate/Makefile +++ b/examples/natmod/deflate/Makefile @@ -7,7 +7,7 @@ MOD = deflate_$(ARCH) # Source files (.c or .py) SRC = deflate.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH ?= x64 ifeq ($(ARCH),armv6m) diff --git a/examples/natmod/features0/Makefile b/examples/natmod/features0/Makefile index fb01b8d031..788d035eb8 100644 --- a/examples/natmod/features0/Makefile +++ b/examples/natmod/features0/Makefile @@ -7,7 +7,7 @@ MOD = features0 # Source files (.c or .py) SRC = features0.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 # Include to get the rules for compiling and linking the module diff --git a/examples/natmod/features1/Makefile b/examples/natmod/features1/Makefile index 4904051102..47deeed8f2 100644 --- a/examples/natmod/features1/Makefile +++ b/examples/natmod/features1/Makefile @@ -7,7 +7,7 @@ MOD = features1 # Source files (.c or .py) SRC = features1.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 # Include to get the rules for compiling and linking the module diff --git a/examples/natmod/features2/Makefile b/examples/natmod/features2/Makefile index 5ddb74087b..efd096c4ed 100644 --- a/examples/natmod/features2/Makefile +++ b/examples/natmod/features2/Makefile @@ -7,7 +7,7 @@ MOD = features2 # Source files (.c or .py) SRC = main.c prod.c test.py -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 # Link with libm.a and libgcc.a from the toolchain diff --git a/examples/natmod/features3/Makefile b/examples/natmod/features3/Makefile index 3573f41cac..85d1a13421 100644 --- a/examples/natmod/features3/Makefile +++ b/examples/natmod/features3/Makefile @@ -7,7 +7,7 @@ MOD = features3 # Source files (.c or .py) SRC = features3.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 # Include to get the rules for compiling and linking the module diff --git a/examples/natmod/features4/Makefile b/examples/natmod/features4/Makefile index 34fc3a7ef7..4eb657b722 100644 --- a/examples/natmod/features4/Makefile +++ b/examples/natmod/features4/Makefile @@ -7,7 +7,7 @@ MOD = features4 # Source files (.c or .py) SRC = features4.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 # Include to get the rules for compiling and linking the module diff --git a/examples/natmod/framebuf/Makefile b/examples/natmod/framebuf/Makefile index 35453c0bb4..a86efef41f 100644 --- a/examples/natmod/framebuf/Makefile +++ b/examples/natmod/framebuf/Makefile @@ -7,7 +7,7 @@ MOD = framebuf_$(ARCH) # Source files (.c or .py) SRC = framebuf.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH ?= x64 ifeq ($(ARCH),armv6m) diff --git a/examples/natmod/heapq/Makefile b/examples/natmod/heapq/Makefile index 61e2fc8fcc..345359abb3 100644 --- a/examples/natmod/heapq/Makefile +++ b/examples/natmod/heapq/Makefile @@ -7,7 +7,7 @@ MOD = heapq_$(ARCH) # Source files (.c or .py) SRC = heapq.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/random/Makefile b/examples/natmod/random/Makefile index bffbb32d60..27d8ec935f 100644 --- a/examples/natmod/random/Makefile +++ b/examples/natmod/random/Makefile @@ -7,7 +7,7 @@ MOD = random_$(ARCH) # Source files (.c or .py) SRC = random.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH ?= x64 ifeq ($(ARCH),xtensa) diff --git a/examples/natmod/re/Makefile b/examples/natmod/re/Makefile index 6535693dcb..c5f05e64ab 100644 --- a/examples/natmod/re/Makefile +++ b/examples/natmod/re/Makefile @@ -7,7 +7,7 @@ MOD = re_$(ARCH) # Source files (.c or .py) SRC = re.c -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc, rv64imc) ARCH = x64 ifeq ($(ARCH),armv6m) diff --git a/py/dynruntime.mk b/py/dynruntime.mk index 030728cfc9..866d5fae7b 100644 --- a/py/dynruntime.mk +++ b/py/dynruntime.mk @@ -106,7 +106,7 @@ else ifeq ($(ARCH),rv32imc) # rv32imc CROSS = riscv64-unknown-elf- CFLAGS_ARCH += -march=rv32imac -mabi=ilp32 -mno-relax -# If Picolibc is available then select it explicitly. Ubuntu 22.04 ships its +# If Picolibc is available then select it explicitly. Ubuntu 24.04 ships its # bare metal RISC-V toolchain with Picolibc rather than Newlib, and the default # is "nosys" so a value must be provided. To avoid having per-distro # workarounds, always select Picolibc if available. @@ -120,6 +120,25 @@ endif MICROPY_FLOAT_IMPL ?= none +else ifeq ($(ARCH),rv64imc) + +# rv64imc +CROSS = riscv64-unknown-elf- +CFLAGS_ARCH += -march=rv64imac -mabi=lp64 -mno-relax +# If Picolibc is available then select it explicitly. Ubuntu 24.04 ships its +# bare metal RISC-V toolchain with Picolibc rather than Newlib, and the default +# is "nosys" so a value must be provided. To avoid having per-distro +# workarounds, always select Picolibc if available. +PICOLIBC_SPECS := $(shell $(CROSS)gcc --print-file-name=picolibc.specs) +ifneq ($(PICOLIBC_SPECS),picolibc.specs) +CFLAGS_ARCH += -specs=$(PICOLIBC_SPECS) +USE_PICOLIBC := 1 +PICOLIBC_ARCH := rv64imac +PICOLIBC_ABI := lp64 +endif + +MICROPY_FLOAT_IMPL ?= none + else $(error architecture '$(ARCH)' not supported) endif diff --git a/tests/run-natmodtests.py b/tests/run-natmodtests.py index e35e580dc1..cd6c643bf9 100755 --- a/tests/run-natmodtests.py +++ b/tests/run-natmodtests.py @@ -40,6 +40,7 @@ AVAILABLE_ARCHS = ( "xtensa", "xtensawin", "rv32imc", + "rv64imc", ) ARCH_MAPPINGS = {"armv7em": "armv7m"} diff --git a/tools/ci.sh b/tools/ci.sh index 60e870ce65..4ade31160b 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -378,6 +378,8 @@ function ci_qemu_setup_rv64 { ci_gcc_riscv_setup sudo apt-get update sudo apt-get install qemu-system + sudo pip3 install pyelftools + sudo pip3 install ar qemu-system-riscv64 --version } @@ -436,6 +438,9 @@ function ci_qemu_build_rv64 { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV64 submodules make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV64 test + + # Test building native .mpy with rv64imc architecture. + ci_native_mpy_modules_build rv64imc } ######################################################################################## @@ -669,9 +674,9 @@ function ci_native_mpy_modules_build { make -C examples/natmod/$natmod ARCH=$arch done - # features2 requires soft-float on rv32imc and xtensa. + # features2 requires soft-float on rv32imc, rv64imc, and xtensa. make -C examples/natmod/features2 ARCH=$arch clean - if [ $arch = "rv32imc" ] || [ $arch = "xtensa" ]; then + if [ $arch = "rv32imc" ] || [ $arch = "rv64imc" ] || [ $arch = "xtensa" ]; then make -C examples/natmod/features2 ARCH=$arch MICROPY_FLOAT_IMPL=float else make -C examples/natmod/features2 ARCH=$arch diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index b3b28e453d..b363c6a25f 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -49,6 +49,7 @@ MP_NATIVE_ARCH_ARMV7EMDP = 8 MP_NATIVE_ARCH_XTENSA = 9 MP_NATIVE_ARCH_XTENSAWIN = 10 MP_NATIVE_ARCH_RV32IMC = 11 +MP_NATIVE_ARCH_RV64IMC = 12 MP_PERSISTENT_OBJ_STR = 5 MP_SCOPE_FLAG_VIPERRELOC = 0x10 MP_SCOPE_FLAG_VIPERRODATA = 0x20 @@ -62,6 +63,7 @@ R_RISCV_32 = 1 R_X86_64_64 = 1 R_XTENSA_32 = 1 R_386_PC32 = 2 +R_RISCV_64 = 2 R_X86_64_PC32 = 2 R_ARM_ABS32 = 2 R_386_GOT32 = 3 @@ -175,7 +177,7 @@ def asm_jump_xtensa(entry): return struct.pack("> 8) -def asm_jump_rv32(entry): +def asm_jump_riscv(entry): # This could be 6 bytes shorter, but the code currently cannot # support a trampoline with varying length depending on the offset. @@ -261,7 +263,14 @@ ARCH_DATA = { MP_NATIVE_ARCH_RV32IMC << 2, 4, (R_RISCV_32, R_RISCV_GOT_HI20, R_RISCV_GOT32_PCREL), - asm_jump_rv32, + asm_jump_riscv, + ), + "rv64imc": ArchData( + "EM_RISCV", + MP_NATIVE_ARCH_RV64IMC << 2, + 8, + (R_RISCV_64, R_RISCV_GOT_HI20, R_RISCV_GOT32_PCREL), + asm_jump_riscv, ), } @@ -779,7 +788,7 @@ def do_relocation_data(env, text_addr, r): or env.arch.name == "EM_XTENSA" and r_info_type == R_XTENSA_32 or env.arch.name == "EM_RISCV" - and r_info_type == R_RISCV_32 + and r_info_type in (R_RISCV_32, R_RISCV_64) ): # Relocation in data.rel.ro to internal/external symbol if env.arch.word_size == 4: