diff --git a/.devcontainer/cortex-m-toolchain.sh b/.devcontainer/cortex-m-toolchain.sh index de1ccde62742a..38ecdb72a7b96 100755 --- a/.devcontainer/cortex-m-toolchain.sh +++ b/.devcontainer/cortex-m-toolchain.sh @@ -14,10 +14,10 @@ echo -e "[cortex-m-toolchain.sh] downloading and installing gcc-arm-non-eabi too cd /workspaces wget -qO gcc-arm-none-eabi.tar.xz \ - https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-arm-none-eabi.tar.xz + https://developer.arm.com/-/media/Files/downloads/gnu/14.2.rel1/binrel/arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi.tar.xz tar -xJf gcc-arm-none-eabi.tar.xz -ln -s arm-gnu-toolchain-13.2.Rel1-x86_64-arm-none-eabi gcc-arm-none-eabi +ln -s arm-gnu-toolchain-14.2.Rel1-x86_64-arm-none-eabi gcc-arm-none-eabi rm -f gcc-arm-none-eabi.tar.xz echo -e "[cortex-m-toolchain.sh] update PATH in environment" diff --git a/.github/actions/deps/external/action.yml b/.github/actions/deps/external/action.yml index 0b1444a820da2..10aace1134ec5 100644 --- a/.github/actions/deps/external/action.yml +++ b/.github/actions/deps/external/action.yml @@ -27,7 +27,7 @@ runs: uses: carlosperate/arm-none-eabi-gcc-action@v1 with: # When changing this update what Windows grabs too! - release: '13.2.Rel1' + release: '14.2.Rel1' # espressif - name: Get espressif toolchain diff --git a/.github/actions/deps/ports/broadcom/action.yml b/.github/actions/deps/ports/broadcom/action.yml index f936f8e7edfde..9ad0e361bda1b 100644 --- a/.github/actions/deps/ports/broadcom/action.yml +++ b/.github/actions/deps/ports/broadcom/action.yml @@ -5,8 +5,8 @@ runs: steps: - name: Get broadcom toolchain run: | - wget --no-verbose https://adafruit-circuit-python.s3.amazonaws.com/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-elf.tar.xz - sudo tar -C /usr --strip-components=1 -xaf arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-elf.tar.xz + wget --no-verbose https://adafruit-circuit-python.s3.amazonaws.com/arm-gnu-toolchain-14.2.rel1-x86_64-aarch64-none-elf.tar.xz + sudo tar -C /usr --strip-components=1 -xaf arm-gnu-toolchain-14.2.rel1-x86_64-aarch64-none-elf.tar.xz sudo apt-get update sudo apt-get install -y mtools shell: bash diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index eb6a9a0c26325..0f837d793bddc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -261,9 +261,9 @@ jobs: python3 -c "import sys, locale; print(sys.getdefaultencoding(), locale.getpreferredencoding(False))" - name: Install dependencies run: | - wget --no-verbose -O gcc-arm.zip https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-mingw-w64-i686-arm-none-eabi.zip - unzip -q -d /tmp gcc-arm.zip - tar -C /tmp/arm-gnu-toolchain* -cf - . | tar -C /usr/local -xf - + wget --no-verbose -O gcc-arm.zip https://developer.arm.com/-/media/Files/downloads/gnu/14.2.rel1/binrel/arm-gnu-toolchain-14.2.rel1-mingw-w64-i686-arm-none-eabi.zip + unzip -q -d /tmp/arm-gnu-toolchain gcc-arm.zip + tar -C /tmp/arm-gnu-toolchain -cf - . | tar -C /usr/local -xf - # We could use a venv instead, but that requires entering the venv on each run step # that runs in its own shell. There are some actions that help with that, but not for msys2 # that I can find. (dhalbert) diff --git a/.github/workflows/notify-on-issue-label.yml b/.github/workflows/notify-on-issue-label.yml index da1ac0a18e28a..2b229156811f8 100644 --- a/.github/workflows/notify-on-issue-label.yml +++ b/.github/workflows/notify-on-issue-label.yml @@ -10,7 +10,7 @@ jobs: permissions: issues: write steps: - - uses: tekktrik/issue-labeled-ping@v1 + - uses: tekktrik/issue-labeled-ping@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} user: v923z diff --git a/.gitignore b/.gitignore index 6725b901b92bf..f996911d8d746 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ *.o *.a !atmel-samd/asf/**/*.a +!ports/espressif/microros-lib/**/*.a *.elf *.bin !*.toml.bin @@ -38,10 +39,12 @@ bin/ circuitpython-stubs/ test-stubs/ build-*/ +docs/genrst/ -# Test failure outputs +# Test failure outputs and intermediate artifacts ###################### tests/results/* +tests/ports/unix/ffi_lib.so # Python cache files ###################### @@ -75,6 +78,7 @@ TAGS #################### *~ +# MacOS desktop metadata files *.DS_Store **/*.DS_Store *.icloud @@ -99,6 +103,7 @@ TAGS .cache **/CLAUDE.local.md +.claude # windsurf rules .windsurfrules diff --git a/.gitmodules b/.gitmodules index a5226ffafdd52..b1ec0f9faee7f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,7 +7,7 @@ url = https://github.com/micropython/axtls.git [submodule "lib/libffi"] path = lib/libffi - url = https://github.com/atgreen/libffi + url = https://github.com/libffi/libffi [submodule "lib/berkeley-db-1.xx"] path = lib/berkeley-db-1.xx url = https://github.com/micropython/berkeley-db-1.xx @@ -412,3 +412,6 @@ [submodule "ports/analog/msdk"] path = ports/analog/msdk url = https://github.com/analogdevicesinc/msdk.git +[submodule "ports/espressif/microros-lib"] + path = ports/espressif/microros-lib + url = https://github.com/hierophect/microros-lib.git diff --git a/LICENSE b/LICENSE index a9ba6ea592670..df12f02238a51 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2023 Damien P. George +Copyright (c) 2013-2024 Damien P. George Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -22,8 +22,6 @@ THE SOFTWARE. -------------------------------------------------------------------------------- -# CIRCUITPY-CHANGE: - Unless specified otherwise (see below), the above license and copyright applies to all files derived from MicroPython in this repository. diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index 9663e70699807..6376f6f10c8c9 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -40,13 +40,13 @@ bool vm_used_ble; void common_hal_bleio_init(void) { } -void bleio_user_reset() { +void bleio_user_reset(void) { // HCI doesn't support the BLE workflow so just do a full reset. bleio_reset(); } // Turn off BLE on a reset or reload. -void bleio_reset() { +void bleio_reset(void) { // Create a UUID object for all CCCD's. cccd_uuid.base.type = &bleio_uuid_type; common_hal_bleio_uuid_construct(&cccd_uuid, BLE_UUID_CCCD, NULL); diff --git a/docs/library/builtins.rst b/docs/library/builtins.rst index 6003c23fb131b..97ca0044ec389 100644 --- a/docs/library/builtins.rst +++ b/docs/library/builtins.rst @@ -86,15 +86,9 @@ Functions and types .. class:: int() - .. classmethod:: from_bytes(bytes, byteorder) + .. classmethod:: from_bytes(bytes, byteorder="big", *, signed=False) - In CircuitPython, the ``byteorder`` parameter must be positional (this is - compatible with CPython). - - .. method:: to_bytes(size, byteorder) - - In CircuitPython, the ``byteorder`` parameter must be positional (this is - compatible with CPython). + .. method:: to_bytes(length=1, byteorder="big", *, signed=False) .. function:: isinstance() diff --git a/docs/library/micropython.rst b/docs/library/micropython.rst index 166192de3a38e..40b3cdf157231 100644 --- a/docs/library/micropython.rst +++ b/docs/library/micropython.rst @@ -1,5 +1,5 @@ -:mod:`micropython` -- MicroPython extensions and internals -========================================================== +:mod:`micropython` -- access and control MicroPython internals +============================================================== .. module:: micropython :synopsis: access and control MicroPython internals @@ -26,3 +26,132 @@ Functions provided as part of the :mod:`micropython` module mainly so that scripts can be written which run under both CPython and MicroPython, by following the above pattern. + +.. CIRCUITPY-CHANGE: REMOVE .. function:: opt_level([level]) + + If *level* is given then this function sets the optimisation level for subsequent + compilation of scripts, and returns ``None``. Otherwise it returns the current + optimisation level. + + The optimisation level controls the following compilation features: + + - Assertions: at level 0 assertion statements are enabled and compiled into the + bytecode; at levels 1 and higher assertions are not compiled. + - Built-in ``__debug__`` variable: at level 0 this variable expands to ``True``; + at levels 1 and higher it expands to ``False``. + - Source-code line numbers: at levels 0, 1 and 2 source-code line number are + stored along with the bytecode so that exceptions can report the line number + they occurred at; at levels 3 and higher line numbers are not stored. + + The default optimisation level is usually level 0. + +.. CIRCUITPY-CHANGE: REMOVE .. function:: alloc_emergency_exception_buf(size) + + Allocate *size* bytes of RAM for the emergency exception buffer (a good + size is around 100 bytes). The buffer is used to create exceptions in cases + when normal RAM allocation would fail (eg within an interrupt handler) and + therefore give useful traceback information in these situations. + + A good way to use this function is to put it at the start of your main script + (eg ``boot.py`` or ``main.py``) and then the emergency exception buffer will be active + for all the code following it. + +.. CIRCUITPY-CHANGE: REMOVE .. function:: mem_info([verbose]) + + Print information about currently used memory. If the *verbose* argument + is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the amount of stack and heap used. In verbose mode it prints out + the entire heap indicating which blocks are used and which are free. + +.. CIRCUITPY-CHANGE: REMOVE .. function:: qstr_info([verbose]) + + Print information about currently interned strings. If the *verbose* + argument is given then extra information is printed. + + The information that is printed is implementation dependent, but currently + includes the number of interned strings and the amount of RAM they use. In + verbose mode it prints out the names of all RAM-interned strings. + +.. CIRCUITPY-CHANGE: REMOVE .. function:: stack_use() + + Return an integer representing the current amount of stack that is being + used. The absolute value of this is not particularly useful, rather it + should be used to compute differences in stack usage at different points. + +.. CIRCUITPY-CHANGE: REMOVE .. function:: heap_lock() +.. CIRCUITPY-CHANGE: REMOVE .. function:: heap_unlock() +.. CIRCUITPY-CHANGE: REMOVE .. function:: heap_locked() + + Lock or unlock the heap. When locked no memory allocation can occur and a + `builtins.MemoryError` will be raised if any heap allocation is attempted. + `heap_locked()` returns a true value if the heap is currently locked. + + These functions can be nested, ie `heap_lock()` can be called multiple times + in a row and the lock-depth will increase, and then `heap_unlock()` must be + called the same number of times to make the heap available again. + + Both `heap_unlock()` and `heap_locked()` return the current lock depth + (after unlocking for the former) as a non-negative integer, with 0 meaning + the heap is not locked. + + If the REPL becomes active with the heap locked then it will be forcefully + unlocked. + + Note: `heap_locked()` is not enabled on most ports by default, + requires ``MICROPY_PY_MICROPYTHON_HEAP_LOCKED``. + +.. CIRCUITPY-CHANGE: REMOVE .. function:: kbd_intr(chr) + + Set the character that will raise a `KeyboardInterrupt` exception. By + default this is set to 3 during script execution, corresponding to Ctrl-C. + Passing -1 to this function will disable capture of Ctrl-C, and passing 3 + will restore it. + + This function can be used to prevent the capturing of Ctrl-C on the + incoming stream of characters that is usually used for the REPL, in case + that stream is used for other purposes. + +.. CIRCUITPY-CHANGE: REMOVE .. function:: schedule(func, arg) + + Schedule the function *func* to be executed "very soon". The function + is passed the value *arg* as its single argument. "Very soon" means that + the MicroPython runtime will do its best to execute the function at the + earliest possible time, given that it is also trying to be efficient, and + that the following conditions hold: + + - A scheduled function will never preempt another scheduled function. + - Scheduled functions are always executed "between opcodes" which means + that all fundamental Python operations (such as appending to a list) + are guaranteed to be atomic. + - A given port may define "critical regions" within which scheduled + functions will never be executed. Functions may be scheduled within + a critical region but they will not be executed until that region + is exited. An example of a critical region is a preempting interrupt + handler (an IRQ). + + A use for this function is to schedule a callback from a preempting IRQ. + Such an IRQ puts restrictions on the code that runs in the IRQ (for example + the heap may be locked) and scheduling a function to call later will lift + those restrictions. + + On multi-threaded ports, the scheduled function's behaviour depends on + whether the Global Interpreter Lock (GIL) is enabled for the specific port: + + - If GIL is enabled, the function can preempt any thread and run in its + context. + - If GIL is disabled, the function will only preempt the main thread and run + in its context. + + Note: If `schedule()` is called from a preempting IRQ, when memory + allocation is not allowed and the callback to be passed to `schedule()` is + a bound method, passing this directly will fail. This is because creating a + reference to a bound method causes memory allocation. A solution is to + create a reference to the method in the class constructor and to pass that + reference to `schedule()`. This is discussed in detail here + :ref:`reference documentation ` under "Creation of Python + objects". + + There is a finite queue to hold the scheduled functions and `schedule()` + will raise a `RuntimeError` if the queue is full. diff --git a/examples/natmod/.gitignore b/examples/natmod/.gitignore deleted file mode 100644 index 4815d20f06be7..0000000000000 --- a/examples/natmod/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.mpy diff --git a/examples/natmod/README.md b/examples/natmod/README.md deleted file mode 100644 index 0cc4010ef42f3..0000000000000 --- a/examples/natmod/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# Dynamic Native Modules - -Dynamic Native Modules are .mpy files that contain native machine code from a -language other than Python. For more info see [the documentation] -(https://docs.micropython.org/en/latest/develop/natmod.html). - -This should not be confused with [User C Modules] -(https://docs.micropython.org/en/latest/develop/cmodules.html) which are a -mechanism to add additional out-of-tree modules into the firmware build. - -## Examples - -This directory contains several examples of writing dynamic native modules, in -two main categories: - -1. Feature examples. - - * `features0` - A module containing a single "factorial" function which - demonstrates working with integers. - - * `features1` - A module that demonstrates some common tasks: - - defining simple functions exposed to Python - - defining local, helper C functions - - defining constant integers and strings exposed to Python - - getting and creating integer objects - - creating Python lists - - raising exceptions - - allocating memory - - BSS and constant data (rodata) - - relocated pointers in rodata - - * `features2` - This is a hybrid module containing both Python and C code, - and additionally the C code is spread over multiple files. It also - demonstrates using floating point (only when the target supports - hardware floating point). - - * `features3` - A module that shows how to use types, constant objects, - and creating dictionary instances. - - * `features4` - A module that demonstrates how to define a class. - -2. Dynamic version of existing built-ins. - - This provides a way to add missing functionality to firmware that doesn't - include certain built-in modules. See the `heapq`, `random`, `re`, - `deflate`, `btree`, and `framebuf` directories. - - So for example, if your firmware was compiled with `MICROPY_PY_FRAMEBUF` - disabled (e.g. to save flash space), then it would not include the - `framebuf` module. The `framebuf` native module provides a way to add the - `framebuf` module dynamically. - - The way these work is they define a dynamic native module which - `#include`'s the original module and then does the necessary - initialisation of the module's globals dict. - -## Build instructions - -To compile an example, you need to have the same toolchain available as -required for your target port. e.g. `arm-none-eabi-gcc` for any ARM Cortex M -target. See the port instructions for details. - -You also need to have the `pyelftools` Python package available, either via -your system package manager or installed from PyPI in a virtual environment -with `pip`. - -Each example provides a Makefile. You should specify the `ARCH` argument to -make (one of x86, x64, armv6m, armv7m, xtensa, xtensawin): - -``` -$ cd features0 -$ make ARCH=armv7m -$ mpremote cp features0.mpy : -``` diff --git a/examples/natmod/deflate/Makefile b/examples/natmod/deflate/Makefile deleted file mode 100644 index 86ef29b6324b3..0000000000000 --- a/examples/natmod/deflate/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Location of top-level MicroPython directory -MPY_DIR = ../../.. - -# Name of module (different to built-in uzlib so it can coexist) -MOD = deflate_$(ARCH) - -# Source files (.c or .py) -SRC = deflate.c - -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) -ARCH = x64 - -include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/deflate/deflate.c b/examples/natmod/deflate/deflate.c deleted file mode 100644 index 9de7e101a7689..0000000000000 --- a/examples/natmod/deflate/deflate.c +++ /dev/null @@ -1,70 +0,0 @@ -#define MICROPY_PY_DEFLATE (1) -#define MICROPY_PY_DEFLATE_COMPRESS (1) - -#include "py/dynruntime.h" - -#if !defined(__linux__) -void *memcpy(void *dst, const void *src, size_t n) { - return mp_fun_table.memmove_(dst, src, n); -} -void *memset(void *s, int c, size_t n) { - return mp_fun_table.memset_(s, c, n); -} -#endif - -mp_obj_full_type_t deflateio_type; - -#include "extmod/moddeflate.c" - -// Re-implemented from py/stream.c, not yet available in dynruntime.h. -mp_obj_t mp_stream_close(mp_obj_t stream) { - const mp_stream_p_t *stream_p = mp_get_stream(stream); - int error; - mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error); - if (res == MP_STREAM_ERROR) { - mp_raise_OSError(error); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_close_obj, mp_stream_close); - -// Re-implemented from py/stream.c, not yet available in dynruntime.h. -static mp_obj_t mp_stream___exit__(size_t n_args, const mp_obj_t *args) { - (void)n_args; - return mp_stream_close(args[0]); -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream___exit___obj, 4, 4, mp_stream___exit__); - -// Re-implemented from obj.c, not yet available in dynruntime.h. -mp_obj_t mp_identity(mp_obj_t self) { - return self; -} -MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity); - -mp_map_elem_t deflateio_locals_dict_table[7]; -static MP_DEFINE_CONST_DICT(deflateio_locals_dict, deflateio_locals_dict_table); - -mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { - MP_DYNRUNTIME_INIT_ENTRY - - deflateio_type.base.type = mp_fun_table.type_type; - deflateio_type.name = MP_QSTR_DeflateIO; - MP_OBJ_TYPE_SET_SLOT(&deflateio_type, make_new, &deflateio_make_new, 0); - MP_OBJ_TYPE_SET_SLOT(&deflateio_type, protocol, &deflateio_stream_p, 1); - deflateio_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_OBJ_FROM_PTR(&mp_stream_read_obj) }; - deflateio_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_OBJ_FROM_PTR(&mp_stream_readinto_obj) }; - deflateio_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_OBJ_FROM_PTR(&mp_stream_unbuffered_readline_obj) }; - deflateio_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_OBJ_FROM_PTR(&mp_stream_write_obj) }; - deflateio_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_close), MP_OBJ_FROM_PTR(&mp_stream_close_obj) }; - deflateio_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR___enter__), MP_OBJ_FROM_PTR(&mp_identity_obj) }; - deflateio_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR___exit__), MP_OBJ_FROM_PTR(&mp_stream___exit___obj) }; - MP_OBJ_TYPE_SET_SLOT(&deflateio_type, locals_dict, (void*)&deflateio_locals_dict, 2); - - mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_deflate)); - mp_store_global(MP_QSTR_DeflateIO, MP_OBJ_FROM_PTR(&deflateio_type)); - mp_store_global(MP_QSTR_RAW, MP_OBJ_NEW_SMALL_INT(DEFLATEIO_FORMAT_RAW)); - mp_store_global(MP_QSTR_ZLIB, MP_OBJ_NEW_SMALL_INT(DEFLATEIO_FORMAT_ZLIB)); - mp_store_global(MP_QSTR_GZIP, MP_OBJ_NEW_SMALL_INT(DEFLATEIO_FORMAT_GZIP)); - - MP_DYNRUNTIME_INIT_EXIT -} diff --git a/examples/natmod/features0/Makefile b/examples/natmod/features0/Makefile deleted file mode 100644 index 57490df90abe7..0000000000000 --- a/examples/natmod/features0/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# Location of top-level MicroPython directory -MPY_DIR = ../../.. - -# Name of module -MOD = features0 - -# Source files (.c or .py) -SRC = features0.c - -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) -ARCH = x64 - -# Include to get the rules for compiling and linking the module -include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features0/features0.c b/examples/natmod/features0/features0.c deleted file mode 100644 index c3d31afb79cb8..0000000000000 --- a/examples/natmod/features0/features0.c +++ /dev/null @@ -1,40 +0,0 @@ -/* This example demonstrates the following features in a native module: - - defining a simple function exposed to Python - - defining a local, helper C function - - getting and creating integer objects -*/ - -// Include the header file to get access to the MicroPython API -#include "py/dynruntime.h" - -// Helper function to compute factorial -static mp_int_t factorial_helper(mp_int_t x) { - if (x == 0) { - return 1; - } - return x * factorial_helper(x - 1); -} - -// This is the function which will be called from Python, as factorial(x) -static mp_obj_t factorial(mp_obj_t x_obj) { - // Extract the integer from the MicroPython input object - mp_int_t x = mp_obj_get_int(x_obj); - // Calculate the factorial - mp_int_t result = factorial_helper(x); - // Convert the result to a MicroPython integer object and return it - return mp_obj_new_int(result); -} -// Define a Python reference to the function above -static MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial); - -// This is the entry point and is called when the module is imported -mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { - // This must be first, it sets up the globals dict and other things - MP_DYNRUNTIME_INIT_ENTRY - - // Make the function available in the module's namespace - mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj)); - - // This must be last, it restores the globals dict - MP_DYNRUNTIME_INIT_EXIT -} diff --git a/examples/natmod/features1/Makefile b/examples/natmod/features1/Makefile deleted file mode 100644 index 010640daf9746..0000000000000 --- a/examples/natmod/features1/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# Location of top-level MicroPython directory -MPY_DIR = ../../.. - -# Name of module -MOD = features1 - -# Source files (.c or .py) -SRC = features1.c - -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) -ARCH = x64 - -# Include to get the rules for compiling and linking the module -include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features1/features1.c b/examples/natmod/features1/features1.c deleted file mode 100644 index 92b96dbb18351..0000000000000 --- a/examples/natmod/features1/features1.c +++ /dev/null @@ -1,106 +0,0 @@ -/* This example demonstrates the following features in a native module: - - defining simple functions exposed to Python - - defining local, helper C functions - - defining constant integers and strings exposed to Python - - getting and creating integer objects - - creating Python lists - - raising exceptions - - allocating memory - - BSS and constant data (rodata) - - relocated pointers in rodata -*/ - -// Include the header file to get access to the MicroPython API -#include "py/dynruntime.h" - -// BSS (zero) data -uint16_t data16[4]; - -// Constant data (rodata) -const uint8_t table8[] = { 0, 1, 1, 2, 3, 5, 8, 13 }; -const uint16_t table16[] = { 0x1000, 0x2000 }; - -// Constant data pointing to BSS/constant data -uint16_t *const table_ptr16a[] = { &data16[0], &data16[1], &data16[2], &data16[3] }; -const uint16_t *const table_ptr16b[] = { &table16[0], &table16[1] }; - -// A simple function that adds its 2 arguments (must be integers) -static mp_obj_t add(mp_obj_t x_in, mp_obj_t y_in) { - mp_int_t x = mp_obj_get_int(x_in); - mp_int_t y = mp_obj_get_int(y_in); - return mp_obj_new_int(x + y); -} -static MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add); - -// A local helper function (not exposed to Python) -static mp_int_t fibonacci_helper(mp_int_t x) { - if (x < MP_ARRAY_SIZE(table8)) { - return table8[x]; - } else { - return fibonacci_helper(x - 1) + fibonacci_helper(x - 2); - } -} - -// A function which computes Fibonacci numbers -static mp_obj_t fibonacci(mp_obj_t x_in) { - mp_int_t x = mp_obj_get_int(x_in); - if (x < 0) { - mp_raise_ValueError(MP_ERROR_TEXT("can't compute negative Fibonacci number")); - } - return mp_obj_new_int(fibonacci_helper(x)); -} -static MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci); - -// A function that accesses the BSS data -static mp_obj_t access(size_t n_args, const mp_obj_t *args) { - if (n_args == 0) { - // Create a list holding all items from data16 - mp_obj_list_t *lst = MP_OBJ_TO_PTR(mp_obj_new_list(MP_ARRAY_SIZE(data16), NULL)); - for (int i = 0; i < MP_ARRAY_SIZE(data16); ++i) { - lst->items[i] = mp_obj_new_int(data16[i]); - } - return MP_OBJ_FROM_PTR(lst); - } else if (n_args == 1) { - // Get one item from data16 - mp_int_t idx = mp_obj_get_int(args[0]) & 3; - return mp_obj_new_int(data16[idx]); - } else { - // Set one item in data16 (via table_ptr16a) - mp_int_t idx = mp_obj_get_int(args[0]) & 3; - *table_ptr16a[idx] = mp_obj_get_int(args[1]); - return mp_const_none; - } -} -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(access_obj, 0, 2, access); - -// A function that allocates memory and creates a bytearray -static mp_obj_t make_array(void) { - uint16_t *ptr = m_new(uint16_t, MP_ARRAY_SIZE(table_ptr16b)); - for (int i = 0; i < MP_ARRAY_SIZE(table_ptr16b); ++i) { - ptr[i] = *table_ptr16b[i]; - } - return mp_obj_new_bytearray_by_ref(sizeof(uint16_t) * MP_ARRAY_SIZE(table_ptr16b), ptr); -} -static MP_DEFINE_CONST_FUN_OBJ_0(make_array_obj, make_array); - -// This is the entry point and is called when the module is imported -mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { - // This must be first, it sets up the globals dict and other things - MP_DYNRUNTIME_INIT_ENTRY - - // Messages can be printed as usual - mp_printf(&mp_plat_print, "initialising module self=%p\n", self); - - // Make the functions available in the module's namespace - mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj)); - mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj)); - mp_store_global(MP_QSTR_access, MP_OBJ_FROM_PTR(&access_obj)); - mp_store_global(MP_QSTR_make_array, MP_OBJ_FROM_PTR(&make_array_obj)); - - // Add some constants to the module's namespace - mp_store_global(MP_QSTR_VAL, MP_OBJ_NEW_SMALL_INT(42)); - mp_store_global(MP_QSTR_MSG, MP_OBJ_NEW_QSTR(MP_QSTR_HELLO_MICROPYTHON)); - - // This must be last, it restores the globals dict - MP_DYNRUNTIME_INIT_EXIT -} diff --git a/examples/natmod/features2/Makefile b/examples/natmod/features2/Makefile deleted file mode 100644 index 4fd23c6879d47..0000000000000 --- a/examples/natmod/features2/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# Location of top-level MicroPython directory -MPY_DIR = ../../.. - -# Name of module -MOD = features2 - -# Source files (.c or .py) -SRC = main.c prod.c test.py - -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) -ARCH = x64 - -# Include to get the rules for compiling and linking the module -include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features2/main.c b/examples/natmod/features2/main.c deleted file mode 100644 index 22961aa494f5f..0000000000000 --- a/examples/natmod/features2/main.c +++ /dev/null @@ -1,83 +0,0 @@ -/* This example demonstrates the following features in a native module: - - using floats - - defining additional code in Python (see test.py) - - have extra C code in a separate file (see prod.c) -*/ - -// Include the header file to get access to the MicroPython API -#include "py/dynruntime.h" - -// Include the header for auxiliary C code for this module -#include "prod.h" - -// Automatically detect if this module should include double-precision code. -// If double precision is supported by the target architecture then it can -// be used in native module regardless of what float setting the target -// MicroPython runtime uses (being none, float or double). -#if defined(__i386__) || defined(__x86_64__) || (defined(__ARM_FP) && (__ARM_FP & 8)) -#define USE_DOUBLE 1 -#else -#define USE_DOUBLE 0 -#endif - -// A function that uses the default float type configured for the current target -// This default can be overridden by specifying MICROPY_FLOAT_IMPL at the make level -static mp_obj_t add(mp_obj_t x, mp_obj_t y) { - return mp_obj_new_float(mp_obj_get_float(x) + mp_obj_get_float(y)); -} -static MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add); - -// A function that explicitly uses single precision floats -static mp_obj_t add_f(mp_obj_t x, mp_obj_t y) { - return mp_obj_new_float_from_f(mp_obj_get_float_to_f(x) + mp_obj_get_float_to_f(y)); -} -static MP_DEFINE_CONST_FUN_OBJ_2(add_f_obj, add_f); - -#if USE_DOUBLE -// A function that explicitly uses double precision floats -static mp_obj_t add_d(mp_obj_t x, mp_obj_t y) { - return mp_obj_new_float_from_d(mp_obj_get_float_to_d(x) + mp_obj_get_float_to_d(y)); -} -static MP_DEFINE_CONST_FUN_OBJ_2(add_d_obj, add_d); -#endif - -// A function that computes the product of floats in an array. -// This function uses the most general C argument interface, which is more difficult -// to use but has access to the globals dict of the module via self->globals. -static mp_obj_t productf(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { - // Check number of arguments is valid - mp_arg_check_num(n_args, n_kw, 1, 1, false); - - // Extract buffer pointer and verify typecode - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_RW); - if (bufinfo.typecode != 'f') { - mp_raise_ValueError(MP_ERROR_TEXT("expecting float array")); - } - - // Compute product, store result back in first element of array - float *ptr = bufinfo.buf; - float prod = prod_array(bufinfo.len / sizeof(*ptr), ptr); - ptr[0] = prod; - - return mp_const_none; -} - -// This is the entry point and is called when the module is imported -mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { - // This must be first, it sets up the globals dict and other things - MP_DYNRUNTIME_INIT_ENTRY - - // Make the functions available in the module's namespace - mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj)); - mp_store_global(MP_QSTR_add_f, MP_OBJ_FROM_PTR(&add_f_obj)); - #if USE_DOUBLE - mp_store_global(MP_QSTR_add_d, MP_OBJ_FROM_PTR(&add_d_obj)); - #endif - - // The productf function uses the most general C argument interface - mp_store_global(MP_QSTR_productf, MP_DYNRUNTIME_MAKE_FUNCTION(productf)); - - // This must be last, it restores the globals dict - MP_DYNRUNTIME_INIT_EXIT -} diff --git a/examples/natmod/features2/prod.c b/examples/natmod/features2/prod.c deleted file mode 100644 index 7791dcad1d214..0000000000000 --- a/examples/natmod/features2/prod.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "prod.h" - -float prod_array(int n, float *ar) { - float ans = 1; - for (int i = 0; i < n; ++i) { - ans *= ar[i]; - } - return ans; -} diff --git a/examples/natmod/features2/prod.h b/examples/natmod/features2/prod.h deleted file mode 100644 index f27dd8d0330fe..0000000000000 --- a/examples/natmod/features2/prod.h +++ /dev/null @@ -1 +0,0 @@ -float prod_array(int n, float *ar); diff --git a/examples/natmod/features2/test.py b/examples/natmod/features2/test.py deleted file mode 100644 index af79b9692c216..0000000000000 --- a/examples/natmod/features2/test.py +++ /dev/null @@ -1,31 +0,0 @@ -# This Python code will be merged with the C code in main.c - -# ruff: noqa: F821 - this file is evaluated with C-defined names in scope - -import array - - -def isclose(a, b): - return abs(a - b) < 1e-3 - - -def test(): - tests = [ - isclose(add(0.1, 0.2), 0.3), - isclose(add_f(0.1, 0.2), 0.3), - ] - - ar = array.array("f", [1, 2, 3.5]) - productf(ar) - tests.append(isclose(ar[0], 7)) - - if "add_d" in globals(): - tests.append(isclose(add_d(0.1, 0.2), 0.3)) - - print(tests) - - if not all(tests): - raise SystemExit(1) - - -test() diff --git a/examples/natmod/features3/Makefile b/examples/natmod/features3/Makefile deleted file mode 100644 index 4a5f71b8f255b..0000000000000 --- a/examples/natmod/features3/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# Location of top-level MicroPython directory -MPY_DIR = ../../.. - -# Name of module -MOD = features3 - -# Source files (.c or .py) -SRC = features3.c - -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) -ARCH = x64 - -# Include to get the rules for compiling and linking the module -include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features3/features3.c b/examples/natmod/features3/features3.c deleted file mode 100644 index 1d3bc51e609d1..0000000000000 --- a/examples/natmod/features3/features3.c +++ /dev/null @@ -1,60 +0,0 @@ -/* This example demonstrates the following features in a native module: - - using types - - using constant objects - - creating dictionaries -*/ - -// Include the header file to get access to the MicroPython API. -#include "py/dynruntime.h" - -// A function that returns a tuple of object types. -static mp_obj_t get_types(void) { - return mp_obj_new_tuple(9, ((mp_obj_t []) { - MP_OBJ_FROM_PTR(&mp_type_type), - MP_OBJ_FROM_PTR(&mp_type_NoneType), - MP_OBJ_FROM_PTR(&mp_type_bool), - MP_OBJ_FROM_PTR(&mp_type_int), - MP_OBJ_FROM_PTR(&mp_type_str), - MP_OBJ_FROM_PTR(&mp_type_bytes), - MP_OBJ_FROM_PTR(&mp_type_tuple), - MP_OBJ_FROM_PTR(&mp_type_list), - MP_OBJ_FROM_PTR(&mp_type_dict), - })); -} -static MP_DEFINE_CONST_FUN_OBJ_0(get_types_obj, get_types); - -// A function that returns a tuple of constant objects. -static mp_obj_t get_const_objects(void) { - return mp_obj_new_tuple(5, ((mp_obj_t []) { - mp_const_none, - mp_const_false, - mp_const_true, - mp_const_empty_bytes, - mp_const_empty_tuple, - })); -} -static MP_DEFINE_CONST_FUN_OBJ_0(get_const_objects_obj, get_const_objects); - -// A function that creates a dictionary from the given arguments. -static mp_obj_t make_dict(size_t n_args, const mp_obj_t *args) { - mp_obj_t dict = mp_obj_new_dict(n_args / 2); - for (; n_args >= 2; n_args -= 2, args += 2) { - mp_obj_dict_store(dict, args[0], args[1]); - } - return dict; -} -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(make_dict_obj, 0, MP_OBJ_FUN_ARGS_MAX, make_dict); - -// This is the entry point and is called when the module is imported. -mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { - // This must be first, it sets up the globals dict and other things. - MP_DYNRUNTIME_INIT_ENTRY - - // Make the functions available in the module's namespace. - mp_store_global(MP_QSTR_make_dict, MP_OBJ_FROM_PTR(&make_dict_obj)); - mp_store_global(MP_QSTR_get_types, MP_OBJ_FROM_PTR(&get_types_obj)); - mp_store_global(MP_QSTR_get_const_objects, MP_OBJ_FROM_PTR(&get_const_objects_obj)); - - // This must be last, it restores the globals dict. - MP_DYNRUNTIME_INIT_EXIT -} diff --git a/examples/natmod/features4/Makefile b/examples/natmod/features4/Makefile deleted file mode 100644 index f76a31a7cc141..0000000000000 --- a/examples/natmod/features4/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# Location of top-level MicroPython directory -MPY_DIR = ../../.. - -# Name of module -MOD = features4 - -# Source files (.c or .py) -SRC = features4.c - -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) -ARCH = x64 - -# Include to get the rules for compiling and linking the module -include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features4/features4.c b/examples/natmod/features4/features4.c deleted file mode 100644 index e64c7f759213c..0000000000000 --- a/examples/natmod/features4/features4.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - This example extends on features0 but demonstrates how to define a class, - and a custom exception. - - The Factorial class constructor takes an integer, and then the calculate - method can be called to get the factorial. - - >>> import features4 - >>> f = features4.Factorial(4) - >>> f.calculate() - 24 - - If the argument to the Factorial class constructor is less than zero, a - FactorialError is raised. -*/ - -// Include the header file to get access to the MicroPython API -#include "py/dynruntime.h" - -// This is type(Factorial) -mp_obj_full_type_t mp_type_factorial; - -// This is the internal state of a Factorial instance. -typedef struct { - mp_obj_base_t base; - mp_int_t n; -} mp_obj_factorial_t; - -mp_obj_full_type_t mp_type_FactorialError; - -// Essentially Factorial.__new__ (but also kind of __init__). -// Takes a single argument (the number to find the factorial of) -static mp_obj_t factorial_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) { - mp_arg_check_num(n_args, n_kw, 1, 1, false); - - mp_obj_factorial_t *o = mp_obj_malloc(mp_obj_factorial_t, type); - o->n = mp_obj_get_int(args_in[0]); - - if (o->n < 0) { - mp_raise_msg((mp_obj_type_t *)&mp_type_FactorialError, "argument must be zero or above"); - } - - return MP_OBJ_FROM_PTR(o); -} - -static mp_int_t factorial_helper(mp_int_t x) { - if (x == 0) { - return 1; - } - return x * factorial_helper(x - 1); -} - -// Implements Factorial.calculate() -static mp_obj_t factorial_calculate(mp_obj_t self_in) { - mp_obj_factorial_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int(factorial_helper(self->n)); -} -static MP_DEFINE_CONST_FUN_OBJ_1(factorial_calculate_obj, factorial_calculate); - -// Locals dict for the Factorial type (will have a single method, calculate, -// added in mpy_init). -mp_map_elem_t factorial_locals_dict_table[1]; -static MP_DEFINE_CONST_DICT(factorial_locals_dict, factorial_locals_dict_table); - -// This is the entry point and is called when the module is imported -mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { - // This must be first, it sets up the globals dict and other things - MP_DYNRUNTIME_INIT_ENTRY - - // Initialise the type. - mp_type_factorial.base.type = (void*)&mp_type_type; - mp_type_factorial.flags = MP_TYPE_FLAG_NONE; - mp_type_factorial.name = MP_QSTR_Factorial; - MP_OBJ_TYPE_SET_SLOT(&mp_type_factorial, make_new, factorial_make_new, 0); - factorial_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_calculate), MP_OBJ_FROM_PTR(&factorial_calculate_obj) }; - MP_OBJ_TYPE_SET_SLOT(&mp_type_factorial, locals_dict, (void*)&factorial_locals_dict, 1); - - // Make the Factorial type available on the module. - mp_store_global(MP_QSTR_Factorial, MP_OBJ_FROM_PTR(&mp_type_factorial)); - - // Initialise the exception type. - mp_obj_exception_init(&mp_type_FactorialError, MP_QSTR_FactorialError, &mp_type_Exception); - - // Make the FactorialError type available on the module. - mp_store_global(MP_QSTR_FactorialError, MP_OBJ_FROM_PTR(&mp_type_FactorialError)); - - // This must be last, it restores the globals dict - MP_DYNRUNTIME_INIT_EXIT -} diff --git a/examples/natmod/heapq/Makefile b/examples/natmod/heapq/Makefile deleted file mode 100644 index af45b472da1ae..0000000000000 --- a/examples/natmod/heapq/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Location of top-level MicroPython directory -MPY_DIR = ../../.. - -# Name of module (different to built-in heapq so it can coexist) -MOD = heapq_$(ARCH) - -# Source files (.c or .py) -SRC = heapq.c - -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) -ARCH = x64 - -include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/heapq/heapq.c b/examples/natmod/heapq/heapq.c deleted file mode 100644 index ed19652a66b1d..0000000000000 --- a/examples/natmod/heapq/heapq.c +++ /dev/null @@ -1,16 +0,0 @@ -#define MICROPY_PY_HEAPQ (1) - -#include "py/dynruntime.h" - -#include "extmod/modheapq.c" - -mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { - MP_DYNRUNTIME_INIT_ENTRY - - mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_heapq)); - mp_store_global(MP_QSTR_heappush, MP_OBJ_FROM_PTR(&mod_heapq_heappush_obj)); - mp_store_global(MP_QSTR_heappop, MP_OBJ_FROM_PTR(&mod_heapq_heappop_obj)); - mp_store_global(MP_QSTR_heapify, MP_OBJ_FROM_PTR(&mod_heapq_heapify_obj)); - - MP_DYNRUNTIME_INIT_EXIT -} diff --git a/examples/natmod/random/Makefile b/examples/natmod/random/Makefile deleted file mode 100644 index 5c50227b15f9d..0000000000000 --- a/examples/natmod/random/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Location of top-level MicroPython directory -MPY_DIR = ../../.. - -# Name of module (different to built-in random so it can coexist) -MOD = random_$(ARCH) - -# Source files (.c or .py) -SRC = random.c - -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) -ARCH = x64 - -include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/random/random.c b/examples/natmod/random/random.c deleted file mode 100644 index 92257b8bc6811..0000000000000 --- a/examples/natmod/random/random.c +++ /dev/null @@ -1,33 +0,0 @@ -#define MICROPY_PY_RANDOM (1) -#define MICROPY_PY_RANDOM_EXTRA_FUNCS (1) - -#include "py/dynruntime.h" - -// Dynamic native modules don't support a data section so these must go in the BSS -uint32_t yasmarang_pad, yasmarang_n, yasmarang_d; -uint8_t yasmarang_dat; - -#include "extmod/modrandom.c" - -mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { - MP_DYNRUNTIME_INIT_ENTRY - - yasmarang_pad = 0xeda4baba; - yasmarang_n = 69; - yasmarang_d = 233; - - mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_random)); - mp_store_global(MP_QSTR_getrandbits, MP_OBJ_FROM_PTR(&mod_random_getrandbits_obj)); - mp_store_global(MP_QSTR_seed, MP_OBJ_FROM_PTR(&mod_random_seed_obj)); - #if MICROPY_PY_RANDOM_EXTRA_FUNCS - mp_store_global(MP_QSTR_randrange, MP_OBJ_FROM_PTR(&mod_random_randrange_obj)); - mp_store_global(MP_QSTR_randint, MP_OBJ_FROM_PTR(&mod_random_randint_obj)); - mp_store_global(MP_QSTR_choice, MP_OBJ_FROM_PTR(&mod_random_choice_obj)); - #if MICROPY_PY_BUILTINS_FLOAT - mp_store_global(MP_QSTR_random, MP_OBJ_FROM_PTR(&mod_random_random_obj)); - mp_store_global(MP_QSTR_uniform, MP_OBJ_FROM_PTR(&mod_random_uniform_obj)); - #endif - #endif - - MP_DYNRUNTIME_INIT_EXIT -} diff --git a/examples/natmod/re/Makefile b/examples/natmod/re/Makefile deleted file mode 100644 index 1ba540110650d..0000000000000 --- a/examples/natmod/re/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Location of top-level MicroPython directory -MPY_DIR = ../../.. - -# Name of module (different to built-in re so it can coexist) -MOD = re_$(ARCH) - -# Source files (.c or .py) -SRC = re.c - -# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) -ARCH = x64 - -include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/re/re.c b/examples/natmod/re/re.c deleted file mode 100644 index 7ae72a578f4e3..0000000000000 --- a/examples/natmod/re/re.c +++ /dev/null @@ -1,78 +0,0 @@ -#define MICROPY_STACK_CHECK (1) -#define MICROPY_PY_RE (1) -#define MICROPY_PY_RE_MATCH_GROUPS (1) -#define MICROPY_PY_RE_MATCH_SPAN_START_END (1) -#define MICROPY_PY_RE_SUB (0) // requires vstr interface - -#include -#include "py/dynruntime.h" - -#define STACK_LIMIT (2048) - -const char *stack_top; - -void mp_stack_check(void) { - // Assumes descending stack on target - volatile char dummy; - if (stack_top - &dummy >= STACK_LIMIT) { - mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("maximum recursion depth exceeded")); - } -} - -#if !defined(__linux__) -void *memcpy(void *dst, const void *src, size_t n) { - return mp_fun_table.memmove_(dst, src, n); -} -void *memset(void *s, int c, size_t n) { - return mp_fun_table.memset_(s, c, n); -} -#endif - -void *memmove(void *dest, const void *src, size_t n) { - return mp_fun_table.memmove_(dest, src, n); -} - -mp_obj_full_type_t match_type; -mp_obj_full_type_t re_type; - -#include "extmod/modre.c" - -mp_map_elem_t match_locals_dict_table[5]; -static MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table); - -mp_map_elem_t re_locals_dict_table[3]; -static MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table); - -mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { - MP_DYNRUNTIME_INIT_ENTRY - - char dummy; - stack_top = &dummy; - - // Because MP_QSTR_start/end/split are static, xtensa and xtensawin will make a small data section - // to copy in this key/value pair if they are specified as a struct, so assign them separately. - - match_type.base.type = (void*)&mp_fun_table.type_type; - match_type.name = MP_QSTR_match; - MP_OBJ_TYPE_SET_SLOT(&match_type, print, match_print, 0); - match_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_group), MP_OBJ_FROM_PTR(&match_group_obj) }; - match_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_groups), MP_OBJ_FROM_PTR(&match_groups_obj) }; - match_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_span), MP_OBJ_FROM_PTR(&match_span_obj) }; - match_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_start), MP_OBJ_FROM_PTR(&match_start_obj) }; - match_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_OBJ_FROM_PTR(&match_end_obj) }; - MP_OBJ_TYPE_SET_SLOT(&match_type, locals_dict, (void*)&match_locals_dict, 1); - - re_type.base.type = (void*)&mp_fun_table.type_type; - re_type.name = MP_QSTR_re; - MP_OBJ_TYPE_SET_SLOT(&re_type, print, re_print, 0); - re_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_match), MP_OBJ_FROM_PTR(&re_match_obj) }; - re_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_search), MP_OBJ_FROM_PTR(&re_search_obj) }; - re_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_split), MP_OBJ_FROM_PTR(&re_split_obj) }; - MP_OBJ_TYPE_SET_SLOT(&re_type, locals_dict, (void*)&re_locals_dict, 1); - - mp_store_global(MP_QSTR_compile, MP_OBJ_FROM_PTR(&mod_re_compile_obj)); - mp_store_global(MP_QSTR_match, MP_OBJ_FROM_PTR(&re_match_obj)); - mp_store_global(MP_QSTR_search, MP_OBJ_FROM_PTR(&re_search_obj)); - - MP_DYNRUNTIME_INIT_EXIT -} diff --git a/examples/usercmodule/cexample/examplemodule.c b/examples/usercmodule/cexample/examplemodule.c deleted file mode 100644 index 2988fbd565f08..0000000000000 --- a/examples/usercmodule/cexample/examplemodule.c +++ /dev/null @@ -1,90 +0,0 @@ -// Include MicroPython API. -#include "py/runtime.h" - -// Used to get the time in the Timer class example. -#include "py/mphal.h" - -// This is the function which will be called from Python as cexample.add_ints(a, b). -static mp_obj_t example_add_ints(mp_obj_t a_obj, mp_obj_t b_obj) { - // Extract the ints from the micropython input objects. - int a = mp_obj_get_int(a_obj); - int b = mp_obj_get_int(b_obj); - - // Calculate the addition and convert to MicroPython object. - return mp_obj_new_int(a + b); -} -// Define a Python reference to the function above. -static MP_DEFINE_CONST_FUN_OBJ_2(example_add_ints_obj, example_add_ints); - -// This structure represents Timer instance objects. -typedef struct _example_Timer_obj_t { - // All objects start with the base. - mp_obj_base_t base; - // Everything below can be thought of as instance attributes, but they - // cannot be accessed by MicroPython code directly. In this example we - // store the time at which the object was created. - mp_uint_t start_time; -} example_Timer_obj_t; - -// This is the Timer.time() method. After creating a Timer object, this -// can be called to get the time elapsed since creating the Timer. -static mp_obj_t example_Timer_time(mp_obj_t self_in) { - // The first argument is self. It is cast to the *example_Timer_obj_t - // type so we can read its attributes. - example_Timer_obj_t *self = MP_OBJ_TO_PTR(self_in); - - // Get the elapsed time and return it as a MicroPython integer. - mp_uint_t elapsed = mp_hal_ticks_ms() - self->start_time; - return mp_obj_new_int_from_uint(elapsed); -} -static MP_DEFINE_CONST_FUN_OBJ_1(example_Timer_time_obj, example_Timer_time); - -// This represents Timer.__new__ and Timer.__init__, which is called when -// the user instantiates a Timer object. -static mp_obj_t example_Timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - // Allocates the new object and sets the type. - example_Timer_obj_t *self = mp_obj_malloc(example_Timer_obj_t, type); - - // Initializes the time for this Timer instance. - self->start_time = mp_hal_ticks_ms(); - - // The make_new function always returns self. - return MP_OBJ_FROM_PTR(self); -} - -// This collects all methods and other static class attributes of the Timer. -// The table structure is similar to the module table, as detailed below. -static const mp_rom_map_elem_t example_Timer_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&example_Timer_time_obj) }, -}; -static MP_DEFINE_CONST_DICT(example_Timer_locals_dict, example_Timer_locals_dict_table); - -// This defines the type(Timer) object. -MP_DEFINE_CONST_OBJ_TYPE( - example_type_Timer, - MP_QSTR_Timer, - MP_TYPE_FLAG_NONE, - make_new, example_Timer_make_new, - locals_dict, &example_Timer_locals_dict - ); - -// Define all attributes of the module. -// Table entries are key/value pairs of the attribute name (a string) -// and the MicroPython object reference. -// All identifiers and strings are written as MP_QSTR_xxx and will be -// optimized to word-sized integers by the build system (interned strings). -static const mp_rom_map_elem_t example_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cexample) }, - { MP_ROM_QSTR(MP_QSTR_add_ints), MP_ROM_PTR(&example_add_ints_obj) }, - { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&example_type_Timer) }, -}; -static MP_DEFINE_CONST_DICT(example_module_globals, example_module_globals_table); - -// Define module object. -const mp_obj_module_t example_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&example_module_globals, -}; - -// Register the module to make it available in Python. -MP_REGISTER_MODULE(MP_QSTR_cexample, example_user_cmodule); diff --git a/examples/usercmodule/cexample/micropython.cmake b/examples/usercmodule/cexample/micropython.cmake deleted file mode 100644 index ba076a16b246b..0000000000000 --- a/examples/usercmodule/cexample/micropython.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# Create an INTERFACE library for our C module. -add_library(usermod_cexample INTERFACE) - -# Add our source files to the lib -target_sources(usermod_cexample INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/examplemodule.c -) - -# Add the current directory as an include directory. -target_include_directories(usermod_cexample INTERFACE - ${CMAKE_CURRENT_LIST_DIR} -) - -# Link our INTERFACE library to the usermod target. -target_link_libraries(usermod INTERFACE usermod_cexample) diff --git a/examples/usercmodule/cexample/micropython.mk b/examples/usercmodule/cexample/micropython.mk deleted file mode 100644 index d6801dac0ba5b..0000000000000 --- a/examples/usercmodule/cexample/micropython.mk +++ /dev/null @@ -1,8 +0,0 @@ -CEXAMPLE_MOD_DIR := $(USERMOD_DIR) - -# Add all C files to SRC_USERMOD. -SRC_USERMOD += $(CEXAMPLE_MOD_DIR)/examplemodule.c - -# We can add our module folder to include paths if needed -# This is not actually needed in this example. -CFLAGS_USERMOD += -I$(CEXAMPLE_MOD_DIR) diff --git a/examples/usercmodule/cppexample/example.cpp b/examples/usercmodule/cppexample/example.cpp deleted file mode 100644 index 2df832baa76f5..0000000000000 --- a/examples/usercmodule/cppexample/example.cpp +++ /dev/null @@ -1,24 +0,0 @@ -extern "C" { -#include -#include - -// Here we implement the function using C++ code, but since it's -// declaration has to be compatible with C everything goes in extern "C" scope. -mp_obj_t cppfunc(mp_obj_t a_obj, mp_obj_t b_obj) { - // The following no-ops are just here to verify the static assertions used in - // the public API all compile with C++. - MP_STATIC_ASSERT_STR_ARRAY_COMPATIBLE; - if (mp_obj_is_type(a_obj, &mp_type_BaseException)) { - } - - // Prove we have (at least) C++11 features. - const auto a = mp_obj_get_int(a_obj); - const auto b = mp_obj_get_int(b_obj); - const auto sum = [&]() { - return mp_obj_new_int(a + b); - } (); - // Prove we're being scanned for QSTRs. - mp_obj_t tup[] = {sum, MP_ROM_QSTR(MP_QSTR_hellocpp)}; - return mp_obj_new_tuple(2, tup); -} -} diff --git a/examples/usercmodule/cppexample/examplemodule.c b/examples/usercmodule/cppexample/examplemodule.c deleted file mode 100644 index 5d4637b89782d..0000000000000 --- a/examples/usercmodule/cppexample/examplemodule.c +++ /dev/null @@ -1,25 +0,0 @@ -#include - -// Define a Python reference to the function we'll make available. -// See example.cpp for the definition. -static MP_DEFINE_CONST_FUN_OBJ_2(cppfunc_obj, cppfunc); - -// Define all attributes of the module. -// Table entries are key/value pairs of the attribute name (a string) -// and the MicroPython object reference. -// All identifiers and strings are written as MP_QSTR_xxx and will be -// optimized to word-sized integers by the build system (interned strings). -static const mp_rom_map_elem_t cppexample_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cppexample) }, - { MP_ROM_QSTR(MP_QSTR_cppfunc), MP_ROM_PTR(&cppfunc_obj) }, -}; -static MP_DEFINE_CONST_DICT(cppexample_module_globals, cppexample_module_globals_table); - -// Define module object. -const mp_obj_module_t cppexample_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&cppexample_module_globals, -}; - -// Register the module to make it available in Python. -MP_REGISTER_MODULE(MP_QSTR_cppexample, cppexample_user_cmodule); diff --git a/examples/usercmodule/cppexample/examplemodule.h b/examples/usercmodule/cppexample/examplemodule.h deleted file mode 100644 index d89384a630060..0000000000000 --- a/examples/usercmodule/cppexample/examplemodule.h +++ /dev/null @@ -1,5 +0,0 @@ -// Include MicroPython API. -#include "py/runtime.h" - -// Declare the function we'll make available in Python as cppexample.cppfunc(). -extern mp_obj_t cppfunc(mp_obj_t a_obj, mp_obj_t b_obj); diff --git a/examples/usercmodule/cppexample/micropython.cmake b/examples/usercmodule/cppexample/micropython.cmake deleted file mode 100644 index 6da972c94e3b5..0000000000000 --- a/examples/usercmodule/cppexample/micropython.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# Create an INTERFACE library for our CPP module. -add_library(usermod_cppexample INTERFACE) - -# Add our source files to the library. -target_sources(usermod_cppexample INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/example.cpp - ${CMAKE_CURRENT_LIST_DIR}/examplemodule.c -) - -# Add the current directory as an include directory. -target_include_directories(usermod_cppexample INTERFACE - ${CMAKE_CURRENT_LIST_DIR} -) - -# Link our INTERFACE library to the usermod target. -target_link_libraries(usermod INTERFACE usermod_cppexample) diff --git a/examples/usercmodule/cppexample/micropython.mk b/examples/usercmodule/cppexample/micropython.mk deleted file mode 100644 index 0071d4fcc72b6..0000000000000 --- a/examples/usercmodule/cppexample/micropython.mk +++ /dev/null @@ -1,12 +0,0 @@ -CPPEXAMPLE_MOD_DIR := $(USERMOD_DIR) - -# Add our source files to the respective variables. -SRC_USERMOD += $(CPPEXAMPLE_MOD_DIR)/examplemodule.c -SRC_USERMOD_CXX += $(CPPEXAMPLE_MOD_DIR)/example.cpp - -# Add our module directory to the include path. -CFLAGS_USERMOD += -I$(CPPEXAMPLE_MOD_DIR) -CXXFLAGS_USERMOD += -I$(CPPEXAMPLE_MOD_DIR) -std=c++11 - -# We use C++ features so have to link against the standard library. -LDFLAGS_USERMOD += -lstdc++ diff --git a/examples/usercmodule/micropython.cmake b/examples/usercmodule/micropython.cmake deleted file mode 100644 index b9802401fa9f7..0000000000000 --- a/examples/usercmodule/micropython.cmake +++ /dev/null @@ -1,10 +0,0 @@ -# This top-level micropython.cmake is responsible for listing -# the individual modules we want to include. -# Paths are absolute, and ${CMAKE_CURRENT_LIST_DIR} can be -# used to prefix subdirectories. - -# Add the C example. -include(${CMAKE_CURRENT_LIST_DIR}/cexample/micropython.cmake) - -# Add the CPP example. -include(${CMAKE_CURRENT_LIST_DIR}/cppexample/micropython.cmake) diff --git a/examples/usercmodule/subpackage/README.md b/examples/usercmodule/subpackage/README.md deleted file mode 100644 index c7f2ee53a2408..0000000000000 --- a/examples/usercmodule/subpackage/README.md +++ /dev/null @@ -1 +0,0 @@ -This is an example of a user C module that includes subpackages. diff --git a/examples/usercmodule/subpackage/micropython.cmake b/examples/usercmodule/subpackage/micropython.cmake deleted file mode 100644 index a51e7a80613d3..0000000000000 --- a/examples/usercmodule/subpackage/micropython.cmake +++ /dev/null @@ -1,19 +0,0 @@ -# Create an INTERFACE library for our C module. -add_library(usermod_subpackage_example INTERFACE) - -# Add our source files to the lib -target_sources(usermod_subpackage_example INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/examplemodule.c -) - -# Add the current directory as an include directory. -target_include_directories(usermod_subpackage_example INTERFACE - ${CMAKE_CURRENT_LIST_DIR} -) - -target_compile_definitions(usermod_subpackage_example INTERFACE - MICROPY_MODULE_BUILTIN_SUBPACKAGES=1 -) - -# Link our INTERFACE library to the usermod target. -target_link_libraries(usermod INTERFACE usermod_subpackage_example) diff --git a/examples/usercmodule/subpackage/micropython.mk b/examples/usercmodule/subpackage/micropython.mk deleted file mode 100644 index 99ebf13ec19ab..0000000000000 --- a/examples/usercmodule/subpackage/micropython.mk +++ /dev/null @@ -1,10 +0,0 @@ -SUBPACKAGE_EXAMPLE_MOD_DIR := $(USERMOD_DIR) - -# Add all C files to SRC_USERMOD. -SRC_USERMOD += $(SUBPACKAGE_EXAMPLE_MOD_DIR)/modexamplepackage.c - -# We can add our module folder to include paths if needed -# This is not actually needed in this example. -CFLAGS_USERMOD += -I$(SUBPACKAGE_EXAMPLE_MOD_DIR) -DMICROPY_MODULE_BUILTIN_SUBPACKAGES=1 - -QSTR_DEFS += $(SUBPACKAGE_EXAMPLE_MOD_DIR)/qstrdefsexamplepackage.h diff --git a/examples/usercmodule/subpackage/modexamplepackage.c b/examples/usercmodule/subpackage/modexamplepackage.c deleted file mode 100644 index d68d0528398c4..0000000000000 --- a/examples/usercmodule/subpackage/modexamplepackage.c +++ /dev/null @@ -1,84 +0,0 @@ -// Include MicroPython API. -#include "py/runtime.h" - -// Define example_package.foo.bar.f() -static mp_obj_t example_package_foo_bar_f(void) { - mp_printf(&mp_plat_print, "example_package.foo.bar.f\n"); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_0(example_package_foo_bar_f_obj, example_package_foo_bar_f); - -// Define all attributes of the second-level sub-package (example_package.foo.bar). -static const mp_rom_map_elem_t example_package_foo_bar_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package_dot_foo_dot_bar) }, - { MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_foo_bar_f_obj) }, -}; -static MP_DEFINE_CONST_DICT(example_package_foo_bar_globals, example_package_foo_bar_globals_table); - -// Define example_package.foo.bar module object. -const mp_obj_module_t example_package_foo_bar_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&example_package_foo_bar_globals, -}; - -// Define example_package.foo.f() -static mp_obj_t example_package_foo_f(void) { - mp_printf(&mp_plat_print, "example_package.foo.f\n"); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_0(example_package_foo_f_obj, example_package_foo_f); - -// Define all attributes of the first-level sub-package (example_package.foo). -static const mp_rom_map_elem_t example_package_foo_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package_dot_foo) }, - { MP_ROM_QSTR(MP_QSTR_bar), MP_ROM_PTR(&example_package_foo_bar_user_cmodule) }, - { MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_foo_f_obj) }, -}; -static MP_DEFINE_CONST_DICT(example_package_foo_globals, example_package_foo_globals_table); - -// Define example_package.foo module object. -const mp_obj_module_t example_package_foo_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&example_package_foo_globals, -}; - -// Define example_package.f() -static mp_obj_t example_package_f(void) { - mp_printf(&mp_plat_print, "example_package.f\n"); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_0(example_package_f_obj, example_package_f); - -static mp_obj_t example_package___init__(void) { - if (!MP_STATE_VM(example_package_initialised)) { - // __init__ for builtins is called each time the module is imported, - // so ensure that initialisation only happens once. - MP_STATE_VM(example_package_initialised) = true; - mp_printf(&mp_plat_print, "example_package.__init__\n"); - } - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_0(example_package___init___obj, example_package___init__); - -// The "initialised" state is stored on mp_state so that it is cleared on soft -// reset. -MP_REGISTER_ROOT_POINTER(int example_package_initialised); - -// Define all attributes of the top-level package (example_package). -static const mp_rom_map_elem_t example_package_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_example_package) }, - { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&example_package___init___obj) }, - { MP_ROM_QSTR(MP_QSTR_foo), MP_ROM_PTR(&example_package_foo_user_cmodule) }, - { MP_ROM_QSTR(MP_QSTR_f), MP_ROM_PTR(&example_package_f_obj) }, -}; -static MP_DEFINE_CONST_DICT(example_package_globals, example_package_globals_table); - -// Define module object. -const mp_obj_module_t example_package_user_cmodule = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&example_package_globals, -}; - -// Register the module to make it available in Python. -// Note: subpackages should not be registered with MP_REGISTER_MODULE. -MP_REGISTER_MODULE(MP_QSTR_example_package, example_package_user_cmodule); diff --git a/examples/usercmodule/subpackage/qstrdefsexamplepackage.h b/examples/usercmodule/subpackage/qstrdefsexamplepackage.h deleted file mode 100644 index 057ec5279d003..0000000000000 --- a/examples/usercmodule/subpackage/qstrdefsexamplepackage.h +++ /dev/null @@ -1,2 +0,0 @@ -Q(example_package.foo) -Q(example_package.foo.bar) diff --git a/extmod/extmod.mk b/extmod/extmod.mk index b81b44af37617..a64c1d20388ac 100644 --- a/extmod/extmod.mk +++ b/extmod/extmod.mk @@ -129,6 +129,7 @@ SRC_LIB_LIBM_DBL_SQRT_HW_C += lib/libm_dbl/thumb_vfp_sqrt.c # Too many warnings in libm_dbl, disable for now. $(BUILD)/lib/libm_dbl/%.o: CFLAGS += -Wno-double-promotion -Wno-float-conversion +$(BUILD)/lib/libm_dbl/__rem_pio2_large.o: CFLAGS += -Wno-maybe-uninitialized ################################################################################ # VFS FAT FS @@ -203,6 +204,10 @@ MBEDTLS_CONFIG_FILE ?= \"mbedtls/mbedtls_config_port.h\" GIT_SUBMODULES += $(MBEDTLS_DIR) CFLAGS_EXTMOD += -DMBEDTLS_CONFIG_FILE=$(MBEDTLS_CONFIG_FILE) CFLAGS_EXTMOD += -DMICROPY_SSL_MBEDTLS=1 -I$(TOP)/$(MBEDTLS_DIR)/include +ifeq ($(MICROPY_PY_SSL_ECDSA_SIGN_ALT),1) +CFLAGS_EXTMOD += -DMICROPY_PY_SSL_ECDSA_SIGN_ALT=1 +LDFLAGS_EXTMOD += -Wl,--wrap=mbedtls_ecdsa_write_signature +endif SRC_THIRDPARTY_C += lib/mbedtls_errors/mp_mbedtls_errors.c SRC_THIRDPARTY_C += $(addprefix $(MBEDTLS_DIR)/library/,\ aes.c \ @@ -294,6 +299,8 @@ $(BUILD)/$(LWIP_DIR)/core/ipv4/dhcp.o: CFLAGS += -Wno-address SRC_THIRDPARTY_C += shared/netutils/netutils.c SRC_THIRDPARTY_C += $(addprefix $(LWIP_DIR)/,\ apps/mdns/mdns.c \ + apps/mdns/mdns_domain.c \ + apps/mdns/mdns_out.c \ core/def.c \ core/dns.c \ core/inet_chksum.c \ @@ -311,6 +318,7 @@ SRC_THIRDPARTY_C += $(addprefix $(LWIP_DIR)/,\ core/tcp_out.c \ core/timeouts.c \ core/udp.c \ + core/ipv4/acd.c \ core/ipv4/autoip.c \ core/ipv4/dhcp.c \ core/ipv4/etharp.c \ @@ -329,6 +337,32 @@ SRC_THIRDPARTY_C += $(addprefix $(LWIP_DIR)/,\ core/ipv6/mld6.c \ core/ipv6/nd6.c \ netif/ethernet.c \ + netif/ppp/auth.c \ + netif/ppp/ccp.c \ + netif/ppp/chap-md5.c \ + netif/ppp/chap_ms.c \ + netif/ppp/chap-new.c \ + netif/ppp/demand.c \ + netif/ppp/eap.c \ + netif/ppp/ecp.c \ + netif/ppp/eui64.c \ + netif/ppp/fsm.c \ + netif/ppp/ipcp.c \ + netif/ppp/ipv6cp.c \ + netif/ppp/lcp.c \ + netif/ppp/magic.c \ + netif/ppp/mppe.c \ + netif/ppp/multilink.c \ + netif/ppp/polarssl/md5.c \ + netif/ppp/pppapi.c \ + netif/ppp/ppp.c \ + netif/ppp/pppcrypt.c \ + netif/ppp/pppoe.c \ + netif/ppp/pppol2tp.c \ + netif/ppp/pppos.c \ + netif/ppp/upap.c \ + netif/ppp/utils.c \ + netif/ppp/vj.c \ ) ifeq ($(MICROPY_PY_LWIP_LOOPBACK),1) CFLAGS_EXTMOD += -DLWIP_NETIF_LOOPBACK=1 @@ -489,6 +523,7 @@ ifeq ($(MICROPY_PY_OPENAMP),1) OPENAMP_DIR = lib/open-amp LIBMETAL_DIR = lib/libmetal GIT_SUBMODULES += $(LIBMETAL_DIR) $(OPENAMP_DIR) +MICROPY_PY_OPENAMP_MODE ?= 0 include $(TOP)/extmod/libmetal/libmetal.mk INC += -I$(TOP)/$(OPENAMP_DIR) @@ -498,12 +533,21 @@ ifeq ($(MICROPY_PY_OPENAMP_REMOTEPROC),1) CFLAGS += -DMICROPY_PY_OPENAMP_REMOTEPROC=1 endif +ifeq ($(MICROPY_PY_OPENAMP_MODE),0) +CFLAGS += -DMICROPY_PY_OPENAMP_HOST=1 +CFLAGS_THIRDPARTY += -DVIRTIO_DRIVER_ONLY +else ifeq ($(MICROPY_PY_OPENAMP_MODE),1) +CFLAGS += -DMICROPY_PY_OPENAMP_DEVICE=1 +CFLAGS_THIRDPARTY += -DVIRTIO_DEVICE_ONLY +else +$(error Invalid Open-AMP mode specified: $(MICROPY_PY_OPENAMP_MODE)) +endif + CFLAGS_THIRDPARTY += \ -I$(BUILD)/openamp \ -I$(TOP)/$(OPENAMP_DIR) \ -I$(TOP)/$(OPENAMP_DIR)/lib/include/ \ -DMETAL_INTERNAL \ - -DVIRTIO_DRIVER_ONLY \ -DNO_ATOMIC_64_SUPPORT \ -DRPMSG_BUFFER_SIZE=512 \ diff --git a/extmod/modasyncio.c b/extmod/modasyncio.c index b0af32f70f217..f73d32baf6dbc 100644 --- a/extmod/modasyncio.c +++ b/extmod/modasyncio.c @@ -58,6 +58,9 @@ typedef struct _mp_obj_task_t { typedef struct _mp_obj_task_queue_t { mp_obj_base_t base; mp_obj_task_t *heap; + #if MICROPY_PY_ASYNCIO_TASK_QUEUE_PUSH_CALLBACK + mp_obj_t push_callback; + #endif } mp_obj_task_queue_t; static const mp_obj_type_t task_queue_type; @@ -105,9 +108,16 @@ static int task_lt(mp_pairheap_t *n1, mp_pairheap_t *n2) { static mp_obj_t task_queue_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)args; - mp_arg_check_num(n_args, n_kw, 0, 0, false); + mp_arg_check_num(n_args, n_kw, 0, MICROPY_PY_ASYNCIO_TASK_QUEUE_PUSH_CALLBACK ? 1 : 0, false); mp_obj_task_queue_t *self = mp_obj_malloc(mp_obj_task_queue_t, type); self->heap = (mp_obj_task_t *)mp_pairheap_new(task_lt); + #if MICROPY_PY_ASYNCIO_TASK_QUEUE_PUSH_CALLBACK + if (n_args == 1) { + self->push_callback = args[0]; + } else { + self->push_callback = MP_OBJ_NULL; + } + #endif return MP_OBJ_FROM_PTR(self); } @@ -132,6 +142,11 @@ static mp_obj_t task_queue_push(size_t n_args, const mp_obj_t *args) { task->ph_key = args[2]; } self->heap = (mp_obj_task_t *)mp_pairheap_push(task_lt, TASK_PAIRHEAP(self->heap), TASK_PAIRHEAP(task)); + #if MICROPY_PY_ASYNCIO_TASK_QUEUE_PUSH_CALLBACK + if (self->push_callback != MP_OBJ_NULL) { + mp_call_function_1(self->push_callback, MP_OBJ_NEW_SMALL_INT(0)); + } + #endif return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(task_queue_push_obj, 2, 3, task_queue_push); diff --git a/extmod/modos.c b/extmod/modos.c index 7f1e31fba7793..e7f7fc818cf08 100644 --- a/extmod/modos.c +++ b/extmod/modos.c @@ -153,9 +153,6 @@ static const mp_rom_map_elem_t os_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_putenv), MP_ROM_PTR(&mp_os_putenv_obj) }, { MP_ROM_QSTR(MP_QSTR_unsetenv), MP_ROM_PTR(&mp_os_unsetenv_obj) }, #endif - #if MICROPY_PY_OS_SEP - { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) }, - #endif #if MICROPY_PY_OS_SYNC { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&mp_os_sync_obj) }, #endif @@ -170,6 +167,7 @@ static const mp_rom_map_elem_t os_module_globals_table[] = { #endif #if MICROPY_VFS + { MP_ROM_QSTR(MP_QSTR_sep), MP_ROM_QSTR(MP_QSTR__slash_) }, { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&mp_vfs_chdir_obj) }, { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&mp_vfs_getcwd_obj) }, { MP_ROM_QSTR(MP_QSTR_listdir), MP_ROM_PTR(&mp_vfs_listdir_obj) }, diff --git a/extmod/modplatform.h b/extmod/modplatform.h index 56a50e53c5445..b932551c7ccb2 100644 --- a/extmod/modplatform.h +++ b/extmod/modplatform.h @@ -83,6 +83,9 @@ #elif defined(__NEWLIB__) #define MICROPY_PLATFORM_LIBC_LIB "newlib" #define MICROPY_PLATFORM_LIBC_VER _NEWLIB_VERSION +#elif defined(_PICOLIBC__) +#define MICROPY_PLATFORM_LIBC_LIB "picolibc" +#define MICROPY_PLATFORM_LIBC_VER _PICOLIBC_VERSION #else #define MICROPY_PLATFORM_LIBC_LIB "" #define MICROPY_PLATFORM_LIBC_VER "" diff --git a/extmod/modre.c b/extmod/modre.c index a7e784a6ac966..ba2927eb4a8a6 100644 --- a/extmod/modre.c +++ b/extmod/modre.c @@ -31,7 +31,7 @@ #include "py/runtime.h" #include "py/binary.h" #include "py/objstr.h" -#include "py/stackctrl.h" +#include "py/cstack.h" #if MICROPY_PY_BUILTINS_STR_UNICODE #include "py/unicode.h" @@ -39,7 +39,7 @@ #if MICROPY_PY_RE -#define re1_5_stack_chk() MP_STACK_CHECK() +#define re1_5_stack_chk() mp_cstack_check() #include "lib/re1.5/re1.5.h" @@ -194,7 +194,8 @@ static void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t mp_printf(print, "", self); } -static mp_obj_t re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) { +// Note: this function can't be named re_exec because it may clash with system headers, eg on FreeBSD +static mp_obj_t re_exec_helper(bool is_anchored, uint n_args, const mp_obj_t *args) { (void)n_args; mp_obj_re_t *self; if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) { @@ -254,12 +255,12 @@ static mp_obj_t re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) { } static mp_obj_t re_match(size_t n_args, const mp_obj_t *args) { - return re_exec(true, n_args, args); + return re_exec_helper(true, n_args, args); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_match_obj, 2, 4, re_match); static mp_obj_t re_search(size_t n_args, const mp_obj_t *args) { - return re_exec(false, n_args, args); + return re_exec_helper(false, n_args, args); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_search_obj, 2, 4, re_search); diff --git a/extmod/vfs.c b/extmod/vfs.c index 4deb8a4428e8b..3d44f623703c2 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -149,7 +149,7 @@ mp_import_stat_t mp_vfs_import_stat(const char *path) { } // delegate to vfs.stat() method - mp_obj_t path_o = mp_obj_new_str(path_out, strlen(path_out)); + mp_obj_t path_o = mp_obj_new_str_from_cstr(path_out); mp_obj_t stat; nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { @@ -283,7 +283,7 @@ mp_obj_t mp_vfs_umount(mp_obj_t mnt_in) { mnt_str = mp_obj_str_get_data(mnt_in, &mnt_len); } for (mp_vfs_mount_t **vfsp = &MP_STATE_VM(vfs_mount_table); *vfsp != NULL; vfsp = &(*vfsp)->next) { - if ((mnt_str != NULL && !memcmp(mnt_str, (*vfsp)->str, mnt_len + 1)) || (*vfsp)->obj == mnt_in) { + if ((mnt_str != NULL && mnt_len == (*vfsp)->len && !memcmp(mnt_str, (*vfsp)->str, mnt_len)) || (*vfsp)->obj == mnt_in) { vfs = *vfsp; *vfsp = (*vfsp)->next; break; diff --git a/extmod/vfs_blockdev.c b/extmod/vfs_blockdev.c index eda5cecc147a9..f1187b9bbf2f5 100644 --- a/extmod/vfs_blockdev.c +++ b/extmod/vfs_blockdev.c @@ -76,6 +76,34 @@ void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev) { } } +// Helper function to minimise code size of read/write functions +// note the n_args argument is moved to the end for further code size reduction (args keep same position in caller and callee). +static int mp_vfs_blockdev_call_rw(mp_obj_t *args, size_t block_num, size_t block_off, size_t len, void *buf, size_t n_args) { + mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, len, buf}; + args[2] = MP_OBJ_NEW_SMALL_INT(block_num); + args[3] = MP_OBJ_FROM_PTR(&ar); + args[4] = MP_OBJ_NEW_SMALL_INT(block_off); // ignored for n_args == 2 + mp_obj_t ret = mp_call_method_n_kw(n_args, 0, args); + + if (ret == mp_const_none) { + return 0; + } else { + // Some block devices return a bool indicating success, so + // convert those to an errno integer code. + if (ret == mp_const_true) { + return 0; + } else if (ret == mp_const_false) { + return -MP_EIO; + } + // Block device functions are expected to return 0 on success + // and negative integer on errors. Check for positive integer + // results as some callers (i.e. littlefs) will produce corrupt + // results from these. + int i = MP_OBJ_SMALL_INT_VALUE(ret); + return i > 0 ? (-MP_EINVAL) : i; + } +} + int mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, uint8_t *buf) { if (self->flags & MP_BLOCKDEV_FLAG_NATIVE) { // CIRCUITPY-CHANGE: Pass the blockdev object into native readblocks so @@ -83,26 +111,12 @@ int mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_b mp_uint_t (*f)(mp_obj_t self, uint8_t *, uint32_t, uint32_t) = (void *)(uintptr_t)self->readblocks[2]; return f(self->readblocks[1], buf, block_num, num_blocks); } else { - mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, num_blocks *self->block_size, buf}; - self->readblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num); - self->readblocks[3] = MP_OBJ_FROM_PTR(&ar); - mp_call_method_n_kw(2, 0, self->readblocks); - // TODO handle error return - return 0; + return mp_vfs_blockdev_call_rw(self->readblocks, block_num, 0, num_blocks * self->block_size, buf, 2); } } int mp_vfs_blockdev_read_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t block_off, size_t len, uint8_t *buf) { - mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, len, buf}; - self->readblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num); - self->readblocks[3] = MP_OBJ_FROM_PTR(&ar); - self->readblocks[4] = MP_OBJ_NEW_SMALL_INT(block_off); - mp_obj_t ret = mp_call_method_n_kw(3, 0, self->readblocks); - if (ret == mp_const_none) { - return 0; - } else { - return MP_OBJ_SMALL_INT_VALUE(ret); - } + return mp_vfs_blockdev_call_rw(self->readblocks, block_num, block_off, len, buf, 3); } int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, const uint8_t *buf) { @@ -117,12 +131,7 @@ int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_ mp_uint_t (*f)(mp_obj_t self, const uint8_t *, uint32_t, uint32_t) = (void *)(uintptr_t)self->writeblocks[2]; return f(self->writeblocks[1], buf, block_num, num_blocks); } else { - mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, num_blocks *self->block_size, (void *)buf}; - self->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num); - self->writeblocks[3] = MP_OBJ_FROM_PTR(&ar); - mp_call_method_n_kw(2, 0, self->writeblocks); - // TODO handle error return - return 0; + return mp_vfs_blockdev_call_rw(self->writeblocks, block_num, 0, num_blocks * self->block_size, (void *)buf, 2); } } @@ -131,17 +140,7 @@ int mp_vfs_blockdev_write_ext(mp_vfs_blockdev_t *self, size_t block_num, size_t // read-only block device return -MP_EROFS; } - - mp_obj_array_t ar = {{&mp_type_bytearray}, BYTEARRAY_TYPECODE, 0, len, (void *)buf}; - self->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(block_num); - self->writeblocks[3] = MP_OBJ_FROM_PTR(&ar); - self->writeblocks[4] = MP_OBJ_NEW_SMALL_INT(block_off); - mp_obj_t ret = mp_call_method_n_kw(3, 0, self->writeblocks); - if (ret == mp_const_none) { - return 0; - } else { - return MP_OBJ_SMALL_INT_VALUE(ret); - } + return mp_vfs_blockdev_call_rw(self->writeblocks, block_num, block_off, len, (void *)buf, 3); } mp_obj_t mp_vfs_blockdev_ioctl(mp_vfs_blockdev_t *self, uintptr_t cmd, uintptr_t arg) { diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 154dfec13f1a7..5011a820af864 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -134,6 +134,11 @@ static mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { mp_raise_OSError_fresult(res); } + // set the filesystem label if it's configured + #ifdef MICROPY_HW_FLASH_FS_LABEL + f_setlabel(&vfs->fatfs, MICROPY_HW_FLASH_FS_LABEL); + #endif + return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_mkfs_fun_obj, fat_vfs_mkfs); @@ -164,7 +169,7 @@ static mp_obj_t mp_vfs_fat_ilistdir_it_iternext(mp_obj_t self_in) { // make 4-tuple with info about this entry mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL)); if (self->is_str) { - t->items[0] = mp_obj_new_str(fn, strlen(fn)); + t->items[0] = mp_obj_new_str_from_cstr(fn); } else { t->items[0] = mp_obj_new_bytes((const byte *)fn, strlen(fn)); } @@ -323,7 +328,7 @@ static mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) { // CIRCUITPY-CHANGE mp_raise_OSError_fresult(res); } - return mp_obj_new_str(buf, strlen(buf)); + return mp_obj_new_str_from_cstr(buf); } static MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd); diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c index 19da4417e6d00..4b10ca3aa597c 100644 --- a/extmod/vfs_lfsx.c +++ b/extmod/vfs_lfsx.c @@ -192,7 +192,7 @@ static mp_obj_t MP_VFS_LFSx(ilistdir_it_iternext)(mp_obj_t self_in) { // make 4-tuple with info about this entry mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL)); if (self->is_str) { - t->items[0] = mp_obj_new_str(info.name, strlen(info.name)); + t->items[0] = mp_obj_new_str_from_cstr(info.name); } else { t->items[0] = mp_obj_new_bytes((const byte *)info.name, strlen(info.name)); } diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c index ed4c06e36731e..bd9a6d84062cf 100644 --- a/extmod/vfs_posix.c +++ b/extmod/vfs_posix.c @@ -194,7 +194,7 @@ static mp_obj_t vfs_posix_getcwd(mp_obj_t self_in) { } #endif } - return mp_obj_new_str(ret, strlen(ret)); + return mp_obj_new_str_from_cstr(ret); } static MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_getcwd_obj, vfs_posix_getcwd); @@ -234,7 +234,7 @@ static mp_obj_t vfs_posix_ilistdir_it_iternext(mp_obj_t self_in) { mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); if (self->is_str) { - t->items[0] = mp_obj_new_str(fn, strlen(fn)); + t->items[0] = mp_obj_new_str_from_cstr(fn); } else { t->items[0] = mp_obj_new_bytes((const byte *)fn, strlen(fn)); } diff --git a/extmod/vfs_posix_file.c b/extmod/vfs_posix_file.c index bc06bc74db1cb..501550cb502c5 100644 --- a/extmod/vfs_posix_file.c +++ b/extmod/vfs_posix_file.c @@ -160,12 +160,27 @@ static mp_uint_t vfs_posix_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_ #if defined(__APPLE__) #define VFS_POSIX_STREAM_STDIO_ERR_CATCH (err == EINVAL || err == ENOTSUP) #elif defined(_MSC_VER) + // In debug builds fsync (i.e. _commit on windows) will generate a debug report via _ASSERTE when + // called with non-redirected stdin/stdout/stderr (i.e. _isatty) handles because FlushFileBuffers, + // which it calls internally, will fail since console output is not buffered. + // In release builds it also fails, but merely returns an error which is handled appropriately below. + // The check for the handle being stdin/stdout/stderr is added explicitly because according to + // the documentation _isatty is also true for serial ports for instance. + #ifdef _DEBUG + if ((o->fd == STDIN_FILENO || o->fd == STDOUT_FILENO || o->fd == STDERR_FILENO) && _isatty(o->fd)) { + return 0; + } + #endif #define VFS_POSIX_STREAM_STDIO_ERR_CATCH (err == EINVAL || err == EBADF) #else #define VFS_POSIX_STREAM_STDIO_ERR_CATCH (err == EINVAL) #endif MP_HAL_RETRY_SYSCALL(ret, fsync(o->fd), { if (VFS_POSIX_STREAM_STDIO_ERR_CATCH + // Note: comparing fd against the standard FILENOs is technically not correct, for example: + // sys.stderr.close() in Python code results in close(STDERR_FILENO) here, but because + // open() uses the next available file descriptor, opening an arbitrary file with + // fd = open('/some/file') means that fd becomes STDERR_FILENO. && (o->fd == STDIN_FILENO || o->fd == STDOUT_FILENO || o->fd == STDERR_FILENO)) { return 0; } diff --git a/lib/libffi b/lib/libffi index e9de7e35f2339..3d0ce1e6fcf19 160000 --- a/lib/libffi +++ b/lib/libffi @@ -1 +1 @@ -Subproject commit e9de7e35f2339598b16cbb375f9992643ed81209 +Subproject commit 3d0ce1e6fcf19f853894862abcbac0ae78a7be60 diff --git a/lib/libm/libm.h b/lib/libm/libm.h index f782249e53465..75a2a775f8945 100644 --- a/lib/libm/libm.h +++ b/lib/libm/libm.h @@ -19,7 +19,15 @@ #include #include +// CIRCUITPY-CHANGE: prevent undefined warnings +#ifndef FLT_EVAL_METHOD #define FLT_EVAL_METHOD 0 +#endif + +// These lines verify that FLT_EVAL_METHOD==0, MicroPython's libm requires this. +// If compilation fails here then check the host compiler's FLT_EVAL_METHOD. +typedef float float_t; +typedef double double_t; #define FORCE_EVAL(x) do { \ if (sizeof(x) == sizeof(float)) { \ diff --git a/lib/libm/wf_lgamma.c b/lib/libm/wf_lgamma.c index bcf3705420ec8..7580d2f74e5a8 100644 --- a/lib/libm/wf_lgamma.c +++ b/lib/libm/wf_lgamma.c @@ -24,7 +24,9 @@ */ #include "fdlibm.h" +#ifndef _IEEE_LIBM #define _IEEE_LIBM 1 +#endif #ifdef __STDC__ float lgammaf(float x) diff --git a/lib/libm/wf_tgamma.c b/lib/libm/wf_tgamma.c index 3ff05f331d099..1a6c74ca11d86 100644 --- a/lib/libm/wf_tgamma.c +++ b/lib/libm/wf_tgamma.c @@ -24,7 +24,9 @@ #include "math.h" #include "fdlibm.h" +#ifndef _IEEE_LIBM #define _IEEE_LIBM 1 +#endif #ifdef __STDC__ float tgammaf(float x) diff --git a/lib/libm_dbl/libm.h b/lib/libm_dbl/libm.h index dc0b431a44857..cbae6916625e2 100644 --- a/lib/libm_dbl/libm.h +++ b/lib/libm_dbl/libm.h @@ -15,7 +15,10 @@ #include #include -#define FLT_EVAL_METHOD 0 +// These lines verify that FLT_EVAL_METHOD==0, MicroPython's libm requires this. +// If compilation fails here then check the host compiler's FLT_EVAL_METHOD. +typedef float float_t; +typedef double double_t; #define FORCE_EVAL(x) do { \ if (sizeof(x) == sizeof(float)) { \ diff --git a/lib/micropython-lib b/lib/micropython-lib index 50ed36fbeb919..68e3e07bc7ab6 160000 --- a/lib/micropython-lib +++ b/lib/micropython-lib @@ -1 +1 @@ -Subproject commit 50ed36fbeb919753bcc26ce13a8cffd7691d06ef +Subproject commit 68e3e07bc7ab63931cead3854b2a114e9a084248 diff --git a/lib/tinytest/README b/lib/tinytest/README deleted file mode 100644 index 28165d8bc794a..0000000000000 --- a/lib/tinytest/README +++ /dev/null @@ -1,17 +0,0 @@ -Tinytest is a tiny little test framework written in C by Nick Mathewson. - -It is distributed under the 3-clause BSD license. You can use it in -your own programs so long as you follow the license's conditions. - -It's been tested on Windows, Mac, and many of the free Unixes. - -It knows how to fork before running certain tests, and it makes -text-mode output in a format I like. - -For info on how to use it, check out tinytest_demo.c. - -You can get the latest version using Git, by pulling from - git://github.com/nmathewson/tinytest.git - -Patches are welcome. Patches that turn this from tinytest to hugetest -will not be applied. If you want a huge test framework, use CUnit. diff --git a/lib/tinytest/tinytest.c b/lib/tinytest/tinytest.c deleted file mode 100644 index 1a5030ae3c5ac..0000000000000 --- a/lib/tinytest/tinytest.c +++ /dev/null @@ -1,473 +0,0 @@ -/* tinytest.c -- Copyright 2009-2012 Nick Mathewson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifdef TINYTEST_LOCAL -#include "tinytest_local.h" -#endif - -#include -#include -#include -#include - -#ifndef NO_FORKING - -#ifdef _WIN32 -#include -#else -#include -#include -#include -#endif - -#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) -#if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \ - __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070) -/* Workaround for a stupid bug in OSX 10.6 */ -#define FORK_BREAKS_GCOV -#include -#endif -#endif - -#endif /* !NO_FORKING */ - -#ifndef __GNUC__ -#define __attribute__(x) -#endif - -#include "tinytest.h" -#include "tinytest_macros.h" - -#define LONGEST_TEST_NAME 16384 - -static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/ -static int n_ok = 0; /**< Number of tests that have passed */ -static int n_bad = 0; /**< Number of tests that have failed. */ -static int n_skipped = 0; /**< Number of tests that have been skipped. */ - -static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/ -static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */ -static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */ -const char *verbosity_flag = ""; - -const struct testlist_alias_t *cfg_aliases=NULL; - -enum outcome { SKIP=2, OK=1, FAIL=0 }; -static enum outcome cur_test_outcome = 0; -const char *cur_test_prefix = NULL; /**< prefix of the current test group */ -/** Name of the current test, if we haven't logged is yet. Used for --quiet */ -const char *cur_test_name = NULL; - -#ifdef _WIN32 -/* Copy of argv[0] for win32. */ -static char commandname[MAX_PATH+1]; -#endif - -static void usage(struct testgroup_t *groups, int list_groups) - __attribute__((noreturn)); -static int process_test_option(struct testgroup_t *groups, const char *test); - -static enum outcome -testcase_run_bare_(const struct testcase_t *testcase) -{ - void *env = NULL; - int outcome; - if (testcase->setup) { - env = testcase->setup->setup_fn(testcase); - if (!env) - return FAIL; - else if (env == (void*)TT_SKIP) - return SKIP; - } - - cur_test_outcome = OK; - testcase->fn(env); - outcome = cur_test_outcome; - - if (testcase->setup) { - if (testcase->setup->cleanup_fn(testcase, env) == 0) - outcome = FAIL; - } - - return outcome; -} - -#define MAGIC_EXITCODE 42 - -#ifndef NO_FORKING - -static enum outcome -testcase_run_forked_(const struct testgroup_t *group, - const struct testcase_t *testcase) -{ -#ifdef _WIN32 - /* Fork? On Win32? How primitive! We'll do what the smart kids do: - we'll invoke our own exe (whose name we recall from the command - line) with a command line that tells it to run just the test we - want, and this time without forking. - - (No, threads aren't an option. The whole point of forking is to - share no state between tests.) - */ - int ok; - char buffer[LONGEST_TEST_NAME+256]; - STARTUPINFOA si; - PROCESS_INFORMATION info; - DWORD exitcode; - - if (!in_tinytest_main) { - printf("\nERROR. On Windows, testcase_run_forked_ must be" - " called from within tinytest_main.\n"); - abort(); - } - if (opt_verbosity>0) - printf("[forking] "); - - snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s", - commandname, verbosity_flag, group->prefix, testcase->name); - - memset(&si, 0, sizeof(si)); - memset(&info, 0, sizeof(info)); - si.cb = sizeof(si); - - ok = CreateProcessA(commandname, buffer, NULL, NULL, 0, - 0, NULL, NULL, &si, &info); - if (!ok) { - printf("CreateProcess failed!\n"); - return 0; - } - WaitForSingleObject(info.hProcess, INFINITE); - GetExitCodeProcess(info.hProcess, &exitcode); - CloseHandle(info.hProcess); - CloseHandle(info.hThread); - if (exitcode == 0) - return OK; - else if (exitcode == MAGIC_EXITCODE) - return SKIP; - else - return FAIL; -#else - int outcome_pipe[2]; - pid_t pid; - (void)group; - - if (pipe(outcome_pipe)) - perror("opening pipe"); - - if (opt_verbosity>0) - printf("[forking] "); - pid = fork(); -#ifdef FORK_BREAKS_GCOV - vproc_transaction_begin(0); -#endif - if (!pid) { - /* child. */ - int test_r, write_r; - char b[1]; - close(outcome_pipe[0]); - test_r = testcase_run_bare_(testcase); - assert(0<=(int)test_r && (int)test_r<=2); - b[0] = "NYS"[test_r]; - write_r = (int)write(outcome_pipe[1], b, 1); - if (write_r != 1) { - perror("write outcome to pipe"); - exit(1); - } - exit(0); - return FAIL; /* unreachable */ - } else { - /* parent */ - int status, r; - char b[1]; - /* Close this now, so that if the other side closes it, - * our read fails. */ - close(outcome_pipe[1]); - r = (int)read(outcome_pipe[0], b, 1); - if (r == 0) { - printf("[Lost connection!] "); - return 0; - } else if (r != 1) { - perror("read outcome from pipe"); - } - waitpid(pid, &status, 0); - close(outcome_pipe[0]); - return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL); - } -#endif -} - -#endif /* !NO_FORKING */ - -int -testcase_run_one(const struct testgroup_t *group, - const struct testcase_t *testcase) -{ - enum outcome outcome; - - if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) { - if (opt_verbosity>0) - printf("%s%s: %s\n", - group->prefix, testcase->name, - (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED"); - ++n_skipped; - return SKIP; - } - - if (opt_verbosity>0 && !opt_forked) { - printf("%s%s: ", group->prefix, testcase->name); - } else { - if (opt_verbosity==0) printf("."); - cur_test_prefix = group->prefix; - cur_test_name = testcase->name; - } - -#ifndef NO_FORKING - if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) { - outcome = testcase_run_forked_(group, testcase); - } else { -#else - { -#endif - outcome = testcase_run_bare_(testcase); - } - - if (outcome == OK) { - ++n_ok; - if (opt_verbosity>0 && !opt_forked) - puts(opt_verbosity==1?"OK":""); - } else if (outcome == SKIP) { - ++n_skipped; - if (opt_verbosity>0 && !opt_forked) - puts("SKIPPED"); - } else { - ++n_bad; - if (!opt_forked) - printf("\n [%s FAILED]\n", testcase->name); - } - - if (opt_forked) { - exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1)); - return 1; /* unreachable */ - } else { - return (int)outcome; - } -} - -int -tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag) -{ - int i, j; - size_t length = LONGEST_TEST_NAME; - char fullname[LONGEST_TEST_NAME]; - int found=0; - if (strstr(arg, "..")) - length = strstr(arg,"..")-arg; - for (i=0; groups[i].prefix; ++i) { - for (j=0; groups[i].cases[j].name; ++j) { - struct testcase_t *testcase = &groups[i].cases[j]; - snprintf(fullname, sizeof(fullname), "%s%s", - groups[i].prefix, testcase->name); - if (!flag) { /* Hack! */ - printf(" %s", fullname); - if (testcase->flags & TT_OFF_BY_DEFAULT) - puts(" (Off by default)"); - else if (testcase->flags & TT_SKIP) - puts(" (DISABLED)"); - else - puts(""); - } - if (!strncmp(fullname, arg, length)) { - if (set) - testcase->flags |= flag; - else - testcase->flags &= ~flag; - ++found; - } - } - } - return found; -} - -static void -usage(struct testgroup_t *groups, int list_groups) -{ - puts("Options are: [--verbose|--quiet|--terse] [--no-fork]"); - puts(" Specify tests by name, or using a prefix ending with '..'"); - puts(" To skip a test, prefix its name with a colon."); - puts(" To enable a disabled test, prefix its name with a plus."); - puts(" Use --list-tests for a list of tests."); - if (list_groups) { - puts("Known tests are:"); - tinytest_set_flag_(groups, "..", 1, 0); - } - exit(0); -} - -static int -process_test_alias(struct testgroup_t *groups, const char *test) -{ - int i, j, n, r; - for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) { - if (!strcmp(cfg_aliases[i].name, test)) { - n = 0; - for (j = 0; cfg_aliases[i].tests[j]; ++j) { - r = process_test_option(groups, cfg_aliases[i].tests[j]); - if (r<0) - return -1; - n += r; - } - return n; - } - } - printf("No such test alias as @%s!",test); - return -1; -} - -static int -process_test_option(struct testgroup_t *groups, const char *test) -{ - int flag = TT_ENABLED_; - int n = 0; - if (test[0] == '@') { - return process_test_alias(groups, test + 1); - } else if (test[0] == ':') { - ++test; - flag = TT_SKIP; - } else if (test[0] == '+') { - ++test; - ++n; - if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) { - printf("No such test as %s!\n", test); - return -1; - } - } else { - ++n; - } - if (!tinytest_set_flag_(groups, test, 1, flag)) { - printf("No such test as %s!\n", test); - return -1; - } - return n; -} - -void -tinytest_set_aliases(const struct testlist_alias_t *aliases) -{ - cfg_aliases = aliases; -} - -int -tinytest_main(int c, const char **v, struct testgroup_t *groups) -{ - int i, j, n=0; - -#ifdef _WIN32 - const char *sp = strrchr(v[0], '.'); - const char *extension = ""; - if (!sp || stricmp(sp, ".exe")) - extension = ".exe"; /* Add an exe so CreateProcess will work */ - snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension); - commandname[MAX_PATH]='\0'; -#endif - for (i=1; i= 1) - printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped); - - return (n_bad == 0) ? 0 : 1; -} - -int -tinytest_get_verbosity_(void) -{ - return opt_verbosity; -} - -void -tinytest_set_test_failed_(void) -{ - if (opt_verbosity <= 0 && cur_test_name) { - if (opt_verbosity==0) puts(""); - printf("%s%s: ", cur_test_prefix, cur_test_name); - cur_test_name = NULL; - } - cur_test_outcome = 0; -} - -void -tinytest_set_test_skipped_(void) -{ - if (cur_test_outcome==OK) - cur_test_outcome = SKIP; -} diff --git a/lib/tinytest/tinytest.h b/lib/tinytest/tinytest.h deleted file mode 100644 index dff440e3190ed..0000000000000 --- a/lib/tinytest/tinytest.h +++ /dev/null @@ -1,98 +0,0 @@ -/* tinytest.h -- Copyright 2009-2012 Nick Mathewson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TINYTEST_H_INCLUDED_ -#define TINYTEST_H_INCLUDED_ - -/** Flag for a test that needs to run in a subprocess. */ -#define TT_FORK (1<<0) -/** Runtime flag for a test we've decided to skip. */ -#define TT_SKIP (1<<1) -/** Internal runtime flag for a test we've decided to run. */ -#define TT_ENABLED_ (1<<2) -/** Flag for a test that's off by default. */ -#define TT_OFF_BY_DEFAULT (1<<3) -/** If you add your own flags, make them start at this point. */ -#define TT_FIRST_USER_FLAG (1<<4) - -typedef void (*testcase_fn)(void *); - -struct testcase_t; - -/** Functions to initialize/teardown a structure for a testcase. */ -struct testcase_setup_t { - /** Return a new structure for use by a given testcase. */ - void *(*setup_fn)(const struct testcase_t *); - /** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */ - int (*cleanup_fn)(const struct testcase_t *, void *); -}; - -/** A single test-case that you can run. */ -struct testcase_t { - const char *name; /**< An identifier for this case. */ - testcase_fn fn; /**< The function to run to implement this case. */ - unsigned long flags; /**< Bitfield of TT_* flags. */ - const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/ - void *setup_data; /**< Extra data usable by setup function */ -}; -#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL } - -/** A group of tests that are selectable together. */ -struct testgroup_t { - const char *prefix; /**< Prefix to prepend to testnames. */ - struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */ -}; -#define END_OF_GROUPS { NULL, NULL} - -struct testlist_alias_t { - const char *name; - const char **tests; -}; -#define END_OF_ALIASES { NULL, NULL } - -/** Implementation: called from a test to indicate failure, before logging. */ -void tinytest_set_test_failed_(void); -/** Implementation: called from a test to indicate that we're skipping. */ -void tinytest_set_test_skipped_(void); -/** Implementation: return 0 for quiet, 1 for normal, 2 for loud. */ -int tinytest_get_verbosity_(void); -/** Implementation: Set a flag on tests matching a name; returns number - * of tests that matched. */ -int tinytest_set_flag_(struct testgroup_t *, const char *, int set, unsigned long); - -/** Set all tests in 'groups' matching the name 'named' to be skipped. */ -#define tinytest_skip(groups, named) \ - tinytest_set_flag_(groups, named, 1, TT_SKIP) - -/** Run a single testcase in a single group. */ -int testcase_run_one(const struct testgroup_t *,const struct testcase_t *); - -void tinytest_set_aliases(const struct testlist_alias_t *aliases); - -/** Run a set of testcases from an END_OF_GROUPS-terminated array of groups, - as selected from the command line. */ -int tinytest_main(int argc, const char **argv, struct testgroup_t *groups); - -#endif diff --git a/lib/tinytest/tinytest_macros.h b/lib/tinytest/tinytest_macros.h deleted file mode 100644 index 9ff69b1d506da..0000000000000 --- a/lib/tinytest/tinytest_macros.h +++ /dev/null @@ -1,184 +0,0 @@ -/* tinytest_macros.h -- Copyright 2009-2012 Nick Mathewson - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef TINYTEST_MACROS_H_INCLUDED_ -#define TINYTEST_MACROS_H_INCLUDED_ - -/* Helpers for defining statement-like macros */ -#define TT_STMT_BEGIN do { -#define TT_STMT_END } while (0) - -/* Redefine this if your test functions want to abort with something besides - * "goto end;" */ -#ifndef TT_EXIT_TEST_FUNCTION -#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END -#endif - -/* Redefine this if you want to note success/failure in some different way. */ -#ifndef TT_DECLARE -#define TT_DECLARE(prefix, args) \ - TT_STMT_BEGIN \ - printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \ - printf args ; \ - TT_STMT_END -#endif - -/* Announce a failure. Args are parenthesized printf args. */ -#define TT_GRIPE(args) TT_DECLARE("FAIL", args) - -/* Announce a non-failure if we're verbose. */ -#define TT_BLATHER(args) \ - TT_STMT_BEGIN \ - if (tinytest_get_verbosity_()>1) TT_DECLARE(" OK", args); \ - TT_STMT_END - -#define TT_DIE(args) \ - TT_STMT_BEGIN \ - tinytest_set_test_failed_(); \ - TT_GRIPE(args); \ - TT_EXIT_TEST_FUNCTION; \ - TT_STMT_END - -#define TT_FAIL(args) \ - TT_STMT_BEGIN \ - tinytest_set_test_failed_(); \ - TT_GRIPE(args); \ - TT_STMT_END - -/* Fail and abort the current test for the reason in msg */ -#define tt_abort_printf(msg) TT_DIE(msg) -#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno)) -#define tt_abort_msg(msg) TT_DIE(("%s", msg)) -#define tt_abort() TT_DIE(("%s", "(Failed.)")) - -/* Fail but do not abort the current test for the reason in msg. */ -#define tt_failprint_f(msg) TT_FAIL(msg) -#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno)) -#define tt_fail_msg(msg) TT_FAIL(("%s", msg)) -#define tt_fail() TT_FAIL(("%s", "(Failed.)")) - -/* End the current test, and indicate we are skipping it. */ -#define tt_skip() \ - TT_STMT_BEGIN \ - tinytest_set_test_skipped_(); \ - TT_EXIT_TEST_FUNCTION; \ - TT_STMT_END - -#define tt_want_(b, msg, fail) \ - TT_STMT_BEGIN \ - if (!(b)) { \ - tinytest_set_test_failed_(); \ - TT_GRIPE(("%s",msg)); \ - fail; \ - } else { \ - TT_BLATHER(("%s",msg)); \ - } \ - TT_STMT_END - -/* Assert b, but do not stop the test if b fails. Log msg on failure. */ -#define tt_want_msg(b, msg) \ - tt_want_(b, msg, ); - -/* Assert b and stop the test if b fails. Log msg on failure. */ -#define tt_assert_msg(b, msg) \ - tt_want_(b, msg, TT_EXIT_TEST_FUNCTION); - -/* Assert b, but do not stop the test if b fails. */ -#define tt_want(b) tt_want_msg( (b), "want("#b")") -/* Assert b, and stop the test if b fails. */ -#define tt_assert(b) tt_assert_msg((b), "assert("#b")") - -#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \ - setup_block,cleanup_block,die_on_fail) \ - TT_STMT_BEGIN \ - type val1_ = (type)(a); \ - type val2_ = (type)(b); \ - int tt_status_ = (test); \ - if (!tt_status_ || tinytest_get_verbosity_()>1) { \ - printf_type print_; \ - printf_type print1_; \ - printf_type print2_; \ - type value_ = val1_; \ - setup_block; \ - print1_ = print_; \ - value_ = val2_; \ - setup_block; \ - print2_ = print_; \ - TT_DECLARE(tt_status_?" OK":"FAIL", \ - ("assert(%s): "printf_fmt" vs "printf_fmt, \ - str_test, print1_, print2_)); \ - print_ = print1_; \ - cleanup_block; \ - print_ = print2_; \ - cleanup_block; \ - if (!tt_status_) { \ - tinytest_set_test_failed_(); \ - die_on_fail ; \ - } \ - } \ - TT_STMT_END - -#define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail) \ - tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \ - {print_=value_;},{},die_on_fail) - -/* Helper: assert that a op b, when cast to type. Format the values with - * printf format fmt on failure. */ -#define tt_assert_op_type(a,op,b,type,fmt) \ - tt_assert_test_type(a,b,#a" "#op" "#b,type,(val1_ op val2_),fmt, \ - TT_EXIT_TEST_FUNCTION) - -#define tt_int_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \ - "%ld",TT_EXIT_TEST_FUNCTION) - -#define tt_uint_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \ - (val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION) - -#define tt_ptr_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,void*, \ - (val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION) - -#define tt_str_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \ - (strcmp(val1_,val2_) op 0),"<%s>",TT_EXIT_TEST_FUNCTION) - -#define tt_want_int_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0) - -#define tt_want_uint_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \ - (val1_ op val2_),"%lu",(void)0) - -#define tt_want_ptr_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,void*, \ - (val1_ op val2_),"%p",(void)0) - -#define tt_want_str_op(a,op,b) \ - tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \ - (strcmp(val1_,val2_) op 0),"<%s>",(void)0) - -#endif diff --git a/locale/ID.po b/locale/ID.po index 0eedaf07868d4..134694c4bc242 100644 --- a/locale/ID.po +++ b/locale/ID.po @@ -321,7 +321,7 @@ msgid "'%q' object does not support '%q'" msgstr "Objek '%q' tidak mendukung '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "Objek '%q' bukan merupakan iterator" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -329,7 +329,7 @@ msgid "'%q' object is not callable" msgstr "Objek '%q' tidak dapat dipanggil" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "Objek '%q' tidak dapat diulang" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -871,6 +871,10 @@ msgstr "Deretan koordinat memiliki panjang yang berbeda" msgid "Coordinate arrays types have different sizes" msgstr "Tipe array koordinat memiliki ukuran yang berbeda" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "Tidak dapat mengatur alamat" @@ -883,6 +887,11 @@ msgstr "Tidak dapat memulai interupsi, RX sibuk" msgid "Couldn't allocate decoder" msgstr "Tidak dapat mengalokasikan dekoder" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "Terjadi kesalahan saat menginisialisasi kanal DAC" @@ -1312,6 +1321,10 @@ msgstr "" msgid "Invalid MAC address" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Argumen tidak valid" @@ -1874,6 +1887,10 @@ msgstr "Ukuran program tidak valid" msgid "Program too long" msgstr "Program terlalu lama" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "Pull tidak digunakan saat arah output." @@ -1894,6 +1911,26 @@ msgstr "Kesalahan DeInit RNG" msgid "RNG Init Error" msgstr "Kesalahan Init RNG" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -3193,7 +3230,7 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "" #: py/objdeque.c @@ -3652,7 +3689,7 @@ msgid "must use keyword argument for key function" msgstr "" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "" #: py/runtime.c @@ -4293,11 +4330,11 @@ msgid "tx and rx cannot both be None" msgstr "tx dan rx keduanya tidak boleh kosong" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "" #: py/runtime.c @@ -4710,13 +4747,13 @@ msgstr "Zi harus berbentuk (n_section, 2)" #~ msgid "'%s' object does not support item deletion" #~ msgstr "Objek '%s' tidak mendukung penghapusan item" -#~ msgid "'%s' object is not an iterator" +#~ msgid "'%s' object isn't an iterator" #~ msgstr "Objek '%s' bukan iterator" #~ msgid "'%s' object is not callable" #~ msgstr "Objek '%s' tidak dapat dipanggil" -#~ msgid "'%s' object is not iterable" +#~ msgid "'%s' object isn't iterable" #~ msgstr "'%s' objek tidak dapat diulang" #~ msgid "'%s' object is not subscriptable" @@ -5526,7 +5563,7 @@ msgstr "Zi harus berbentuk (n_section, 2)" #~ msgid "frequency can only be either 80Mhz or 160MHz" #~ msgstr "frekuensi hanya bisa didefinisikan 80Mhz atau 160Mhz" -#~ msgid "function does not take keyword arguments" +#~ msgid "function doesn't take keyword arguments" #~ msgstr "fungsi tidak dapat mengambil argumen keyword" #~ msgid "impossible baudrate" @@ -5581,7 +5618,7 @@ msgstr "Zi harus berbentuk (n_section, 2)" #~ msgid "name must be a string" #~ msgstr "keyword harus berupa string" -#~ msgid "name reused for argument" +#~ msgid "argument name reused" #~ msgstr "nama digunakan kembali untuk argumen" #~ msgid "non-keyword arg after */**" diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 1c6fcce1d417a..9e8043764288f 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -69,7 +69,7 @@ msgstr "" #: py/objstr.c #, c-format -msgid "%%c requires int or char" +msgid "%%c needs int or char" msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -158,7 +158,7 @@ msgstr "" msgid "%q length must be >= %d" msgstr "" -#: py/modsys.c py/runtime.c +#: py/runtime.c msgid "%q moved from %q to %q" msgstr "" @@ -309,15 +309,15 @@ msgid "'%q' object does not support '%q'" msgstr "" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object is not callable" +msgid "'%q' object isn't callable" msgstr "" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -848,6 +848,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "" @@ -860,6 +864,11 @@ msgstr "" msgid "Couldn't allocate decoder" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "" @@ -1287,6 +1296,10 @@ msgstr "" msgid "Invalid MAC address" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "" @@ -1841,6 +1854,10 @@ msgstr "" msgid "Program too long" msgstr "" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "" @@ -1861,6 +1878,26 @@ msgstr "" msgid "RNG Init Error" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2728,6 +2765,10 @@ msgstr "" msgid "can't convert to str implicitly" msgstr "" +#: py/objtype.c +msgid "can't create '%q' instances" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2826,10 +2867,6 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create '%q' instances" -msgstr "" - #: py/objtype.c msgid "cannot create instance" msgstr "" @@ -3144,7 +3181,15 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" +msgstr "" + +#: py/objstr.c +msgid "format string didn't convert all arguments" +msgstr "" + +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" #: py/objdeque.c @@ -3603,7 +3648,7 @@ msgid "must use keyword argument for key function" msgstr "" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "" #: py/runtime.c @@ -3693,7 +3738,7 @@ msgid "non-default argument follows default argument" msgstr "" #: py/objstr.c -msgid "non-hex digit found" +msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c @@ -3712,14 +3757,6 @@ msgstr "" msgid "not a constant" msgstr "" -#: py/objstr.c -msgid "not all arguments converted during string formatting" -msgstr "" - -#: py/objstr.c -msgid "not enough arguments for format string" -msgstr "" - #: extmod/ulab/code/numpy/carray/carray_tools.c msgid "not implemented for complex dtype" msgstr "" @@ -3782,10 +3819,6 @@ msgstr "" msgid "object with buffer protocol required" msgstr "" -#: py/objstr.c -msgid "odd-length string" -msgstr "" - #: supervisor/shared/web_workflow/web_workflow.c msgid "off" msgstr "" @@ -3974,10 +4007,6 @@ msgstr "" msgid "pull masks conflict with direction masks" msgstr "" -#: py/parse.c -msgid "raw f-strings are not supported" -msgstr "" - #: extmod/ulab/code/numpy/fft/fft_tools.c msgid "real and imaginary parts must be of equal length" msgstr "" @@ -4244,11 +4273,11 @@ msgid "tx and rx cannot both be None" msgstr "" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "" #: py/runtime.c diff --git a/locale/cs.po b/locale/cs.po index f9e5f9f670350..c7e1f916dceab 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -80,8 +80,8 @@ msgstr " výstup:\n" #: py/objstr.c #, c-format -msgid "%%c requires int or char" -msgstr "%%c vyžaduje int nebo char" +msgid "%%c needs int or char" +msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format @@ -169,7 +169,7 @@ msgstr "Délka %q musí být <= %d" msgid "%q length must be >= %d" msgstr "Délka %q musí být >= %d" -#: py/modsys.c py/runtime.c +#: py/runtime.c msgid "%q moved from %q to %q" msgstr "" @@ -320,15 +320,15 @@ msgid "'%q' object does not support '%q'" msgstr "Objekt '%q' nepodporuje '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "Objekt '%q' není iterátor" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object is not callable" -msgstr "Objekt '%q' nelze zavolat" +msgid "'%q' object isn't callable" +msgstr "" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "Objekt '%q' není iterovatelný" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -865,6 +865,10 @@ msgstr "Pole souřadnic mají různé délky" msgid "Coordinate arrays types have different sizes" msgstr "" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "Není možné nastavit adresu" @@ -877,6 +881,11 @@ msgstr "Nelze začít přerušení, RX je zaneprázdněn" msgid "Couldn't allocate decoder" msgstr "Dekodér nelze přiřadit" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "Chyba inicializace kanálu DAC" @@ -1307,6 +1316,10 @@ msgstr "Chybné BSSID" msgid "Invalid MAC address" msgstr "Chybná MAC adresa" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Neplatný argument" @@ -1864,6 +1877,10 @@ msgstr "Velikost programu je nesprávná" msgid "Program too long" msgstr "Program je příliš dlouhý" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "" @@ -1884,6 +1901,26 @@ msgstr "" msgid "RNG Init Error" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2757,6 +2794,10 @@ msgstr "nelze převést na int" msgid "can't convert to str implicitly" msgstr "" +#: py/objtype.c +msgid "can't create '%q' instances" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2855,10 +2896,6 @@ msgstr "nelze převést complex na dtype" msgid "cannot convert complex type" msgstr "nelze převést typ complex" -#: py/objtype.c -msgid "cannot create '%q' instances" -msgstr "" - #: py/objtype.c msgid "cannot create instance" msgstr "" @@ -3173,7 +3210,15 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" +msgstr "" + +#: py/objstr.c +msgid "format string didn't convert all arguments" +msgstr "" + +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" #: py/objdeque.c @@ -3632,7 +3677,7 @@ msgid "must use keyword argument for key function" msgstr "" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "" #: py/runtime.c @@ -3722,7 +3767,7 @@ msgid "non-default argument follows default argument" msgstr "" #: py/objstr.c -msgid "non-hex digit found" +msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c @@ -3741,14 +3786,6 @@ msgstr "" msgid "not a constant" msgstr "není konstanta" -#: py/objstr.c -msgid "not all arguments converted during string formatting" -msgstr "" - -#: py/objstr.c -msgid "not enough arguments for format string" -msgstr "" - #: extmod/ulab/code/numpy/carray/carray_tools.c msgid "not implemented for complex dtype" msgstr "není implementováno pro komplexní dtype" @@ -3811,10 +3848,6 @@ msgstr "objekt typu '%s' nemá len()" msgid "object with buffer protocol required" msgstr "" -#: py/objstr.c -msgid "odd-length string" -msgstr "" - #: supervisor/shared/web_workflow/web_workflow.c msgid "off" msgstr "vypnuto" @@ -4003,10 +4036,6 @@ msgstr "" msgid "pull masks conflict with direction masks" msgstr "" -#: py/parse.c -msgid "raw f-strings are not supported" -msgstr "surové f-stringy nesjou podporované" - #: extmod/ulab/code/numpy/fft/fft_tools.c msgid "real and imaginary parts must be of equal length" msgstr "" @@ -4273,11 +4302,11 @@ msgid "tx and rx cannot both be None" msgstr "" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "" #: py/runtime.c @@ -4481,6 +4510,16 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, c-format +#~ msgid "%%c requires int or char" +#~ msgstr "%%c vyžaduje int nebo char" + +#~ msgid "'%q' object is not callable" +#~ msgstr "Objekt '%q' nelze zavolat" + +#~ msgid "raw f-strings are not supported" +#~ msgstr "surové f-stringy nesjou podporované" + #~ msgid "Unsupported format" #~ msgstr "Nepodporovaný formát" @@ -4703,7 +4742,7 @@ msgstr "" #~ msgid "'continue' outside loop" #~ msgstr "'continue' je volán mimo cyklus" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "Objekt 'coroutine' není iterátor" #~ msgid "64 bit types" diff --git a/locale/de_DE.po b/locale/de_DE.po index 8d509153cbf2c..956f4c13353b5 100644 --- a/locale/de_DE.po +++ b/locale/de_DE.po @@ -6,14 +6,14 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2024-12-15 14:00+0000\n" -"Last-Translator: Exp3rt \n" +"PO-Revision-Date: 2025-06-12 23:09+0000\n" +"Last-Translator: MAE \n" "Language: de_DE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.9-rc\n" +"X-Generator: Weblate 5.12-dev\n" #: main.c msgid "" @@ -117,7 +117,7 @@ msgstr "%q Fehler: %d" #: shared-module/audiodelays/MultiTapDelay.c msgid "%q in %q must be of type %q or %q, not %q" -msgstr "" +msgstr "%q in %q muss vom Typ %q oder %q sein, nicht %q" #: py/argcheck.c shared-module/audiofilters/Filter.c msgid "%q in %q must be of type %q, not %q" @@ -304,7 +304,7 @@ msgstr "%q[%u] schiebt mehr Bits raus als Pins vorhanden sind" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "%q[%u] uses extra pin" -msgstr "" +msgstr "%q[%u] verwendet zusätzlichen Pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "%q[%u] waits on input outside of count" @@ -324,7 +324,7 @@ msgid "'%q' object does not support '%q'" msgstr "'%q' Objekt unterstützt '%q' nicht" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "'%q' Objekt ist kein Iterator" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -332,7 +332,7 @@ msgid "'%q' object is not callable" msgstr "'%q' Objekt ist kein callable" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "'%q' Objekt ist nicht iterierbar" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -495,7 +495,7 @@ msgstr "Adressbereich nicht erlaubt" #: shared-bindings/memorymap/AddressRange.c msgid "Address range wraps around" -msgstr "" +msgstr "Der Adressbereich umfasst folgende Bereiche" #: ports/espressif/common-hal/canio/CAN.c msgid "All CAN peripherals are in use" @@ -573,7 +573,7 @@ msgstr "All-Matchers-Listener bereits vorhanden" #: ports/espressif/common-hal/_bleio/__init__.c msgid "Already in progress" -msgstr "" +msgstr "Bereits in Arbeit" #: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c @@ -613,7 +613,7 @@ msgstr "Array-Werte sollten aus Einzelbytes bestehen." #: ports/atmel-samd/common-hal/spitarget/SPITarget.c msgid "Async SPI transfer in progress on this bus, keep awaiting." -msgstr "" +msgstr "Asynchroner SPI-Transfer auf diesem Bus im Gange, warten Sie weiter." #: shared-module/memorymonitor/AllocationAlarm.c #, c-format @@ -627,7 +627,7 @@ msgstr "Audio-Konvertierung nicht implementiert" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c msgid "Audio source error" -msgstr "" +msgstr "Audioquellenfehler" #: shared-bindings/wifi/Radio.c msgid "AuthMode.OPEN is not used with password" @@ -660,7 +660,7 @@ msgstr "Unterhalb der minimalen Frame Rate" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must be sequential GPIO pins" -msgstr "" +msgstr "Bittakt und Wortauswahl müssen aufeinanderfolgende GPIO-Pins sein" #: shared-bindings/bitmaptools/__init__.c msgid "Bitmap size and bits per value must match" @@ -767,6 +767,8 @@ msgstr "Kann nur auf zwei Pins Alarm als low aus Deep Sleep auslösen." #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Can't construct AudioOut because continuous channel already open" msgstr "" +"AudioOut kann nicht erstellt werden, da ein kontinuierlicher Kanal bereits " +"geöffnet ist" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c @@ -816,6 +818,7 @@ msgstr "Aufnahme in eine Datei nicht möglich" #: shared-module/storage/__init__.c msgid "Cannot remount path when visible via USB." msgstr "" +"Der Pfad kann nicht neu gemountet werden, wenn er über USB sichtbar ist." #: shared-bindings/digitalio/DigitalInOut.c msgid "Cannot set value when direction is input." @@ -832,7 +835,7 @@ msgstr "Slice kann keine sub-klasse sein" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" +msgstr "GPIO0..15 kann nicht zusammen mit GPIO32..47 verwendet werden" #: ports/nordic/common-hal/alarm/pin/PinAlarm.c msgid "Cannot wake on pin edge, only level" @@ -870,6 +873,10 @@ msgstr "Koordinaten-Arrays haben unterschiedliche Längen" msgid "Coordinate arrays types have different sizes" msgstr "Typen der Koordinaten-Arrays haben unterschiedliche Längen" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "Konnte Adresse nicht setzen" @@ -882,6 +889,11 @@ msgstr "Interrupt konnte nicht gestartet werden, RX beschäftigt" msgid "Couldn't allocate decoder" msgstr "Decoder konnte nicht zugeordnet werden" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "DAC-Kanal-Initialisierungsfehler" @@ -1000,12 +1012,14 @@ msgstr "Mutex konnte nicht akquiriert werden. Status: 0x%04x" #: ports/raspberrypi/common-hal/mdns/Server.c msgid "Failed to add service TXT record" -msgstr "" +msgstr "Fehler beim Hinzufügen des TXT-Diensteintrags" #: shared-bindings/mdns/Server.c msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" +"Fehler beim Hinzufügen des TXT-Diensteintrags; Nicht-Zeichenfolge oder Bytes " +"in txt_records gefunden" #: shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" @@ -1035,22 +1049,24 @@ msgstr "Verbindung nicht erfolgreich: timeout" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to create continuous channels: invalid arg" msgstr "" +"Kontinuierliche Kanäle konnten nicht erstellt werden: ungültiges Argument" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to create continuous channels: invalid state" msgstr "" +"Kontinuierliche Kanäle konnten nicht erstellt werden: ungültiger Status" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to create continuous channels: no mem" -msgstr "" +msgstr "Kontinuierliche Kanäle konnten nicht erstellt werden: kein Speicher" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to create continuous channels: not found" -msgstr "" +msgstr "Kontinuierliche Kanäle konnten nicht erstellt werden: nicht gefunden" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to enable continuous" -msgstr "" +msgstr "Kontinuierliche Aktivierung fehlgeschlagen" #: shared-module/audiomp3/MP3Decoder.c msgid "Failed to parse MP3 file" @@ -1058,7 +1074,7 @@ msgstr "MP3-Datei konnte nicht analysiert werden" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to register continuous events callback" -msgstr "" +msgstr "Rückruf für kontinuierliche Ereignisse konnte nicht registriert werden" #: ports/nordic/sd_mutex.c #, c-format @@ -1067,11 +1083,11 @@ msgstr "Mutex konnte nicht freigegeben werden. Status: 0x%04x" #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" -msgstr "" +msgstr "Hostname konnte nicht gesetzt werden" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to start async audio" -msgstr "" +msgstr "Start von asynchronem Audio fehlgeschlagen" #: supervisor/shared/safe_mode.c msgid "Failed to write internal flash." @@ -1224,7 +1240,7 @@ msgstr "Unzureichender Speicherpool für das Bild" #: shared-module/jpegio/JpegDecoder.c msgid "Insufficient stream input buffer" -msgstr "" +msgstr "Unzureichender Stream-Eingabepuffer" #: ports/espressif/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c @@ -1318,6 +1334,10 @@ msgstr "Ungültige BSSID" msgid "Invalid MAC address" msgstr "Ungültige MAC-Adresse" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Ungültiges Argument" @@ -1397,6 +1417,8 @@ msgstr "Ebene muss eine Gruppe oder eine TileGrid Subklasse sein" #: shared-bindings/audiocore/RawSample.c msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" +"Die Länge von %q muss ein gerades Vielfaches von channel_count * type_size " +"sein" #: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" @@ -1410,7 +1432,7 @@ msgstr "MITM-Sicherheit wird nicht unterstützt" #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "MMC/SDIO Clock Error %x" -msgstr "" +msgstr "MMC/SDIO-Taktfehler %x" #: shared-bindings/is31fl3741/IS31FL3741.c msgid "Mapping must be a tuple" @@ -1600,7 +1622,7 @@ msgstr "Kein Pulldown-Widerstand am Pin; 1 MOhm wird vorgeschlagen" #: shared-module/touchio/TouchIn.c msgid "No pullup on pin; 1Mohm recommended" -msgstr "" +msgstr "Kein Pullup-Widerstand am Pin; 1Mohm wird vorgeschlagen" #: py/moderrno.c msgid "No space left on device" @@ -1649,7 +1671,7 @@ msgstr "Nicht unterstützter JPEG-Standard" #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format msgid "Number of data_pins must be %d or %d, not %d" -msgstr "" +msgstr "Die Anzahl der data_pins muss %d oder %d sein, nicht %d" #: shared-bindings/util.c msgid "" @@ -1778,6 +1800,7 @@ msgstr "PWM-Stück-Kanal A wird bereits verwendet" #: shared-bindings/spitarget/SPITarget.c msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" +"Die Paketpuffer für eine SPI-Übertragung müssen die gleiche Länge haben." #: shared-module/jpegio/JpegDecoder.c msgid "Parameter error" @@ -1884,6 +1907,10 @@ msgstr "Programm-Größe ist ungültig" msgid "Program too long" msgstr "Programm zu lang" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "Pull wird nicht verwendet, wenn die Richtung output ist." @@ -1904,6 +1931,26 @@ msgstr "RNG DeInit-Fehler" msgid "RNG Init Error" msgstr "RNG-Init-Fehler" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -1986,7 +2033,7 @@ msgstr "SDIO GetCardInfo-Fehler %d" #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "SDIO Init Error %x" -msgstr "" +msgstr "SDIO-Init-Fehler %x" #: ports/espressif/common-hal/busio/SPI.c msgid "SPI configuration failed" @@ -2086,7 +2133,7 @@ msgstr "Die Länge von rgb_pins muss 6, 12, 18, 24 oder 30 betragen" #: shared-module/audiocore/__init__.c msgid "The sample's %q does not match" -msgstr "" +msgstr "Der %q-Wert der Probe stimmt nicht überein" #: supervisor/shared/safe_mode.c msgid "Third-party firmware fatal error." @@ -2120,7 +2167,7 @@ msgstr "Die Kachelbreite muss die Bitmap-Breite genau teilen" #: shared-module/tilepalettemapper/TilePaletteMapper.c msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" +msgstr "TilePaletteMapper darf nur einmal an ein TileGrid gebunden werden" #: shared-bindings/alarm/time/TimeAlarm.c msgid "Time is in the past." @@ -2233,7 +2280,7 @@ msgstr "Konnte keine Buffer für Vorzeichenumwandlung allozieren" #: supervisor/shared/safe_mode.c msgid "Unable to allocate to the heap." -msgstr "" +msgstr "Die Zuweisung zum Heap ist nicht möglich." #: ports/espressif/common-hal/busio/I2C.c msgid "Unable to create lock" @@ -2256,6 +2303,8 @@ msgstr "Konnte Farbpalettendaten nicht lesen" #: ports/mimxrt10xx/common-hal/canio/CAN.c msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" +"CAN-Nachricht kann nicht gesendet werden: alle Sende-Nachrichtenpuffer sind " +"belegt" #: ports/espressif/common-hal/mdns/Server.c #: ports/raspberrypi/common-hal/mdns/Server.c @@ -2360,7 +2409,7 @@ msgstr "Hash Algorithmus wird nicht unterstützt" #: ports/espressif/common-hal/socketpool/Socket.c #: ports/zephyr-cp/common-hal/socketpool/Socket.c msgid "Unsupported socket type" -msgstr "" +msgstr "Nicht unterstützter Sockeltyp" #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/espressif/common-hal/dualbank/__init__.c @@ -2421,7 +2470,7 @@ msgstr "Wi-Fi: " #: ports/raspberrypi/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "WiFi is not enabled" -msgstr "" +msgstr "WiFi ist nicht aktiviert" #: main.c msgid "Woken up by alarm.\n" @@ -2520,7 +2569,7 @@ msgstr "addresses ist leer" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "already playing" -msgstr "" +msgstr "spielt bereits" #: py/compile.c msgid "annotation must be an identifier" @@ -2549,6 +2598,7 @@ msgstr "argsort ist für flattened Arrays nicht implementiert" #: extmod/ulab/code/numpy/random/random.c msgid "argument must be None, an integer or a tuple of integers" msgstr "" +"Das Argument muss None, eine Ganzzahl oder ein Tupel von Ganzzahlen sein" #: py/compile.c msgid "argument name reused" @@ -2602,7 +2652,7 @@ msgstr "Attribute werden nicht unterstützt" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "audio format not supported" -msgstr "" +msgstr "Audioformat wird nicht unterstützt" #: extmod/ulab/code/ulab_tools.c msgid "axis is out of bounds" @@ -2642,7 +2692,7 @@ msgstr "Der binäre Operator %q ist nicht implementiert" #: ports/espressif/common-hal/audiobusio/PDMIn.c msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" +msgstr "bit_depth muss 8, 16, 24 oder 32 sein." #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" @@ -2658,7 +2708,7 @@ msgstr "bits müssen 32 oder kleiner sein" #: shared-bindings/audiofreeverb/Freeverb.c msgid "bits_per_sample must be 16" -msgstr "" +msgstr "bits_per_sample muss 16 sein" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c #: shared-bindings/audiodelays/MultiTapDelay.c @@ -2873,7 +2923,7 @@ msgstr "" #: py/objcomplex.c msgid "can't truncate-divide a complex number" -msgstr "" +msgstr "kann eine komplexe Zahl nicht kürzen und dividieren" #: extmod/modasyncio.c msgid "can't wait" @@ -3217,7 +3267,7 @@ msgid "format" msgstr "Format" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "Format erfordert ein Wörterbuch (dict)" #: py/objdeque.c @@ -3684,7 +3734,7 @@ msgid "must use keyword argument for key function" msgstr "muss Schlüsselwortargument für key function verwenden" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "Name '%q' ist nirgends definiert worden (Schreibweise kontrollieren)" #: py/runtime.c @@ -3965,7 +4015,7 @@ msgstr "Ausgabe-Array ist zu klein" #: extmod/ulab/code/numpy/random/random.c msgid "out has wrong type" -msgstr "" +msgstr "Ausgabe hat den falschen Typ" #: extmod/ulab/code/numpy/vector.c msgid "out keyword is not supported for complex dtype" @@ -3993,11 +4043,11 @@ msgstr "Außerhalb des Bereichs des Ziels" #: extmod/ulab/code/numpy/random/random.c msgid "output array has wrong type" -msgstr "" +msgstr "Ausgabe-Array hat einen falschen Typ" #: extmod/ulab/code/numpy/random/random.c msgid "output array must be contiguous" -msgstr "" +msgstr "Ausgabe-Array muss zusammenhängend sein" #: py/objint_mpz.c msgid "overflow converting long int to machine word" @@ -4110,7 +4160,7 @@ msgstr "rsplit(None,n)" #: shared-bindings/audiofreeverb/Freeverb.c msgid "samples_signed must be true" -msgstr "" +msgstr "samples_signed muss wahr sein" #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c #: ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -4131,7 +4181,7 @@ msgstr "nicht unterstützt" #: extmod/ulab/code/numpy/random/random.c msgid "shape must be None, and integer or a tuple of integers" -msgstr "" +msgstr "Form muss Keine, eine Ganzzahl oder ein Tupel von Ganzenahlen sein" #: extmod/ulab/code/ndarray.c msgid "shape must be integer or tuple of integers" @@ -4155,7 +4205,7 @@ msgstr "Größe ist nur für ndarrays definiert" #: extmod/ulab/code/numpy/random/random.c msgid "size must match out.shape when used together" -msgstr "" +msgstr "size muss bei gemeinsamer Verwendung mit out.shape übereinstimmen" #: py/nativeglue.c msgid "slice unsupported" @@ -4203,7 +4253,7 @@ msgstr "source_bitmap muss value_count von 8 haben" #: extmod/modre.c msgid "splitting with sub-captures" -msgstr "" +msgstr "Aufteilung mit Untererfassungen" #: py/objstr.c msgid "start/end indices" @@ -4244,7 +4294,7 @@ msgstr "Syntaxfehler in JSON" #: extmod/modtime.c msgid "ticks interval overflow" -msgstr "" +msgstr "Ticks Intervallüberlauf" #: ports/nordic/common-hal/watchdog/WatchDogTimer.c msgid "timeout duration exceeded the maximum supported value" @@ -4256,12 +4306,12 @@ msgstr "timeout muss kleiner als 655.35 Sekunden sein" #: ports/raspberrypi/common-hal/floppyio/__init__.c msgid "timeout waiting for flux" -msgstr "" +msgstr "Zeitüberschreitung beim Warten auf Fluss" #: ports/raspberrypi/common-hal/floppyio/__init__.c #: shared-module/floppyio/__init__.c msgid "timeout waiting for index pulse" -msgstr "" +msgstr "Zeitüberschreitung beim Warten auf Indeximpuls" #: shared-module/sdcardio/SDCard.c msgid "timeout waiting for v1 card" @@ -4331,11 +4381,11 @@ msgid "tx and rx cannot both be None" msgstr "tx und rx können nicht beide None sein" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "Typ '%q' ist kein akzeptierter Basis-Typ" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "Typ ist kein akzeptierter Basis-Typ" #: py/runtime.c @@ -4892,13 +4942,13 @@ msgstr "zi muss die Form (n_section, 2) haben" #~ msgid "'%s' object does not support item deletion" #~ msgstr "'%s' Objekt unterstützt das Löschen von Elementen nicht" -#~ msgid "'%s' object is not an iterator" +#~ msgid "'%s' object isn't an iterator" #~ msgstr "'%s' Objekt ist kein Iterator" #~ msgid "'%s' object is not callable" #~ msgstr "'%s' object ist nicht aufrufbar" -#~ msgid "'%s' object is not iterable" +#~ msgid "'%s' object isn't iterable" #~ msgstr "'%s' Objekt nicht iterierbar" #~ msgid "'%s' object is not subscriptable" @@ -4917,7 +4967,7 @@ msgstr "zi muss die Form (n_section, 2) haben" #~ msgid "'continue' outside loop" #~ msgstr "'continue' außerhalb einer Schleife" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "'coroutine' Objekt ist kein Iterator" #~ msgid "(x,y) integers required" @@ -6287,7 +6337,7 @@ msgstr "zi muss die Form (n_section, 2) haben" #~ msgid "frequency is read-only for this board" #~ msgstr "Frequenz ist für dieses Board schreibgeschützt" -#~ msgid "function does not take keyword arguments" +#~ msgid "function doesn't take keyword arguments" #~ msgstr "Funktion akzeptiert keine Schlüsselwort-Argumente" #~ msgid "function is implemented for scalars and ndarrays only" @@ -6401,7 +6451,7 @@ msgstr "zi muss die Form (n_section, 2) haben" #~ msgid "name must be a string" #~ msgstr "name muss ein String sein" -#~ msgid "name reused for argument" +#~ msgid "argument name reused" #~ msgstr "Name für Argumente wiederverwendet" #~ msgid "no available NIC" diff --git a/locale/el.po b/locale/el.po index 8eb66311bd74a..396f19d071da5 100644 --- a/locale/el.po +++ b/locale/el.po @@ -83,8 +83,8 @@ msgstr " έξοδος:\n" #: py/objstr.c #, c-format -msgid "%%c requires int or char" -msgstr "%%c απαιτεί ακέραιο ή χαρακτήρα" +msgid "%%c needs int or char" +msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format @@ -173,7 +173,7 @@ msgstr "%q μήκος πρέπει να είναι <= %d" msgid "%q length must be >= %d" msgstr "%q μήκος πρέπει να είναι >= %d" -#: py/modsys.c py/runtime.c +#: py/runtime.c msgid "%q moved from %q to %q" msgstr "%q μετακινήθηκε από το %q στο %q" @@ -324,15 +324,15 @@ msgid "'%q' object does not support '%q'" msgstr "'%q' αντικείμενο δεν υποστηρίζει '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "'%q' αντικείμενο δεν είναι επαναλήπτης" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object is not callable" -msgstr "'%q' αντικείμενο δεν καλείται" +msgid "'%q' object isn't callable" +msgstr "" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "'%q' αντικείμενο δεν είναι επαναληπτικό" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -871,6 +871,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "Δεν μπόρεσε να ρυθμιστεί η διεύθυνση" @@ -883,6 +887,11 @@ msgstr "Δεν μπόρεσε να εκκινηθεί το interrupt, RX κατ msgid "Couldn't allocate decoder" msgstr "Δεν μπόρεσε να δεσμευτεί decoder" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "Σφάλμα εκκίνησης καναλιού DAC" @@ -1313,6 +1322,10 @@ msgstr "" msgid "Invalid MAC address" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "" @@ -1869,6 +1882,10 @@ msgstr "" msgid "Program too long" msgstr "" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "" @@ -1889,6 +1906,26 @@ msgstr "" msgid "RNG Init Error" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2756,6 +2793,10 @@ msgstr "" msgid "can't convert to str implicitly" msgstr "" +#: py/objtype.c +msgid "can't create '%q' instances" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2854,10 +2895,6 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create '%q' instances" -msgstr "" - #: py/objtype.c msgid "cannot create instance" msgstr "" @@ -3172,7 +3209,15 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" +msgstr "" + +#: py/objstr.c +msgid "format string didn't convert all arguments" +msgstr "" + +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" #: py/objdeque.c @@ -3631,7 +3676,7 @@ msgid "must use keyword argument for key function" msgstr "" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "" #: py/runtime.c @@ -3721,7 +3766,7 @@ msgid "non-default argument follows default argument" msgstr "" #: py/objstr.c -msgid "non-hex digit found" +msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c @@ -3740,14 +3785,6 @@ msgstr "" msgid "not a constant" msgstr "" -#: py/objstr.c -msgid "not all arguments converted during string formatting" -msgstr "" - -#: py/objstr.c -msgid "not enough arguments for format string" -msgstr "" - #: extmod/ulab/code/numpy/carray/carray_tools.c msgid "not implemented for complex dtype" msgstr "" @@ -3810,10 +3847,6 @@ msgstr "" msgid "object with buffer protocol required" msgstr "" -#: py/objstr.c -msgid "odd-length string" -msgstr "" - #: supervisor/shared/web_workflow/web_workflow.c msgid "off" msgstr "" @@ -4002,10 +4035,6 @@ msgstr "" msgid "pull masks conflict with direction masks" msgstr "" -#: py/parse.c -msgid "raw f-strings are not supported" -msgstr "" - #: extmod/ulab/code/numpy/fft/fft_tools.c msgid "real and imaginary parts must be of equal length" msgstr "" @@ -4272,11 +4301,11 @@ msgid "tx and rx cannot both be None" msgstr "" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "" #: py/runtime.c @@ -4480,6 +4509,13 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, c-format +#~ msgid "%%c requires int or char" +#~ msgstr "%%c απαιτεί ακέραιο ή χαρακτήρα" + +#~ msgid "'%q' object is not callable" +#~ msgstr "'%q' αντικείμενο δεν καλείται" + #~ msgid "Cannot remount '/' when visible via USB." #~ msgstr "Δεν μπορεί να γίνει remount του '/' όταν είναι ορατό μέσω USB." @@ -4600,7 +4636,7 @@ msgstr "" #~ msgid "'continue' outside loop" #~ msgstr "'continue' εκτός επανάληψης" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "" #~ "'coroutine' αντικείμενο δεν μπορεί να χρησιμοποιηθεί σαν επαναλήπτης" diff --git a/locale/en_GB.po b/locale/en_GB.po index f62a09e1db378..8d640a3c68058 100644 --- a/locale/en_GB.po +++ b/locale/en_GB.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2025-04-25 15:04+0000\n" +"PO-Revision-Date: 2025-06-15 23:04+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: none\n" "Language: en_GB\n" @@ -322,16 +322,16 @@ msgid "'%q' object does not support '%q'" msgstr "'%q' object does not support '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" -msgstr "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" +msgstr "'%q' object isn't an iterator" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c msgid "'%q' object is not callable" msgstr "'%q' object is not callable" #: py/runtime.c -msgid "'%q' object is not iterable" -msgstr "'%q' object is not iterable" +msgid "'%q' object isn't iterable" +msgstr "'%q' object isn't iterable" #: py/emitinlinethumb.c py/emitinlinextensa.c #, c-format @@ -865,6 +865,10 @@ msgstr "Coordinate arrays have different lengths" msgid "Coordinate arrays types have different sizes" msgstr "Coordinate arrays types have different sizes" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "Could not publish to ROS topic" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "Could not set address" @@ -877,6 +881,11 @@ msgstr "Could not start interrupt, RX busy" msgid "Couldn't allocate decoder" msgstr "Couldn't allocate decoder" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "Critical ROS failure during soft reboot, reset required: %d" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "DAC channel init error" @@ -1306,6 +1315,10 @@ msgstr "Invalid BSSID" msgid "Invalid MAC address" msgstr "Invalid MAC address" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "Invalid ROS domain ID" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Invalid argument" @@ -1865,6 +1878,10 @@ msgstr "Program size invalid" msgid "Program too long" msgstr "Program too long" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "Publishers can only be created from a parent node" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "Pull not used when direction is output." @@ -1885,6 +1902,26 @@ msgstr "RNG deinit Error" msgid "RNG Init Error" msgstr "RNG init Error" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "ROS failed to initialise. Is agent connected?" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "ROS internal setup failure" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "ROS memory allocator failure" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "ROS node failed to initialise" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "ROS topic failed to initialise" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2098,7 +2135,7 @@ msgstr "Tile width must exactly divide bitmap width" #: shared-module/tilepalettemapper/TilePaletteMapper.c msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" +msgstr "TilePaletteMapper may only be bound to a TileGrid once" #: shared-bindings/alarm/time/TimeAlarm.c msgid "Time is in the past." @@ -2393,7 +2430,7 @@ msgstr "Wi-Fi: " #: ports/raspberrypi/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "WiFi is not enabled" -msgstr "" +msgstr "WiFi is not enabled" #: main.c msgid "Woken up by alarm.\n" @@ -3180,8 +3217,8 @@ msgid "format" msgstr "format" #: py/objstr.c -msgid "format requires a dict" -msgstr "format requires a dict" +msgid "format needs a dict" +msgstr "format needs a dict" #: py/objdeque.c msgid "full" @@ -3639,8 +3676,8 @@ msgid "must use keyword argument for key function" msgstr "must use keyword argument for key function" #: py/runtime.c -msgid "name '%q' is not defined" -msgstr "name '%q' is not defined" +msgid "name '%q' isn't defined" +msgstr "name '%q' isn't defined" #: py/runtime.c msgid "name not defined" @@ -4280,12 +4317,12 @@ msgid "tx and rx cannot both be None" msgstr "tx and rx cannot both be None" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" -msgstr "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" +msgstr "type '%q' isn't an acceptable base type" #: py/objtype.c -msgid "type is not an acceptable base type" -msgstr "type is not an acceptable base type" +msgid "type isn't an acceptable base type" +msgstr "type isn't an acceptable base type" #: py/runtime.c msgid "type object '%q' has no attribute '%q'" @@ -4808,8 +4845,8 @@ msgstr "zi must be of shape (n_section, 2)" #~ msgid "'continue' outside loop" #~ msgstr "'continue' outside loop" -#~ msgid "'coroutine' object is not an iterator" -#~ msgstr "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" +#~ msgstr "'coroutine' object isn't an iterator" #~ msgid "(x,y) integers required" #~ msgstr "(x,y) integers required" @@ -5679,8 +5716,8 @@ msgstr "zi must be of shape (n_section, 2)" #~ msgid "first argument must be an iterable" #~ msgstr "first argument must be an iterable" -#~ msgid "function does not take keyword arguments" -#~ msgstr "function does not take keyword arguments" +#~ msgid "function doesn't take keyword arguments" +#~ msgstr "function doesn't take keyword arguments" #~ msgid "incompatible native .mpy architecture" #~ msgstr "incompatible native .mpy architecture" @@ -5745,8 +5782,8 @@ msgstr "zi must be of shape (n_section, 2)" #~ msgid "maximum number of dimensions is 4" #~ msgstr "maximum number of dimensions is 4" -#~ msgid "name reused for argument" -#~ msgstr "name reused for argument" +#~ msgid "argument name reused" +#~ msgstr "argument name reused" #~ msgid "no available NIC" #~ msgstr "no available NIC" diff --git a/locale/en_US.po b/locale/en_US.po index e9344480c7675..f621d0aa19aee 100644 --- a/locale/en_US.po +++ b/locale/en_US.po @@ -274,7 +274,7 @@ msgid "'%q' object does not support '%q'" msgstr "" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -282,7 +282,7 @@ msgid "'%q' object is not callable" msgstr "" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -3068,7 +3068,7 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "" #: py/objdeque.c @@ -3538,7 +3538,7 @@ msgid "must use keyword argument for key function" msgstr "" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "" #: py/runtime.c @@ -4166,11 +4166,11 @@ msgid "tx and rx cannot both be None" msgstr "" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "" #: py/runtime.c diff --git a/locale/en_x_pirate.po b/locale/en_x_pirate.po index f7b682d56266b..17cac9cb0fb22 100644 --- a/locale/en_x_pirate.po +++ b/locale/en_x_pirate.po @@ -274,7 +274,7 @@ msgid "'%q' object does not support '%q'" msgstr "" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -282,7 +282,7 @@ msgid "'%q' object is not callable" msgstr "" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -3070,7 +3070,7 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "" #: py/objdeque.c @@ -3540,7 +3540,7 @@ msgid "must use keyword argument for key function" msgstr "" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "" #: py/runtime.c @@ -4168,11 +4168,11 @@ msgid "tx and rx cannot both be None" msgstr "" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "" #: py/runtime.c diff --git a/locale/es.po b/locale/es.po index 065782c2b07e6..ef8af2bddbaa7 100644 --- a/locale/es.po +++ b/locale/es.po @@ -8,15 +8,15 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2025-02-09 17:02+0000\n" -"Last-Translator: karlos g liberal \n" +"PO-Revision-Date: 2025-06-09 12:01+0000\n" +"Last-Translator: MAE \n" "Language-Team: \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.10-dev\n" +"X-Generator: Weblate 5.12-dev\n" #: main.c msgid "" @@ -119,7 +119,7 @@ msgstr "%q fallo: %d" #: shared-module/audiodelays/MultiTapDelay.c msgid "%q in %q must be of type %q or %q, not %q" -msgstr "" +msgstr "%q en %q debe ser de tipo %q o %q, no %q" #: py/argcheck.c shared-module/audiofilters/Filter.c msgid "%q in %q must be of type %q, not %q" @@ -324,7 +324,7 @@ msgid "'%q' object does not support '%q'" msgstr "objeto '%q' no tiene capacidad '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "objeto '%q' no es un iterador" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -332,7 +332,7 @@ msgid "'%q' object is not callable" msgstr "objeto '%q' no es llamable" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "objeto '%q' no es iterable" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -836,7 +836,7 @@ msgstr "No se puede manejar la partición en una subclase" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" +msgstr "No se puede utilizar GPIO0..15 junto con GPIO32..47" #: ports/nordic/common-hal/alarm/pin/PinAlarm.c msgid "Cannot wake on pin edge, only level" @@ -874,6 +874,10 @@ msgstr "Las matrices de coordenadas tienen diferentes longitudes" msgid "Coordinate arrays types have different sizes" msgstr "Las matrices de coordenadas tienen diferentes tamaños" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "No se puede definir la dirección" @@ -886,6 +890,11 @@ msgstr "No se pudo iniciar la interrupción, RX ocupado" msgid "Couldn't allocate decoder" msgstr "No se pudo encontrar el decodificador" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "Error de inicio del canal DAC" @@ -1071,7 +1080,7 @@ msgstr "No se puede liberar el mutex, err 0x%04x" #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" -msgstr "" +msgstr "Fallo al establecer el nombre de host" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to start async audio" @@ -1328,6 +1337,10 @@ msgstr "BSSID inválido" msgid "Invalid MAC address" msgstr "Dirección MAC inválida" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Argumento inválido" @@ -1611,7 +1624,7 @@ msgstr "No hay pulldown en el pin; 1Mohm recomendado" #: shared-module/touchio/TouchIn.c msgid "No pullup on pin; 1Mohm recommended" -msgstr "" +msgstr "Sin pullup en el pin; 1Mohm recomendado" #: py/moderrno.c msgid "No space left on device" @@ -1894,6 +1907,10 @@ msgstr "El tamaño del programa no es correcto" msgid "Program too long" msgstr "El programa es demasiado grande" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "Pull no se usa cuando la dirección es output." @@ -1914,6 +1931,26 @@ msgstr "Error de desinicialización de RNG" msgid "RNG Init Error" msgstr "Error de inicialización de RNG" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2430,7 +2467,7 @@ msgstr "Wi-Fi: " #: ports/raspberrypi/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "WiFi is not enabled" -msgstr "" +msgstr "WiFi no está habilitado" #: main.c msgid "Woken up by alarm.\n" @@ -2667,7 +2704,7 @@ msgstr "los bits deben ser 32 o menos" #: shared-bindings/audiofreeverb/Freeverb.c msgid "bits_per_sample must be 16" -msgstr "" +msgstr "bits_per_sample debe ser 16" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c #: shared-bindings/audiodelays/MultiTapDelay.c @@ -3221,7 +3258,7 @@ msgid "format" msgstr "formato" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "format requiere un dict" #: py/objdeque.c @@ -3684,7 +3721,7 @@ msgid "must use keyword argument for key function" msgstr "debe utilizar argumento de palabra clave para la función clave" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "name '%q' no esta definido" #: py/runtime.c @@ -4105,7 +4142,7 @@ msgstr "rsplit(None,n)" #: shared-bindings/audiofreeverb/Freeverb.c msgid "samples_signed must be true" -msgstr "" +msgstr "samples_signed debe ser true" #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c #: ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -4327,11 +4364,11 @@ msgid "tx and rx cannot both be None" msgstr "ambos tx y rx no pueden ser None" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "type '%q' no es un tipo de base aceptable" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "type no es un tipo de base aceptable" #: py/runtime.c @@ -4892,13 +4929,13 @@ msgstr "zi debe ser una forma (n_section,2)" #~ msgid "'%s' object does not support item deletion" #~ msgstr "objeto '%s' no soporta la eliminación de elementos" -#~ msgid "'%s' object is not an iterator" +#~ msgid "'%s' object isn't an iterator" #~ msgstr "objeto '%s' no es un iterator" #~ msgid "'%s' object is not callable" #~ msgstr "objeto '%s' no puede ser llamado" -#~ msgid "'%s' object is not iterable" +#~ msgid "'%s' object isn't iterable" #~ msgstr "objeto '%s' no es iterable" #~ msgid "'%s' object is not subscriptable" @@ -4916,7 +4953,7 @@ msgstr "zi debe ser una forma (n_section,2)" #~ msgid "'continue' outside loop" #~ msgstr "'continue' fuera de un bucle" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "el objeto 'coroutine' no es un iterador" #~ msgid "64 bit types" @@ -6376,7 +6413,7 @@ msgstr "zi debe ser una forma (n_section,2)" #~ msgid "frequency can only be either 80Mhz or 160MHz" #~ msgstr "la frecuencia solo puede ser 80MHz ó 160MHz" -#~ msgid "function does not take keyword arguments" +#~ msgid "function doesn't take keyword arguments" #~ msgstr "la función no tiene argumentos por palabra clave" #~ msgid "function is implemented for scalars and ndarrays only" @@ -6500,7 +6537,7 @@ msgstr "zi debe ser una forma (n_section,2)" #~ msgid "name must be a string" #~ msgstr "name debe de ser un string" -#~ msgid "name reused for argument" +#~ msgid "argument name reused" #~ msgstr "name reusado para argumento" #~ msgid "no available NIC" diff --git a/locale/fil.po b/locale/fil.po index 3069ed78c1dd5..7647d79c81c9f 100644 --- a/locale/fil.po +++ b/locale/fil.po @@ -313,7 +313,7 @@ msgid "'%q' object does not support '%q'" msgstr "" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -321,7 +321,7 @@ msgid "'%q' object is not callable" msgstr "" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -857,6 +857,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "" @@ -869,6 +873,11 @@ msgstr "" msgid "Couldn't allocate decoder" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "" @@ -1299,6 +1308,10 @@ msgstr "" msgid "Invalid MAC address" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Maling argumento" @@ -1858,6 +1871,10 @@ msgstr "" msgid "Program too long" msgstr "" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "Pull hindi ginagamit kapag ang direksyon ay output." @@ -1878,6 +1895,26 @@ msgstr "Error sa RNG DeInit" msgid "RNG Init Error" msgstr "Error sa RNG Init" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -3173,7 +3210,7 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "kailangan ng format ng dict" #: py/objdeque.c @@ -3635,7 +3672,7 @@ msgid "must use keyword argument for key function" msgstr "dapat gumamit ng keyword argument para sa key function" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "name '%q' ay hindi defined" #: py/runtime.c @@ -4276,11 +4313,11 @@ msgid "tx and rx cannot both be None" msgstr "tx at rx hindi pwedeng parehas na None" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "hindi maari ang type na '%q' para sa base type" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "hindi puede ang type para sa base type" #: py/runtime.c @@ -4596,13 +4633,13 @@ msgstr "" #~ msgid "'%s' object does not support item deletion" #~ msgstr "'%s' object ay hindi sumusuporta sa pagtanggal ng item" -#~ msgid "'%s' object is not an iterator" +#~ msgid "'%s' object isn't an iterator" #~ msgstr "'%s' object ay hindi iterator" #~ msgid "'%s' object is not callable" #~ msgstr "'%s' object hindi matatawag" -#~ msgid "'%s' object is not iterable" +#~ msgid "'%s' object isn't iterable" #~ msgstr "'%s' object ay hindi ma i-iterable" #~ msgid "'%s' object is not subscriptable" @@ -5273,7 +5310,7 @@ msgstr "" #~ msgid "frequency can only be either 80Mhz or 160MHz" #~ msgstr "ang frequency ay dapat 80Mhz or 160MHz lamang" -#~ msgid "function does not take keyword arguments" +#~ msgid "function doesn't take keyword arguments" #~ msgstr "ang function ay hindi kumukuha ng mga argumento ng keyword" #~ msgid "impossible baudrate" @@ -5343,7 +5380,7 @@ msgstr "" #~ msgid "name must be a string" #~ msgstr "ang keywords dapat strings" -#~ msgid "name reused for argument" +#~ msgid "argument name reused" #~ msgstr "name muling ginamit para sa argument" #~ msgid "no available NIC" diff --git a/locale/fr.po b/locale/fr.po index e7516a609da30..eee6b141a7473 100644 --- a/locale/fr.po +++ b/locale/fr.po @@ -8,15 +8,15 @@ msgstr "" "Project-Id-Version: 0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2025-02-19 11:46+0000\n" -"Last-Translator: Noel Gaetan \n" +"PO-Revision-Date: 2025-06-16 14:49+0000\n" +"Last-Translator: Franck Sauvé \n" "Language-Team: \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.10.1-dev\n" +"X-Generator: Weblate 5.12-dev\n" #: main.c msgid "" @@ -118,7 +118,7 @@ msgstr "Échec de %q : %d" #: shared-module/audiodelays/MultiTapDelay.c msgid "%q in %q must be of type %q or %q, not %q" -msgstr "" +msgstr "%q dans %q doit être du type %q ou %q, pas %q" #: py/argcheck.c shared-module/audiofilters/Filter.c msgid "%q in %q must be of type %q, not %q" @@ -325,7 +325,7 @@ msgid "'%q' object does not support '%q'" msgstr "l'objet '%q' ne supporte pas '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "l'objet '%q' n'est pas un itérateur" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -333,7 +333,7 @@ msgid "'%q' object is not callable" msgstr "l'objet '%q' ne peut pas être appelé" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "l'objet '%q' n'est pas itérable" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -824,6 +824,7 @@ msgstr "Impossible d'enregistrer vers un fichier" #: shared-module/storage/__init__.c msgid "Cannot remount path when visible via USB." msgstr "" +"Impossible de remonter le chemin d'accès lorsqu'il est visible via USB." #: shared-bindings/digitalio/DigitalInOut.c msgid "Cannot set value when direction is input." @@ -880,6 +881,10 @@ msgstr "Les tableaux de coordonnées sont de longueur différentes" msgid "Coordinate arrays types have different sizes" msgstr "Les types des tableaux de coordonnées sont de longueur différentes" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "Ne peut publier sur le Topic ROS" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "Ne peux définir l'adresse" @@ -892,6 +897,11 @@ msgstr "Ne peux lancer l'interruption, RX occupé" msgid "Couldn't allocate decoder" msgstr "Ne peux allouer le décodeur" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "Erreur critique lors du reboot à chaud, reset requis: %d" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "Erreur init du canal DAC" @@ -1079,7 +1089,7 @@ msgstr "Écchec de liberaton du mutex, err 0x%04x" #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" -msgstr "" +msgstr "hostname impossible à initialiser" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to start async audio" @@ -1332,6 +1342,10 @@ msgstr "BSSID invalide" msgid "Invalid MAC address" msgstr "Adresse MAC invalide" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "ROS domain ID invalide" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Paramètre invalide" @@ -1424,7 +1438,7 @@ msgstr "Sécurité MITM n'est pas supportée" #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "MMC/SDIO Clock Error %x" -msgstr "" +msgstr "Erreur d'horloge MMC/SDIO %x" #: shared-bindings/is31fl3741/IS31FL3741.c msgid "Mapping must be a tuple" @@ -1622,7 +1636,7 @@ msgstr "Pas de pulldown sur la broche ; 1Mohm requis" #: shared-module/touchio/TouchIn.c msgid "No pullup on pin; 1Mohm recommended" -msgstr "" +msgstr "Pas de pullup sur la broche ; 1Mohm recommandé" #: py/moderrno.c msgid "No space left on device" @@ -1904,6 +1918,10 @@ msgstr "Taille du programme invalide" msgid "Program too long" msgstr "Programme trop long" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "Les Publishers ne peuvent etre crées que du noeud parent" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "Le tirage 'pull' n'est pas utilisé quand la direction est 'output'." @@ -1924,6 +1942,26 @@ msgstr "Erreur de désinitialisation du RNG" msgid "RNG Init Error" msgstr "Erreur d'initialisation du RNG" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "L'agent est-il connecté? ROS échoue son initialisation" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "ROS échec de configuration interne" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "Erreur d'allocation mémoire ROS" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "ROS node échoue a s'initialiser" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "Le topic ROS échoue à s'initialiser" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2138,7 +2176,7 @@ msgstr "La largeur de la tuile doit diviser exactement la largeur de l'image" #: shared-module/tilepalettemapper/TilePaletteMapper.c msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" +msgstr "TilePaletteMapper ne peut être lié à un TileGrid qu'une seule fois" #: shared-bindings/alarm/time/TimeAlarm.c msgid "Time is in the past." @@ -2439,7 +2477,7 @@ msgstr "Wi-Fi : " #: ports/raspberrypi/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "WiFi is not enabled" -msgstr "" +msgstr "Le WiFi n'est pas activé" #: main.c msgid "Woken up by alarm.\n" @@ -2677,7 +2715,7 @@ msgstr "les bits doivent être 32 ou moins" #: shared-bindings/audiofreeverb/Freeverb.c msgid "bits_per_sample must be 16" -msgstr "" +msgstr "bits_per_sample doit être de 16" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c #: shared-bindings/audiodelays/MultiTapDelay.c @@ -2686,7 +2724,7 @@ msgstr "" #: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c #: shared-bindings/audiomixer/Mixer.c msgid "bits_per_sample must be 8 or 16" -msgstr "'bits_per_sample' doivent être 8 ou 16" +msgstr "bits_per_sample doivent être 8 ou 16" #: py/emitinlinethumb.c msgid "branch not in range" @@ -3238,7 +3276,7 @@ msgid "format" msgstr "format" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "le format requier un dict" #: py/objdeque.c @@ -3703,7 +3741,7 @@ msgid "must use keyword argument for key function" msgstr "doit utiliser un argument nommé pour une fonction key" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "nom '%q' non défini" #: py/runtime.c @@ -4126,7 +4164,7 @@ msgstr "rsplit(None, n)" #: shared-bindings/audiofreeverb/Freeverb.c msgid "samples_signed must be true" -msgstr "" +msgstr "samples_signed doit être vrai" #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c #: ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -4347,11 +4385,11 @@ msgid "tx and rx cannot both be None" msgstr "tx et rx ne peuvent être 'None' tous les deux" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "le type '%q' n'est pas un type de base accepté" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "le type n'est pas un type de base accepté" #: py/runtime.c @@ -4920,13 +4958,13 @@ msgstr "zi doit être de forme (n_section, 2)" #~ msgid "'%s' object does not support item deletion" #~ msgstr "l'objet '%s' ne supporte pas la suppression d'éléments" -#~ msgid "'%s' object is not an iterator" +#~ msgid "'%s' object isn't an iterator" #~ msgstr "l'objet '%s' n'est pas un itérateur" #~ msgid "'%s' object is not callable" #~ msgstr "l'objet '%s' n'est pas appelable" -#~ msgid "'%s' object is not iterable" +#~ msgid "'%s' object isn't iterable" #~ msgstr "l'objet '%s' n'est pas itérable" #~ msgid "'%s' object is not subscriptable" @@ -4944,7 +4982,7 @@ msgstr "zi doit être de forme (n_section, 2)" #~ msgid "'continue' outside loop" #~ msgstr "'continue' dehors d'une boucle" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "L'objet \"coroutine\" n'est pas un itérateur" #~ msgid "(x,y) integers required" @@ -6433,7 +6471,7 @@ msgstr "zi doit être de forme (n_section, 2)" #~ msgid "frequency is read-only for this board" #~ msgstr "la fréquence est en lecture seule pour cette carte" -#~ msgid "function does not take keyword arguments" +#~ msgid "function doesn't take keyword arguments" #~ msgstr "la fonction ne prend pas d'arguments nommés" #~ msgid "function is implemented for scalars and ndarrays only" @@ -6562,7 +6600,7 @@ msgstr "zi doit être de forme (n_section, 2)" #~ msgid "name must be a string" #~ msgstr "les noms doivent être des chaînes de caractère" -#~ msgid "name reused for argument" +#~ msgid "argument name reused" #~ msgstr "nom réutilisé comme paramètre" #~ msgid "no available NIC" diff --git a/locale/hi.po b/locale/hi.po index abffcfe88cb52..8d3912c18bd9d 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -71,7 +71,7 @@ msgstr "" #: py/objstr.c #, c-format -msgid "%%c requires int or char" +msgid "%%c needs int or char" msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -160,7 +160,7 @@ msgstr "" msgid "%q length must be >= %d" msgstr "" -#: py/modsys.c py/runtime.c +#: py/runtime.c msgid "%q moved from %q to %q" msgstr "" @@ -311,15 +311,15 @@ msgid "'%q' object does not support '%q'" msgstr "" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object is not callable" +msgid "'%q' object isn't callable" msgstr "" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -850,6 +850,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "" @@ -862,6 +866,11 @@ msgstr "" msgid "Couldn't allocate decoder" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "" @@ -1289,6 +1298,10 @@ msgstr "" msgid "Invalid MAC address" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "" @@ -1843,6 +1856,10 @@ msgstr "" msgid "Program too long" msgstr "" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "" @@ -1863,6 +1880,26 @@ msgstr "" msgid "RNG Init Error" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2730,6 +2767,10 @@ msgstr "" msgid "can't convert to str implicitly" msgstr "" +#: py/objtype.c +msgid "can't create '%q' instances" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2828,10 +2869,6 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create '%q' instances" -msgstr "" - #: py/objtype.c msgid "cannot create instance" msgstr "" @@ -3146,7 +3183,15 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" +msgstr "" + +#: py/objstr.c +msgid "format string didn't convert all arguments" +msgstr "" + +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" #: py/objdeque.c @@ -3605,7 +3650,7 @@ msgid "must use keyword argument for key function" msgstr "" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "" #: py/runtime.c @@ -3695,7 +3740,7 @@ msgid "non-default argument follows default argument" msgstr "" #: py/objstr.c -msgid "non-hex digit found" +msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c @@ -3714,14 +3759,6 @@ msgstr "" msgid "not a constant" msgstr "" -#: py/objstr.c -msgid "not all arguments converted during string formatting" -msgstr "" - -#: py/objstr.c -msgid "not enough arguments for format string" -msgstr "" - #: extmod/ulab/code/numpy/carray/carray_tools.c msgid "not implemented for complex dtype" msgstr "" @@ -3784,10 +3821,6 @@ msgstr "" msgid "object with buffer protocol required" msgstr "" -#: py/objstr.c -msgid "odd-length string" -msgstr "" - #: supervisor/shared/web_workflow/web_workflow.c msgid "off" msgstr "" @@ -3976,10 +4009,6 @@ msgstr "" msgid "pull masks conflict with direction masks" msgstr "" -#: py/parse.c -msgid "raw f-strings are not supported" -msgstr "" - #: extmod/ulab/code/numpy/fft/fft_tools.c msgid "real and imaginary parts must be of equal length" msgstr "" @@ -4246,11 +4275,11 @@ msgid "tx and rx cannot both be None" msgstr "" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "" #: py/runtime.c diff --git a/locale/it_IT.po b/locale/it_IT.po index 7ef52213ced3d..15ca320be2a91 100644 --- a/locale/it_IT.po +++ b/locale/it_IT.po @@ -313,7 +313,7 @@ msgid "'%q' object does not support '%q'" msgstr "L'oggetto '%q' non supporta '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "L'oggetto '%q' non è un iteratore" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -321,7 +321,7 @@ msgid "'%q' object is not callable" msgstr "L'oggetto '%q' non è richiamabile" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "L'oggetto '%q' non è iterabile" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -856,6 +856,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "" @@ -868,6 +872,11 @@ msgstr "" msgid "Couldn't allocate decoder" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "" @@ -1297,6 +1306,10 @@ msgstr "" msgid "Invalid MAC address" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Argomento non valido" @@ -1856,6 +1869,10 @@ msgstr "" msgid "Program too long" msgstr "" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "" @@ -1876,6 +1893,26 @@ msgstr "" msgid "RNG Init Error" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -3170,7 +3207,7 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "la formattazione richiede un dict" #: py/objdeque.c @@ -3633,7 +3670,7 @@ msgid "must use keyword argument for key function" msgstr "" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "nome '%q'non definito" #: py/runtime.c @@ -4278,11 +4315,11 @@ msgid "tx and rx cannot both be None" msgstr "tx e rx non possono essere entrambi None" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "il tipo '%q' non è un tipo di base accettabile" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "il tipo non è un tipo di base accettabile" #: py/runtime.c @@ -4642,13 +4679,13 @@ msgstr "" #~ msgid "'%s' object does not support item deletion" #~ msgstr "oggeto '%s' non supporta eliminamento di item" -#~ msgid "'%s' object is not an iterator" +#~ msgid "'%s' object isn't an iterator" #~ msgstr "l'oggetto '%s' non è un iteratore" #~ msgid "'%s' object is not callable" #~ msgstr "oggeto '%s' non è chiamabile" -#~ msgid "'%s' object is not iterable" +#~ msgid "'%s' object isn't iterable" #~ msgstr "l'oggetto '%s' non è iterabile" #~ msgid "'%s' object is not subscriptable" @@ -4664,7 +4701,7 @@ msgstr "" #~ msgid "'continue' outside loop" #~ msgstr "'continue' fuori del ciclo" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "L'oggetto 'coroutine' non è un iteratore" #~ msgid "64 bit types" @@ -5327,7 +5364,7 @@ msgstr "" #~ msgid "frequency can only be either 80Mhz or 160MHz" #~ msgstr "la frequenza può essere o 80Mhz o 160Mhz" -#~ msgid "function does not take keyword arguments" +#~ msgid "function doesn't take keyword arguments" #~ msgstr "la funzione non prende argomenti nominati" #~ msgid "impossible baudrate" @@ -5394,7 +5431,7 @@ msgstr "" #~ msgid "name must be a string" #~ msgstr "argomenti nominati devono essere stringhe" -#~ msgid "name reused for argument" +#~ msgid "argument name reused" #~ msgstr "nome riutilizzato come argomento" #, fuzzy diff --git a/locale/ja.po b/locale/ja.po index ef29c947b1316..bd768e6bd8e54 100644 --- a/locale/ja.po +++ b/locale/ja.po @@ -324,7 +324,7 @@ msgid "'%q' object does not support '%q'" msgstr "'%q' オブジェクトは '%q' に対応していません" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "オブジェクト'%q'はイテレータではありません" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -332,7 +332,7 @@ msgid "'%q' object is not callable" msgstr "オブジェクト'%q'は呼び出し可能ではありません" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "オブジェクト'%q'はイテレート可能ではありません" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -867,6 +867,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "アドレスをセットできません" @@ -879,6 +883,11 @@ msgstr "割り込みをスタートできません。RXビジー" msgid "Couldn't allocate decoder" msgstr "デコーダを確保できません" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "DACチャネル初期化エラー" @@ -1306,6 +1315,10 @@ msgstr "不正なBSSID" msgid "Invalid MAC address" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "不正な引数" @@ -1865,6 +1878,10 @@ msgstr "" msgid "Program too long" msgstr "" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "方向がoutputのときpullは使われません" @@ -1885,6 +1902,26 @@ msgstr "RNG解体エラー" msgid "RNG Init Error" msgstr "乱数生成器の初期化エラー" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -3173,7 +3210,7 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "formatにはdictが必要" #: py/objdeque.c @@ -3633,7 +3670,7 @@ msgid "must use keyword argument for key function" msgstr "" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "名前 '%q' は定義されていません" #: py/runtime.c @@ -4274,11 +4311,11 @@ msgid "tx and rx cannot both be None" msgstr "txとrxを両方ともNoneにできません" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "型'%q'はベース型として使えません" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "この型はベース型にできません" #: py/runtime.c @@ -4649,7 +4686,7 @@ msgstr "" #~ msgid "'continue' outside loop" #~ msgstr "ループ外でのcontinue" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "'coroutine' オブジェクトはイテレータではありません" #~ msgid "Address type out of range" @@ -5249,7 +5286,7 @@ msgstr "" #~ msgid "n must be between 0, and 9" #~ msgstr "nは0から9まで" -#~ msgid "name reused for argument" +#~ msgid "argument name reused" #~ msgstr "引数で名前が再利用されています" #~ msgid "no available NIC" diff --git a/locale/ko.po b/locale/ko.po index a06ff26372503..6b1d45d01134e 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -81,8 +81,8 @@ msgstr " 산출:\n" #: py/objstr.c #, c-format -msgid "%%c requires int or char" -msgstr "%%c 전수(int)또는 캐릭터(char)필요합니다" +msgid "%%c needs int or char" +msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format @@ -171,7 +171,7 @@ msgstr "%q 길이는 <= %d>여야 합니다" msgid "%q length must be >= %d" msgstr "%q 길이는 >= %d이어야 합니다" -#: py/modsys.c py/runtime.c +#: py/runtime.c #, fuzzy msgid "%q moved from %q to %q" msgstr "%q가 %q에서 %q로 이동했습니다" @@ -334,15 +334,15 @@ msgid "'%q' object does not support '%q'" msgstr "'%q' 개체가 '%q'를 지원하지 않습니다" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "'%q' 개체가 iterator가 아닙니다" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object is not callable" -msgstr "'%q' 개체를 호출할 수 없습니다" +msgid "'%q' object isn't callable" +msgstr "" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "'%q' 개체를 사용할 수 없습니다" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -895,6 +895,10 @@ msgstr "좌표 배열의 길이가 다릅니다" msgid "Coordinate arrays types have different sizes" msgstr "좌표 배열 유형은 크기가 다릅니다" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "주소를 설정할 수 없습니다" @@ -907,6 +911,11 @@ msgstr "인터럽트를 시작할 수 없습니다, RX가 사용 중입니다" msgid "Couldn't allocate decoder" msgstr "디코더를 할당할 수 없습니다" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "DAC 채널 초기화 오류" @@ -1341,6 +1350,10 @@ msgstr "잘못된 BSSID" msgid "Invalid MAC address" msgstr "잘못된 MAC 주소" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "잘못된 인수" @@ -1917,6 +1930,10 @@ msgstr "프로그램 크기가 잘못되었습니다" msgid "Program too long" msgstr "프로그램이 너무 깁니다" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c #, fuzzy msgid "Pull not used when direction is output." @@ -1938,6 +1955,26 @@ msgstr "RNG DeInit 오류" msgid "RNG Init Error" msgstr "RNG 초기화 오류" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2806,6 +2843,10 @@ msgstr "" msgid "can't convert to str implicitly" msgstr "" +#: py/objtype.c +msgid "can't create '%q' instances" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2904,10 +2945,6 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create '%q' instances" -msgstr "" - #: py/objtype.c msgid "cannot create instance" msgstr "" @@ -3222,7 +3259,15 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" +msgstr "" + +#: py/objstr.c +msgid "format string didn't convert all arguments" +msgstr "" + +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" #: py/objdeque.c @@ -3681,7 +3726,7 @@ msgid "must use keyword argument for key function" msgstr "" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "" #: py/runtime.c @@ -3771,7 +3816,7 @@ msgid "non-default argument follows default argument" msgstr "" #: py/objstr.c -msgid "non-hex digit found" +msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c @@ -3790,14 +3835,6 @@ msgstr "" msgid "not a constant" msgstr "" -#: py/objstr.c -msgid "not all arguments converted during string formatting" -msgstr "" - -#: py/objstr.c -msgid "not enough arguments for format string" -msgstr "" - #: extmod/ulab/code/numpy/carray/carray_tools.c msgid "not implemented for complex dtype" msgstr "" @@ -3860,10 +3897,6 @@ msgstr "" msgid "object with buffer protocol required" msgstr "" -#: py/objstr.c -msgid "odd-length string" -msgstr "" - #: supervisor/shared/web_workflow/web_workflow.c msgid "off" msgstr "" @@ -4052,10 +4085,6 @@ msgstr "" msgid "pull masks conflict with direction masks" msgstr "" -#: py/parse.c -msgid "raw f-strings are not supported" -msgstr "" - #: extmod/ulab/code/numpy/fft/fft_tools.c msgid "real and imaginary parts must be of equal length" msgstr "" @@ -4322,11 +4351,11 @@ msgid "tx and rx cannot both be None" msgstr "" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "" #: py/runtime.c @@ -4530,6 +4559,13 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, c-format +#~ msgid "%%c requires int or char" +#~ msgstr "%%c 전수(int)또는 캐릭터(char)필요합니다" + +#~ msgid "'%q' object is not callable" +#~ msgstr "'%q' 개체를 호출할 수 없습니다" + #~ msgid "Cannot remount '/' when visible via USB." #~ msgstr "USB를 통해 표시될 때 '/'은 다시 마운트할 수 없습니다." @@ -4658,13 +4694,13 @@ msgstr "" #~ msgid "'%s' object does not support item deletion" #~ msgstr "'%s' 은 삭제할 수 없습니다" -#~ msgid "'%s' object is not an iterator" +#~ msgid "'%s' object isn't an iterator" #~ msgstr "'%s' 은 수정할 수 없습니다" #~ msgid "'%s' object is not callable" #~ msgstr "'%s' 을 검색 할 수 없습니다" -#~ msgid "'%s' object is not iterable" +#~ msgid "'%s' object isn't iterable" #~ msgstr "'%s' 은 변경할 수 없습니다" #~ msgid "'break' outside loop" diff --git a/locale/nl.po b/locale/nl.po index ade9593a2cea1..5cd4898abf862 100644 --- a/locale/nl.po +++ b/locale/nl.po @@ -6,15 +6,15 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2023-11-16 15:03+0000\n" -"Last-Translator: Jeff Epler \n" +"PO-Revision-Date: 2025-06-09 12:01+0000\n" +"Last-Translator: MAE \n" "Language-Team: none\n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.2\n" +"X-Generator: Weblate 5.12-dev\n" #: main.c msgid "" @@ -61,7 +61,7 @@ msgstr "" #: main.c msgid " not found.\n" -msgstr "" +msgstr " niet gevonden.\n" #: main.c msgid " output:\n" @@ -309,7 +309,7 @@ msgid "'%q' object does not support '%q'" msgstr "'%q' object ondersteunt geen '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "'%q' object is geen iterator" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -317,7 +317,7 @@ msgid "'%q' object is not callable" msgstr "'%q' object is niet aanroepbaar" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "'%q' object is niet itereerbaar" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -558,7 +558,7 @@ msgstr "Heeft al een luisteraar voor 'all-matches'" #: ports/espressif/common-hal/_bleio/__init__.c msgid "Already in progress" -msgstr "" +msgstr "Al in uitvoering" #: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c @@ -612,7 +612,7 @@ msgstr "" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c msgid "Audio source error" -msgstr "" +msgstr "Audiobronfout" #: shared-bindings/wifi/Radio.c msgid "AuthMode.OPEN is not used with password" @@ -701,7 +701,7 @@ msgstr "Buffer is %d bytes te klein" #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/struct/__init__.c shared-module/struct/__init__.c msgid "Buffer too small" -msgstr "" +msgstr "Buffer te klein" #: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c @@ -853,6 +853,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "Kan adres niet zetten" @@ -865,6 +869,11 @@ msgstr "Kan interrupt niet starten, RX is bezig" msgid "Couldn't allocate decoder" msgstr "Kan decoder niet alloceren" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "DAC kanaal Init Fout" @@ -925,7 +934,7 @@ msgstr "Beeldscherm rotatie moet in stappen van 90 graden" #: main.c msgid "Done" -msgstr "" +msgstr "Gedaan" #: shared-bindings/digitalio/DigitalInOut.c msgid "Drive mode not used when direction is input." @@ -1064,7 +1073,7 @@ msgstr "Bestand bestaat" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c #: shared-module/os/getenv.c msgid "File not found" -msgstr "" +msgstr "Bestand niet gevonden" #: ports/atmel-samd/common-hal/canio/Listener.c #: ports/espressif/common-hal/canio/Listener.c @@ -1075,11 +1084,11 @@ msgstr "Filters zijn te complex" #: ports/espressif/common-hal/dualbank/__init__.c msgid "Firmware is duplicate" -msgstr "" +msgstr "Firmware is duplicaat" #: ports/espressif/common-hal/dualbank/__init__.c msgid "Firmware is invalid" -msgstr "" +msgstr "Firmware is ongeldig" #: ports/espressif/common-hal/dualbank/__init__.c msgid "Firmware is too big" @@ -1113,7 +1122,7 @@ msgstr "" #: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" -msgstr "" +msgstr "Generieke mislukking" #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c @@ -1215,7 +1224,7 @@ msgstr "Interne define fout" #: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c msgid "Internal error" -msgstr "" +msgstr "Interne fout" #: shared-module/rgbmatrix/RGBMatrix.c #, c-format @@ -1241,7 +1250,7 @@ msgstr "" #: supervisor/shared/safe_mode.c msgid "Interrupt error." -msgstr "" +msgstr "Interruptfout." #: shared-module/jpegio/JpegDecoder.c msgid "Interrupted by output function" @@ -1282,7 +1291,7 @@ msgstr "Ongeldige ADC Unit waarde" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid BLE parameter" -msgstr "" +msgstr "Ongeldige BLE-parameter" #: shared-bindings/wifi/Radio.c msgid "Invalid BSSID" @@ -1290,6 +1299,10 @@ msgstr "Ongeldig BSSID" #: shared-bindings/wifi/Radio.c msgid "Invalid MAC address" +msgstr "Ongeldig MAC-adres" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c @@ -1312,7 +1325,7 @@ msgstr "" #: shared-module/msgpack/__init__.c msgid "Invalid format" -msgstr "" +msgstr "Ongeldig formaat" #: shared-module/audiocore/WaveFile.c msgid "Invalid format chunk size" @@ -1329,7 +1342,7 @@ msgstr "" #: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" -msgstr "" +msgstr "Ongeldige grootte" #: shared-module/ssl/SSLSocket.c msgid "Invalid socket for TLS" @@ -1338,11 +1351,11 @@ msgstr "" #: ports/espressif/common-hal/espidf/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid state" -msgstr "" +msgstr "Ongeldige staat" #: shared-module/os/getenv.c msgid "Invalid unicode escape" -msgstr "" +msgstr "Ongeldige unicode escape" #: shared-bindings/aesio/aes.c msgid "Key must be 16, 24, or 32 bytes long" @@ -1350,7 +1363,7 @@ msgstr "Sleutel moet 16, 24, of 32 bytes lang zijn" #: shared-module/os/getenv.c msgid "Key not found" -msgstr "" +msgstr "Sleutel niet gevonden" #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" @@ -1855,6 +1868,10 @@ msgstr "" msgid "Program too long" msgstr "" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "Pull niet gebruikt wanneer de richting output is." @@ -1875,10 +1892,30 @@ msgstr "RNG DeInit Fout" msgid "RNG Init Error" msgstr "RNG Init Fout" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" -msgstr "" +msgstr "RS485" #: ports/espressif/common-hal/busio/UART.c #: ports/mimxrt10xx/common-hal/busio/UART.c @@ -1910,7 +1947,7 @@ msgstr "" #: supervisor/shared/bluetooth/bluetooth.c msgid "Reconnecting" -msgstr "" +msgstr "Opnieuw aansluiten" #: shared-bindings/epaperdisplay/EPaperDisplay.c msgid "Refresh too soon" @@ -2378,7 +2415,7 @@ msgstr "" #: ports/raspberrypi/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "WiFi is not enabled" -msgstr "" +msgstr "WiFi is niet ingeschakeld" #: main.c msgid "Woken up by alarm.\n" @@ -3165,7 +3202,7 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "format vereist een dict" #: py/objdeque.c @@ -3627,7 +3664,7 @@ msgid "must use keyword argument for key function" msgstr "voor sleutelfunctie moet een trefwoordargument gebruikt worden" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "naam '%q' is niet gedefinieerd" #: py/runtime.c @@ -4268,11 +4305,11 @@ msgid "tx and rx cannot both be None" msgstr "tx en rx kunnen niet beiden None zijn" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "type '%q' is geen aanvaardbaar basistype" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "type is geen aanvaardbaar basistype" #: py/runtime.c @@ -4416,7 +4453,7 @@ msgstr "breedte moet groter dan nul zijn" #: ports/raspberrypi/common-hal/wifi/Monitor.c msgid "wifi.Monitor not available" -msgstr "" +msgstr "wifi.monitor niet beschikbaar" #: shared-bindings/_bleio/Adapter.c msgid "window must be <= interval" @@ -4704,13 +4741,13 @@ msgstr "zi moet vorm (n_section, 2) hebben" #~ msgid "'%s' object does not support item deletion" #~ msgstr "'%s' object ondersteunt item verwijdering niet" -#~ msgid "'%s' object is not an iterator" +#~ msgid "'%s' object isn't an iterator" #~ msgstr "'%s' object is geen iterator" #~ msgid "'%s' object is not callable" #~ msgstr "'%s' object is niet aanroepbaar" -#~ msgid "'%s' object is not iterable" +#~ msgid "'%s' object isn't iterable" #~ msgstr "'%s' object is niet itereerbaar" #~ msgid "'%s' object is not subscriptable" @@ -4728,7 +4765,7 @@ msgstr "zi moet vorm (n_section, 2) hebben" #~ msgid "'continue' outside loop" #~ msgstr "'continue' buiten de loop" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "'coroutine' object is geen iterator" #~ msgid "ADC2 is being used by WiFi" @@ -5505,7 +5542,7 @@ msgstr "zi moet vorm (n_section, 2) hebben" #~ msgid "firstbit must be MSB" #~ msgstr "het eerste bit moet het MSB zijn" -#~ msgid "function does not take keyword arguments" +#~ msgid "function doesn't take keyword arguments" #~ msgstr "functie accepteert geen keyword argumenten" #~ msgid "function is implemented for scalars and ndarrays only" @@ -5583,7 +5620,7 @@ msgstr "zi moet vorm (n_section, 2) hebben" #~ msgid "n must be between 0, and 9" #~ msgstr "n moet tussen 0 en 9 liggen" -#~ msgid "name reused for argument" +#~ msgid "argument name reused" #~ msgstr "naam hergebruikt voor argument" #~ msgid "no available NIC" diff --git a/locale/pl.po b/locale/pl.po index 0c565f72d8d1c..9e2cf3a4096ea 100644 --- a/locale/pl.po +++ b/locale/pl.po @@ -7,16 +7,16 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2023-11-16 15:03+0000\n" -"Last-Translator: Szymon Jakubiak \n" +"PO-Revision-Date: 2025-06-09 12:01+0000\n" +"Last-Translator: MAE \n" "Language-Team: pl\n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " -"|| n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 5.2\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.12-dev\n" #: main.c msgid "" @@ -317,7 +317,7 @@ msgid "'%q' object does not support '%q'" msgstr "Obiekt '%q' nie wspiera '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "Obiekt '%q' nie jest iteratorem" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -325,7 +325,7 @@ msgid "'%q' object is not callable" msgstr "Obiekt '%q' nie jest wywoływalny" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "Obiekt '%q' nie jest iterowalny" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -864,6 +864,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "Nie można ustawić adresu" @@ -876,6 +880,11 @@ msgstr "Nie można rozpocząć przerwania, RX jest zajęty" msgid "Couldn't allocate decoder" msgstr "Nie udało się przydzielić dekodera" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "Błąd inicjalizacji kanału DAC" @@ -1311,6 +1320,10 @@ msgstr "" msgid "Invalid MAC address" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Zły argument" @@ -1754,7 +1767,7 @@ msgstr "" #: ports/stm/common-hal/pwmio/PWMOut.c msgid "PWM restart" -msgstr "" +msgstr "Ponowne uruchomienie PWM" #: ports/raspberrypi/common-hal/countio/Counter.c msgid "PWM slice already in use" @@ -1770,7 +1783,7 @@ msgstr "" #: shared-module/jpegio/JpegDecoder.c msgid "Parameter error" -msgstr "" +msgstr "Błąd parametru" #: ports/espressif/common-hal/audiobusio/__init__.c msgid "Peripheral in use" @@ -1867,6 +1880,10 @@ msgstr "" #: ports/espressif/common-hal/espulp/ULP.c msgid "Program too long" +msgstr "Program zbyt długi" + +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c @@ -1889,10 +1906,30 @@ msgstr "Błąd RNG DeInit" msgid "RNG Init Error" msgstr "Błąd inicjalizacji RNG" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" -msgstr "" +msgstr "RS485" #: ports/espressif/common-hal/busio/UART.c #: ports/mimxrt10xx/common-hal/busio/UART.c @@ -1924,7 +1961,7 @@ msgstr "Otrzymana odpowiedź była nieprawidłowa" #: supervisor/shared/bluetooth/bluetooth.c msgid "Reconnecting" -msgstr "" +msgstr "Ponowne połączenie" #: shared-bindings/epaperdisplay/EPaperDisplay.c msgid "Refresh too soon" @@ -2009,7 +2046,7 @@ msgstr "" #: ports/cxd56/common-hal/camera/Camera.c msgid "Size not supported" -msgstr "" +msgstr "Rozmiar nieobsługiwany" #: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c #: shared-bindings/nvm/ByteArray.c @@ -2140,7 +2177,7 @@ msgstr "" #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c #: ports/stm/common-hal/alarm/touch/TouchAlarm.c msgid "Touch alarms not available" -msgstr "" +msgstr "Alarmy dotykowe niedostępne" #: py/obj.c msgid "Traceback (most recent call last):\n" @@ -2169,7 +2206,7 @@ msgstr "" #: main.c msgid "UID:" -msgstr "" +msgstr "UID:" #: shared-module/usb_hid/Device.c msgid "USB busy" @@ -2185,7 +2222,7 @@ msgstr "" #: shared-module/usb_hid/Device.c msgid "USB error" -msgstr "" +msgstr "Błąd USB" #: shared-bindings/_bleio/UUID.c msgid "UUID integer value must be 0-0xffff" @@ -2251,7 +2288,7 @@ msgstr "" #: shared-bindings/alarm/SleepMemory.c msgid "Unable to write to sleep_memory." -msgstr "" +msgstr "Nie można zapisać do sleep_memory." #: ports/nordic/common-hal/_bleio/UUID.c msgid "Unexpected nrfx uuid type" @@ -2342,7 +2379,7 @@ msgstr "" #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/espressif/common-hal/dualbank/__init__.c msgid "Update failed" -msgstr "" +msgstr "Aktualizacja nie powiodła się" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c @@ -2381,16 +2418,21 @@ msgid "" "\n" "To list built-in modules type `help(\"modules\")`.\n" msgstr "" +"Witamy w Adafruit CircuitPython %s!\n" +"\n" +"Odwiedź circuitpython.org po więcej informacji.\n" +"\n" +"Aby wyświetlić listę wbudowanych modułów wpisz `help(„modules”)`.\n" #: supervisor/shared/web_workflow/web_workflow.c msgid "Wi-Fi: " -msgstr "" +msgstr "Wi-Fi: " #: ports/espressif/common-hal/wifi/Radio.c #: ports/raspberrypi/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "WiFi is not enabled" -msgstr "" +msgstr "WiFi nie jest włączone" #: main.c msgid "Woken up by alarm.\n" @@ -2611,7 +2653,7 @@ msgstr "brak dwu-argumentowego operatora %q" #: ports/espressif/common-hal/audiobusio/PDMIn.c msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" +msgstr "bit_depth musi wynosić 8, 16, 24 lub 32." #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" @@ -2623,11 +2665,11 @@ msgstr "" #: extmod/modrandom.c msgid "bits must be 32 or less" -msgstr "" +msgstr "bitów musi wynosić 32 lub mniej" #: shared-bindings/audiofreeverb/Freeverb.c msgid "bits_per_sample must be 16" -msgstr "" +msgstr "bits_per_sample musi wynosić 16" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c #: shared-bindings/audiodelays/MultiTapDelay.c @@ -2838,7 +2880,7 @@ msgstr "" #: extmod/modasyncio.c msgid "can't wait" -msgstr "" +msgstr "nie mogę się doczekać" #: extmod/ulab/code/ndarray.c msgid "cannot assign new shape" @@ -3025,7 +3067,7 @@ msgstr "" #: extmod/ulab/code/numpy/create.c msgid "divide by zero" -msgstr "" +msgstr "dziel przez zero" #: py/runtime.c msgid "division by zero" @@ -3045,7 +3087,7 @@ msgstr "puste" #: extmod/ulab/code/numpy/io/io.c msgid "empty file" -msgstr "" +msgstr "puste plik" #: extmod/modasyncio.c extmod/modheapq.c msgid "empty heap" @@ -3164,7 +3206,7 @@ msgstr "float zbyt wielki" #: py/nativeglue.c msgid "float unsupported" -msgstr "" +msgstr "float nieobsługiwany" #: shared-bindings/_stage/Text.c msgid "font must be 2048 bytes long" @@ -3172,10 +3214,10 @@ msgstr "font musi mieć 2048 bajtów długości" #: extmod/moddeflate.c msgid "format" -msgstr "" +msgstr "format" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "format wymaga słownika" #: py/objdeque.c @@ -3273,7 +3315,7 @@ msgstr "" #: py/persistentcode.c msgid "incompatible .mpy file" -msgstr "" +msgstr "niekompatybilny plik .mpy" #: py/objstr.c msgid "incomplete format" @@ -3635,7 +3677,7 @@ msgid "must use keyword argument for key function" msgstr "funkcja key musi być podana jako argument nazwany" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "nazwa '%q' niezdefiniowana" #: py/runtime.c @@ -3685,7 +3727,7 @@ msgstr "" #: shared-module/sdcardio/SDCard.c msgid "no SD card" -msgstr "" +msgstr "brak karty SD" #: py/vm.c msgid "no active exception to reraise" @@ -3766,7 +3808,7 @@ msgstr "liczba punktów musi wynosić co najmniej 2" #: py/builtinhelp.c msgid "object " -msgstr "" +msgstr "obiekt " #: py/obj.c #, c-format @@ -3820,7 +3862,7 @@ msgstr "łańcuch o nieparzystej długości" #: supervisor/shared/web_workflow/web_workflow.c msgid "off" -msgstr "" +msgstr "wył" #: extmod/ulab/code/utils/utils.c msgid "offset is too large" @@ -4276,11 +4318,11 @@ msgid "tx and rx cannot both be None" msgstr "tx i rx nie mogą być oba None" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "typ '%q' nie może być bazowy" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "typ nie może być bazowy" #: py/runtime.c @@ -4684,13 +4726,13 @@ msgstr "" #~ msgid "'%s' object does not support item deletion" #~ msgstr "'%s' obiekt nie wspiera usuwania elementów" -#~ msgid "'%s' object is not an iterator" +#~ msgid "'%s' object isn't an iterator" #~ msgstr "'%s' obiekt nie jest iteratorem" #~ msgid "'%s' object is not callable" #~ msgstr "'%s' nie można wywoływać obiektu" -#~ msgid "'%s' object is not iterable" +#~ msgid "'%s' object isn't iterable" #~ msgstr "'%s' nie można iterować po obiekcie" #~ msgid "'%s' object is not subscriptable" @@ -5454,7 +5496,7 @@ msgstr "" #~ msgid "firstbit must be MSB" #~ msgstr "firstbit musi być MSB" -#~ msgid "function does not take keyword arguments" +#~ msgid "function doesn't take keyword arguments" #~ msgstr "funkcja nie bierze argumentów nazwanych" #~ msgid "int() arg 2 must be >= 2 and <= 36" @@ -5502,7 +5544,7 @@ msgstr "" #~ msgid "name must be a string" #~ msgstr "nazwa musi być łańcuchem" -#~ msgid "name reused for argument" +#~ msgid "argument name reused" #~ msgstr "nazwa użyta ponownie jako argument" #~ msgid "no available NIC" diff --git a/locale/pt_BR.po b/locale/pt_BR.po index a1b6b9ff5c6b5..5bb98dc74c51f 100644 --- a/locale/pt_BR.po +++ b/locale/pt_BR.po @@ -6,15 +6,15 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2025-03-09 18:40+0000\n" -"Last-Translator: Wellington Terumi Uemura \n" +"PO-Revision-Date: 2025-06-09 12:01+0000\n" +"Last-Translator: MAE \n" "Language-Team: \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.10.3-dev\n" +"X-Generator: Weblate 5.12-dev\n" #: main.c msgid "" @@ -117,7 +117,7 @@ msgstr "%q falha: %d" #: shared-module/audiodelays/MultiTapDelay.c msgid "%q in %q must be of type %q or %q, not %q" -msgstr "" +msgstr "%q em %q deve ser do tipo %q ou %q, não %q" #: py/argcheck.c shared-module/audiofilters/Filter.c msgid "%q in %q must be of type %q, not %q" @@ -322,7 +322,7 @@ msgid "'%q' object does not support '%q'" msgstr "O objeto '%q' não suporta '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "O objeto '%q' não é um iterador" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -330,7 +330,7 @@ msgid "'%q' object is not callable" msgstr "O objeto '%s' não é invocável" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "O objeto '%q' não é iterável" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -874,6 +874,10 @@ msgstr "As coordenadas das matrizes possuem comprimentos diferentes" msgid "Coordinate arrays types have different sizes" msgstr "Os tipos das coordenadas das matrizes possuem tamanhos diferentes" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "Não foi possível definir o endereço" @@ -886,6 +890,11 @@ msgstr "Não foi possível iniciar a interrupção, RX ocupado" msgid "Couldn't allocate decoder" msgstr "Não foi possível alocar o decodificador" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "Erro de Inicialização do Canal DAC" @@ -1325,6 +1334,10 @@ msgstr "BSSID Inválido" msgid "Invalid MAC address" msgstr "Endereço MAC inválido" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Argumento inválido" @@ -1418,7 +1431,7 @@ msgstr "Não há suporte para segurança MITM" #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "MMC/SDIO Clock Error %x" -msgstr "" +msgstr "Erro de relógio MMC/SDIO %x" #: shared-bindings/is31fl3741/IS31FL3741.c msgid "Mapping must be a tuple" @@ -1897,6 +1910,10 @@ msgstr "O tamanho do programa é inválido" msgid "Program too long" msgstr "Programa muito longo" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "O Pull não foi usado quando a direção for gerada." @@ -1917,6 +1934,26 @@ msgstr "Erro DeInit RNG" msgid "RNG Init Error" msgstr "Houve um erro na inicialização do RNG" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2435,7 +2472,7 @@ msgstr "Wi-Fi: " #: ports/raspberrypi/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "WiFi is not enabled" -msgstr "" +msgstr "O WiFi não está habilitado" #: main.c msgid "Woken up by alarm.\n" @@ -2673,7 +2710,7 @@ msgstr "bits deve ser 32 ou menos" #: shared-bindings/audiofreeverb/Freeverb.c msgid "bits_per_sample must be 16" -msgstr "" +msgstr "bits_per_sample deve ser 16" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c #: shared-bindings/audiodelays/MultiTapDelay.c @@ -3229,7 +3266,7 @@ msgid "format" msgstr "formato" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "formato requer um dict" #: py/objdeque.c @@ -3694,7 +3731,7 @@ msgid "must use keyword argument for key function" msgstr "deve usar o argumento da palavra-chave para a função da chave" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "o nome '%q' não está definido" #: py/runtime.c @@ -4119,7 +4156,7 @@ msgstr "rsplit(Nenhum,n)" #: shared-bindings/audiofreeverb/Freeverb.c msgid "samples_signed must be true" -msgstr "" +msgstr "samples_signed deve ser verdadeiro" #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c #: ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -4341,11 +4378,11 @@ msgid "tx and rx cannot both be None" msgstr "TX e RX não podem ser ambos" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "o tipo '%q' não é um tipo base aceitável" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "tipo não é um tipo base aceitável" #: py/runtime.c @@ -4940,13 +4977,13 @@ msgstr "zi deve estar na forma (n_section, 2)" #~ msgid "'%s' object does not support item deletion" #~ msgstr "O objeto '%s' não é compatível com exclusão do item" -#~ msgid "'%s' object is not an iterator" +#~ msgid "'%s' object isn't an iterator" #~ msgstr "O objeto '%s' não é um iterador" #~ msgid "'%s' object is not callable" #~ msgstr "O objeto '%s' não é invocável" -#~ msgid "'%s' object is not iterable" +#~ msgid "'%s' object isn't iterable" #~ msgstr "O objeto '%s' não é iterável" #~ msgid "'%s' object is not subscriptable" @@ -4966,7 +5003,7 @@ msgstr "zi deve estar na forma (n_section, 2)" #~ msgid "'continue' outside loop" #~ msgstr "'continue' fora do loop" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "O objeto 'corrotina' não é um iterador" #~ msgid "(x,y) integers required" @@ -6323,7 +6360,7 @@ msgstr "zi deve estar na forma (n_section, 2)" #~ msgid "frequency is read-only for this board" #~ msgstr "nesta placa, a frequência é de apenas leitura" -#~ msgid "function does not take keyword arguments" +#~ msgid "function doesn't take keyword arguments" #~ msgstr "função não aceita argumentos de palavras-chave" #~ msgid "function is implemented for scalars and ndarrays only" @@ -6452,7 +6489,7 @@ msgstr "zi deve estar na forma (n_section, 2)" #~ msgid "name must be a string" #~ msgstr "heap deve ser uma lista" -#~ msgid "name reused for argument" +#~ msgid "argument name reused" #~ msgstr "o nome foi reutilizado para o argumento" #~ msgid "no available NIC" diff --git a/locale/ru.po b/locale/ru.po index d2e11451a0d7d..c002056141eb4 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -82,8 +82,8 @@ msgstr " вывод:\n" #: py/objstr.c #, c-format -msgid "%%c requires int or char" -msgstr "%%c требует int или char" +msgid "%%c needs int or char" +msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format @@ -173,7 +173,7 @@ msgstr "Длинна %q должна быть <= %d" msgid "%q length must be >= %d" msgstr "Длинна %q должна быть >= %d" -#: py/modsys.c py/runtime.c +#: py/runtime.c msgid "%q moved from %q to %q" msgstr "%q переместился из %q в %q" @@ -324,15 +324,15 @@ msgid "'%q' object does not support '%q'" msgstr "Объект '%q' не поддерживает '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "Объект '%q' не является итератором" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object is not callable" -msgstr "Объект '%q' не является вызываемым" +msgid "'%q' object isn't callable" +msgstr "" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "Объект '%q' не является итерируемым" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -874,6 +874,10 @@ msgstr "Координатные массивы имеют разные длин msgid "Coordinate arrays types have different sizes" msgstr "Типы массивов координат имеют разные размеры" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "Не удалось задать адрес" @@ -886,6 +890,11 @@ msgstr "Не удалось запустить прерывание, RX заня msgid "Couldn't allocate decoder" msgstr "Не удалось выделить место для декодера" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "Ошибка инициализации канала DAC" @@ -1328,6 +1337,10 @@ msgstr "Неверный BSSID" msgid "Invalid MAC address" msgstr "Неверный MAC-адрес" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Недопустимый аргумент" @@ -1894,6 +1907,10 @@ msgstr "Недопустимый размер программы" msgid "Program too long" msgstr "Слишком длинная программа" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "Тяга не используется, когда выводится направление." @@ -1914,6 +1931,26 @@ msgstr "Ошибка деинициализации генератора слу msgid "RNG Init Error" msgstr "Ошибка инициализации RNG" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2801,6 +2838,10 @@ msgstr "Не удается преобразовать в int" msgid "can't convert to str implicitly" msgstr "не может превратиться в полосу неявно" +#: py/objtype.c +msgid "can't create '%q' instances" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "не может объявить нелокальный во внешнем коде" @@ -2903,10 +2944,6 @@ msgstr "не может превратить комплекс в dtype" msgid "cannot convert complex type" msgstr "Не удается преобразовать сложный тип" -#: py/objtype.c -msgid "cannot create '%q' instances" -msgstr "Не удается создать экземпляры '%q'" - #: py/objtype.c msgid "cannot create instance" msgstr "Не удается создать экземпляр" @@ -3227,9 +3264,17 @@ msgid "format" msgstr "формат" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "Формат требует диктата" +#: py/objstr.c +msgid "format string didn't convert all arguments" +msgstr "" + +#: py/objstr.c +msgid "format string needs more arguments" +msgstr "" + #: py/objdeque.c msgid "full" msgstr "полный" @@ -3692,7 +3737,7 @@ msgid "must use keyword argument for key function" msgstr "Необходимо использовать аргумент ключевого слова для ключевой функции" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "Имя '%q' не определено" #: py/runtime.c @@ -3784,8 +3829,8 @@ msgstr "" "умолчанию" #: py/objstr.c -msgid "non-hex digit found" -msgstr "Ненайдена шестнадцатеричная цифра" +msgid "non-hex digit" +msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" @@ -3803,14 +3848,6 @@ msgstr "не 128-битный UUID" msgid "not a constant" msgstr "не константа" -#: py/objstr.c -msgid "not all arguments converted during string formatting" -msgstr "Не все аргументы преобразуются при форматировании строки" - -#: py/objstr.c -msgid "not enough arguments for format string" -msgstr "Недостаточно аргументов для строки форматирования" - #: extmod/ulab/code/numpy/carray/carray_tools.c msgid "not implemented for complex dtype" msgstr "не реализовано для сложного типа d" @@ -3873,10 +3910,6 @@ msgstr "объект типа «%s» не имеет len()" msgid "object with buffer protocol required" msgstr "Объект с обязательным буферным протоколом" -#: py/objstr.c -msgid "odd-length string" -msgstr "Строка нечетной длины" - #: supervisor/shared/web_workflow/web_workflow.c msgid "off" msgstr "выключить" @@ -4065,10 +4098,6 @@ msgstr "pow() с 3 аргументами требует целых чисел" msgid "pull masks conflict with direction masks" msgstr "Маски вытягивания конфликтуют с масками направления" -#: py/parse.c -msgid "raw f-strings are not supported" -msgstr "Необработанные F-строки не поддерживаются" - #: extmod/ulab/code/numpy/fft/fft_tools.c msgid "real and imaginary parts must be of equal length" msgstr "реальные и воображаемые части должны быть одинаковой длины" @@ -4337,11 +4366,11 @@ msgid "tx and rx cannot both be None" msgstr "tx и rx не могут быть одновременно None" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "Тип '%Q' не является допустимым базовым типом" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "Тип не является приемлемым базовым типом" #: py/runtime.c @@ -4548,6 +4577,31 @@ msgstr "zi должно быть типа float" msgid "zi must be of shape (n_section, 2)" msgstr "zi должен иметь форму (n_section, 2)" +#, c-format +#~ msgid "%%c requires int or char" +#~ msgstr "%%c требует int или char" + +#~ msgid "'%q' object is not callable" +#~ msgstr "Объект '%q' не является вызываемым" + +#~ msgid "cannot create '%q' instances" +#~ msgstr "Не удается создать экземпляры '%q'" + +#~ msgid "non-hex digit found" +#~ msgstr "Ненайдена шестнадцатеричная цифра" + +#~ msgid "not all arguments converted during string formatting" +#~ msgstr "Не все аргументы преобразуются при форматировании строки" + +#~ msgid "not enough arguments for format string" +#~ msgstr "Недостаточно аргументов для строки форматирования" + +#~ msgid "odd-length string" +#~ msgstr "Строка нечетной длины" + +#~ msgid "raw f-strings are not supported" +#~ msgstr "Необработанные F-строки не поддерживаются" + #~ msgid "Unsupported format" #~ msgstr "Неподдерживаемый формат" @@ -4824,7 +4878,7 @@ msgstr "zi должен иметь форму (n_section, 2)" #~ msgid "'continue' outside loop" #~ msgstr "«продолжить» вне цикла" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "Объект 'coroutine' не является итератором" #~ msgid "(x,y) integers required" diff --git a/locale/sv.po b/locale/sv.po index c8b9468f5c3b9..cfdbaa3064b8a 100644 --- a/locale/sv.po +++ b/locale/sv.po @@ -6,8 +6,8 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2025-05-15 08:01+0000\n" -"Last-Translator: Jonny Bergdahl \n" +"PO-Revision-Date: 2025-06-15 23:04+0000\n" +"Last-Translator: Jonny Bergdahl \n" "Language-Team: LANGUAGE \n" "Language: sv\n" "MIME-Version: 1.0\n" @@ -323,7 +323,7 @@ msgid "'%q' object does not support '%q'" msgstr "Objektet '%q' stöder inte '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "Objektet '%q' är inte en iterator" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -331,7 +331,7 @@ msgid "'%q' object is not callable" msgstr "Objektet '%q' kan inte anropas" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "Objektet '%q' är inte itererbart" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -868,6 +868,10 @@ msgstr "Arrayer för koordinater har olika längd" msgid "Coordinate arrays types have different sizes" msgstr "Arrayer för koordinater har olika storlek" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "Kan inte publicera till ROS topic" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "Kan inte ange adress" @@ -880,6 +884,11 @@ msgstr "Det gick inte att starta avbrott, RX upptagen" msgid "Couldn't allocate decoder" msgstr "Det gick inte att allokera avkodaren" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "Kritiskt ROS-fel vid mjuk omstart, reset krävs: %d" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "Initieringsfel för DAC-kanal" @@ -1314,6 +1323,10 @@ msgstr "Ogiltig BSSID" msgid "Invalid MAC address" msgstr "Ogiltig MAC-adress" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "Ogiltigt ROS domän-id" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Ogiltigt argument" @@ -1876,6 +1889,10 @@ msgstr "Programstorlek ogiltig" msgid "Program too long" msgstr "Programmet är för långt" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "Publicerare kan bara skapas from föräldranod" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "Pull används inte när riktningen är output." @@ -1896,6 +1913,26 @@ msgstr "RNG DeInit-fel" msgid "RNG Init Error" msgstr "RNG Init-fel" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "Fel vid ROS initialisering, är agent ansluten?" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "Fel vid ROS intern inställning" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "Fel vid ROS minnesallokering" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "Fel vid ROS-nods initialisering" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "Fel vid initialisering av ROS topic" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -3194,7 +3231,7 @@ msgid "format" msgstr "format" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "formatet kräver en dict" #: py/objdeque.c @@ -3655,7 +3692,7 @@ msgid "must use keyword argument for key function" msgstr "måste använda nyckelordsargument för nyckelfunktion" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "namnet '%q' är inte definierat" #: py/runtime.c @@ -4296,11 +4333,11 @@ msgid "tx and rx cannot both be None" msgstr "tx och rx kan inte båda vara None" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "typ '%q' är inte en acceptabel bastyp" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "typ är inte en acceptabel bastyp" #: py/runtime.c @@ -4886,13 +4923,13 @@ msgstr "zi måste vara i formen (n_section, 2)" #~ msgid "'%s' object does not support item deletion" #~ msgstr "Objektet '%s' stöder inte borttagning av objekt" -#~ msgid "'%s' object is not an iterator" +#~ msgid "'%s' object isn't an iterator" #~ msgstr "Objektet '%s' är inte en iterator" #~ msgid "'%s' object is not callable" #~ msgstr "Objektet '%s' kan inte anropas" -#~ msgid "'%s' object is not iterable" +#~ msgid "'%s' object isn't iterable" #~ msgstr "Objektet '%s' är inte itererable" #~ msgid "'%s' object is not subscriptable" @@ -4910,7 +4947,7 @@ msgstr "zi måste vara i formen (n_section, 2)" #~ msgid "'continue' outside loop" #~ msgstr "'continue' utanför loop" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "objektet 'coroutine\" är inte en iterator" #~ msgid "(x,y) integers required" @@ -6013,7 +6050,7 @@ msgstr "zi måste vara i formen (n_section, 2)" #~ msgid "frequency is read-only for this board" #~ msgstr "frekvens är skrivskyddad för detta kort" -#~ msgid "function does not take keyword arguments" +#~ msgid "function doesn't take keyword arguments" #~ msgstr "funktionen tar inte nyckelordsargument" #~ msgid "function is implemented for scalars and ndarrays only" @@ -6113,7 +6150,7 @@ msgstr "zi måste vara i formen (n_section, 2)" #~ msgid "n must be between 0, and 9" #~ msgstr "n måste vara mellan 0 och 9" -#~ msgid "name reused for argument" +#~ msgid "argument name reused" #~ msgstr "namn återanvänt för argument" #~ msgid "no available NIC" diff --git a/locale/tr.po b/locale/tr.po index 30c8f3d107f71..01f72146771d5 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -80,8 +80,8 @@ msgstr " çıktı:\n" #: py/objstr.c #, c-format -msgid "%%c requires int or char" -msgstr "%%c int veya char tipine ihtiyaç duyar" +msgid "%%c needs int or char" +msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format @@ -171,7 +171,7 @@ msgstr "%q boyutu <= %d olmalıdır" msgid "%q length must be >= %d" msgstr "%q boyutu >= %d olmalıdır" -#: py/modsys.c py/runtime.c +#: py/runtime.c msgid "%q moved from %q to %q" msgstr "" @@ -322,15 +322,15 @@ msgid "'%q' object does not support '%q'" msgstr "'%q' nesnesi '%q' öğesini desteklemiyor" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "'%q' nesnesi bir iteratör değildir" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object is not callable" -msgstr "'%q' nesnesi çağrılabilir değil" +msgid "'%q' object isn't callable" +msgstr "" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "'%q' nesnesi iterable değildir" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -864,6 +864,10 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "Adres ayarlanamadı" @@ -876,6 +880,11 @@ msgstr "Kesinti başlatılamadı, RX kullanımda" msgid "Couldn't allocate decoder" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "" @@ -1307,6 +1316,10 @@ msgstr "Geçersiz BSSID" msgid "Invalid MAC address" msgstr "Geçersiz MAC adresi" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Geçersiz argüman" @@ -1865,6 +1878,10 @@ msgstr "" msgid "Program too long" msgstr "" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "" @@ -1885,6 +1902,26 @@ msgstr "" msgid "RNG Init Error" msgstr "" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2752,6 +2789,10 @@ msgstr "" msgid "can't convert to str implicitly" msgstr "" +#: py/objtype.c +msgid "can't create '%q' instances" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2850,10 +2891,6 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create '%q' instances" -msgstr "" - #: py/objtype.c msgid "cannot create instance" msgstr "" @@ -3168,7 +3205,15 @@ msgid "format" msgstr "" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" +msgstr "" + +#: py/objstr.c +msgid "format string didn't convert all arguments" +msgstr "" + +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" #: py/objdeque.c @@ -3627,7 +3672,7 @@ msgid "must use keyword argument for key function" msgstr "" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "" #: py/runtime.c @@ -3717,7 +3762,7 @@ msgid "non-default argument follows default argument" msgstr "" #: py/objstr.c -msgid "non-hex digit found" +msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c @@ -3736,14 +3781,6 @@ msgstr "" msgid "not a constant" msgstr "" -#: py/objstr.c -msgid "not all arguments converted during string formatting" -msgstr "" - -#: py/objstr.c -msgid "not enough arguments for format string" -msgstr "" - #: extmod/ulab/code/numpy/carray/carray_tools.c msgid "not implemented for complex dtype" msgstr "" @@ -3806,10 +3843,6 @@ msgstr "" msgid "object with buffer protocol required" msgstr "" -#: py/objstr.c -msgid "odd-length string" -msgstr "" - #: supervisor/shared/web_workflow/web_workflow.c msgid "off" msgstr "" @@ -3998,10 +4031,6 @@ msgstr "" msgid "pull masks conflict with direction masks" msgstr "" -#: py/parse.c -msgid "raw f-strings are not supported" -msgstr "" - #: extmod/ulab/code/numpy/fft/fft_tools.c msgid "real and imaginary parts must be of equal length" msgstr "" @@ -4268,11 +4297,11 @@ msgid "tx and rx cannot both be None" msgstr "" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "" #: py/runtime.c @@ -4476,6 +4505,13 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, c-format +#~ msgid "%%c requires int or char" +#~ msgstr "%%c int veya char tipine ihtiyaç duyar" + +#~ msgid "'%q' object is not callable" +#~ msgstr "'%q' nesnesi çağrılabilir değil" + #~ msgid "Cannot remount '/' when visible via USB." #~ msgstr "'/' USB ile görünür olduğunda, yeniden bağlanamaz." @@ -4610,7 +4646,7 @@ msgstr "" #~ msgid "'continue' outside loop" #~ msgstr "döngü dışında 'continue'" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "'coroutine' nesnesi bir iteratör değildir" #~ msgid "(x,y) integers required" diff --git a/locale/zh_Latn_pinyin.po b/locale/zh_Latn_pinyin.po index 85eb703d4db01..973ced8939440 100644 --- a/locale/zh_Latn_pinyin.po +++ b/locale/zh_Latn_pinyin.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: circuitpython-cn\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2025-04-25 15:04+0000\n" +"PO-Revision-Date: 2025-05-31 20:05+0000\n" "Last-Translator: hexthat \n" "Language-Team: Chinese Hanyu Pinyin\n" "Language: zh_Latn_pinyin\n" @@ -324,7 +324,7 @@ msgid "'%q' object does not support '%q'" msgstr "'%q' duì xiàng bù zhī chí '%q'" #: py/runtime.c -msgid "'%q' object is not an iterator" +msgid "'%q' object isn't an iterator" msgstr "%q' duìxiàng bùshì yígè diédàiqì" #: py/objtype.c py/runtime.c shared-module/atexit/__init__.c @@ -332,7 +332,7 @@ msgid "'%q' object is not callable" msgstr "%q' duìxiàng bù kě bèi diàoyòng" #: py/runtime.c -msgid "'%q' object is not iterable" +msgid "'%q' object isn't iterable" msgstr "%q' duìxiàng bù kě yòngyú diédài" #: py/emitinlinethumb.c py/emitinlinextensa.c @@ -868,6 +868,10 @@ msgstr "zuòbiāo shùzǔ jùyǒu bùtóng de chángdù" msgid "Coordinate arrays types have different sizes" msgstr "zuòbiāo shùzǔ lèixíng jùyǒu bùtóng de dàxiǎo" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" msgstr "wúfǎ shèzhì dìzhǐ" @@ -880,6 +884,11 @@ msgstr "Wúfǎ qǐdòng zhōngduàn,RX máng" msgid "Couldn't allocate decoder" msgstr "wúfǎ fēnpèi jiěmǎ qì" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" msgstr "DAC tōngdào chūshǐhuà cuòwù" @@ -1320,6 +1329,10 @@ msgstr "Wúxiào de BSSID" msgid "Invalid MAC address" msgstr "wú xiào de MAC dì zhǐ" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Wúxiào de cānshù" @@ -1883,6 +1896,10 @@ msgstr "chéng xù dà xiǎo wú xiào" msgid "Program too long" msgstr "chéng xù tài cháng" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." msgstr "Fāngxiàng shūchū shí Pull méiyǒu shǐyòng." @@ -1903,6 +1920,26 @@ msgstr "RNG qǔxiāo chūshǐhuà cuòwù" msgid "RNG Init Error" msgstr "RNG chūshǐhuà cuòwù" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c msgid "RS485" @@ -2116,7 +2153,7 @@ msgstr "Píng pū kuāndù bìxū huàfēn wèi tú kuāndù" #: shared-module/tilepalettemapper/TilePaletteMapper.c msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" +msgstr "TilePaletteMapper zhǐnéng bǎngdìng dào yígè TileGrid shàngyícì" #: shared-bindings/alarm/time/TimeAlarm.c msgid "Time is in the past." @@ -2411,7 +2448,7 @@ msgstr "Wi-Fi: " #: ports/raspberrypi/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "WiFi is not enabled" -msgstr "" +msgstr "WiFi wèi qǐyòng" #: main.c msgid "Woken up by alarm.\n" @@ -3201,7 +3238,7 @@ msgid "format" msgstr "Géshì" #: py/objstr.c -msgid "format requires a dict" +msgid "format needs a dict" msgstr "géshì yāoqiú yīgè yǔjù" #: py/objdeque.c @@ -3661,7 +3698,7 @@ msgid "must use keyword argument for key function" msgstr "bìxū shǐyòng guānjiàn cí cānshù" #: py/runtime.c -msgid "name '%q' is not defined" +msgid "name '%q' isn't defined" msgstr "míngchēng '%q' wèi dìngyì" #: py/runtime.c @@ -4305,11 +4342,11 @@ msgid "tx and rx cannot both be None" msgstr "tx hé rx bùnéng dōu shì wú" #: py/objtype.c -msgid "type '%q' is not an acceptable base type" +msgid "type '%q' isn't an acceptable base type" msgstr "lèixíng '%q' bùshì kě jiēshòu de jīchǔ lèixíng" #: py/objtype.c -msgid "type is not an acceptable base type" +msgid "type isn't an acceptable base type" msgstr "lèixíng bùshì kě jiēshòu de jīchǔ lèixíng" #: py/runtime.c @@ -4889,13 +4926,13 @@ msgstr "zi bìxū jùyǒu xíngzhuàng (n_section,2)" #~ msgid "'%s' object does not support item deletion" #~ msgstr "'%s' duìxiàng bù zhīchí shānchú xiàngmù" -#~ msgid "'%s' object is not an iterator" +#~ msgid "'%s' object isn't an iterator" #~ msgstr "'%s' duìxiàng bùshì yīgè diédài qì" #~ msgid "'%s' object is not callable" #~ msgstr "'%s' duìxiàng wúfǎ diàoyòng" -#~ msgid "'%s' object is not iterable" +#~ msgid "'%s' object isn't iterable" #~ msgstr "'%s' duìxiàng bùnéng diédài" #~ msgid "'%s' object is not subscriptable" @@ -4911,7 +4948,7 @@ msgstr "zi bìxū jùyǒu xíngzhuàng (n_section,2)" #~ msgid "'continue' outside loop" #~ msgstr "'continue' wèiyú xúnhuán zhīwài" -#~ msgid "'coroutine' object is not an iterator" +#~ msgid "'coroutine' object isn't an iterator" #~ msgstr "'coroutine' duìxiàng búshì yígè diédàiqì" #~ msgid "(x,y) integers required" @@ -6259,7 +6296,7 @@ msgstr "zi bìxū jùyǒu xíngzhuàng (n_section,2)" #~ msgid "frequency is read-only for this board" #~ msgstr "cǐ zhǔ bǎn de pín lǜ wéi zhǐ dú" -#~ msgid "function does not take keyword arguments" +#~ msgid "function doesn't take keyword arguments" #~ msgstr "hánshù méiyǒu guānjiàn cí cānshù" #~ msgid "function is implemented for scalars and ndarrays only" @@ -6361,7 +6398,7 @@ msgstr "zi bìxū jùyǒu xíngzhuàng (n_section,2)" #~ msgid "name must be a string" #~ msgstr "míngchēng bìxū shì yīgè zìfú chuàn" -#~ msgid "name reused for argument" +#~ msgid "argument name reused" #~ msgstr "cān shǔ míngchēng bèi chóngxīn shǐyòng" #~ msgid "no available NIC" diff --git a/main.c b/main.c index 45b7af2725435..1f387b7ca3ceb 100644 --- a/main.c +++ b/main.c @@ -582,8 +582,8 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s size_t total_time = blink_time + LED_SLEEP_TIME_MS; #endif - // This loop is waits after code completes. It waits for fake sleeps to - // finish, user input or autoreloads. + // This loop is run after code completes. It waits for fake sleeps to + // finish, waits for user input, or waits for an autoreload. #if CIRCUITPY_ALARM bool fake_sleeping = false; #endif @@ -1180,7 +1180,7 @@ void gc_collect(void) { } // Ports may provide an implementation of this function if it is needed -MP_WEAK void port_gc_collect() { +MP_WEAK void port_gc_collect(void) { } size_t gc_get_max_new_split(void) { diff --git a/mpy-cross/Makefile b/mpy-cross/Makefile index 9962e9bcbb246..bd9e0fb1f54d4 100644 --- a/mpy-cross/Makefile +++ b/mpy-cross/Makefile @@ -25,6 +25,12 @@ CFLAGS += -fdata-sections -ffunction-sections -fno-asynchronous-unwind-tables # CIRCUITPY-CHANGE CFLAGS += -DCIRCUITPY +# Build a static executable. +# Useful for builds that must run on multiple operating system versions. Used for published mpy-cross versions. +ifdef STATIC_BUILD +CFLAGS += -static -static-libgcc -static-libstdc++ +endif + # Debugging/Optimization ifdef DEBUG CFLAGS += -g @@ -47,6 +53,10 @@ LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -Wl,--gc-sections endif LDFLAGS += $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA) +ifdef STATIC_BUILD +LDFLAGS += -static -static-libgcc -static-libstdc++ +endif + # source files # CIRCUITPY-CHANGE: extra files SRC_C = \ diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 611da76468728..989aec68bb519 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -55,7 +55,7 @@ static void stdout_print_strn(void *env, const char *str, size_t len) { (void)dummy; } -static const mp_print_t mp_stdout_print = {NULL, stdout_print_strn}; +const mp_print_t mp_stdout_print = {NULL, stdout_print_strn}; static void stderr_print_strn(void *env, const char *str, size_t len) { (void)env; @@ -130,7 +130,8 @@ static int usage(char **argv) { "\n" "Target specific options:\n" "-msmall-int-bits=number : set the maximum bits used to encode a small-int\n" - "-march= : set architecture for native emitter; x86, x64, armv6, armv6m, armv7m, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin\n" + "-march= : set architecture for native emitter;\n" + " x86, x64, armv6, armv6m, armv7m, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin, rv32imc, debug\n" "\n" "Implementation specific options:\n", argv[0] ); @@ -314,6 +315,12 @@ MP_NOINLINE int main_(int argc, char **argv) { } else if (strcmp(arch, "xtensawin") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSAWIN; mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_XTENSAWIN; + } else if (strcmp(arch, "rv32imc") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_RV32IMC; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_RV32I; + } else if (strcmp(arch, "debug") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_DEBUG; + mp_dynamic_compiler.nlr_buf_num_regs = 0; } else if (strcmp(arch, "host") == 0) { #if defined(__i386__) || defined(_M_IX86) mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_X86; diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h index bdd10efdaea00..a8aaceb796135 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -50,6 +50,9 @@ #define MICROPY_EMIT_XTENSA (1) #define MICROPY_EMIT_INLINE_XTENSA (1) #define MICROPY_EMIT_XTENSAWIN (1) +#define MICROPY_EMIT_RV32 (1) +#define MICROPY_EMIT_NATIVE_DEBUG (1) +#define MICROPY_EMIT_NATIVE_DEBUG_PRINTER (&mp_stdout_print) #define MICROPY_DYNAMIC_COMPILER (1) #define MICROPY_COMP_CONST_FOLDING (1) @@ -169,3 +172,5 @@ typedef int ssize_t; typedef mp_off_t off_t; #endif + +extern const struct _mp_print_t mp_stdout_print; diff --git a/mpy-cross/mpy_cross/__init__.py b/mpy-cross/mpy_cross/__init__.py index 5020033e8c808..91cd6f99335b3 100644 --- a/mpy-cross/mpy_cross/__init__.py +++ b/mpy-cross/mpy_cross/__init__.py @@ -43,6 +43,7 @@ "NATIVE_ARCH_ARMV7EMDP": "armv7emdp", "NATIVE_ARCH_XTENSA": "xtensa", "NATIVE_ARCH_XTENSAWIN": "xtensawin", + "NATIVE_ARCH_RV32IMC": "rv32imc", } globals().update(NATIVE_ARCHS) diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 888729c7b7f3d..9582eff212d60 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -107,7 +107,7 @@ else endif endif -CFLAGS += $(INC) -Wall -Werror -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes +CFLAGS += $(INC) -Wall -Werror -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes -Werror=old-style-definition ifeq ($(CHIP_FAMILY), samd21) CFLAGS += \ diff --git a/ports/atmel-samd/audio_dma.c b/ports/atmel-samd/audio_dma.c index d5f841f371dd9..e25b74d9a2893 100644 --- a/ports/atmel-samd/audio_dma.c +++ b/ports/atmel-samd/audio_dma.c @@ -30,7 +30,7 @@ static audio_dma_t *audio_dma_state[AUDIO_DMA_CHANNEL_COUNT]; // This cannot be in audio_dma_state because it's volatile. static volatile bool audio_dma_pending[AUDIO_DMA_CHANNEL_COUNT]; -uint8_t find_sync_event_channel_raise() { +uint8_t find_sync_event_channel_raise(void) { uint8_t event_channel = find_sync_event_channel(); if (event_channel >= EVSYS_SYNCH_NUM) { mp_raise_RuntimeError(MP_ERROR_TEXT("All sync event channels in use")); diff --git a/ports/atmel-samd/boards/openbook_m4/board.c b/ports/atmel-samd/boards/openbook_m4/board.c index 032ebe9f628a7..3ad2e162ecf3c 100644 --- a/ports/atmel-samd/boards/openbook_m4/board.c +++ b/ports/atmel-samd/boards/openbook_m4/board.c @@ -85,6 +85,7 @@ void board_init(void) { false, // chip_select (don't always toggle chip select) false, // grayscale false, // acep + false, // spectra6 false, // two_byte_sequence_length false); // address_little_endian } diff --git a/ports/atmel-samd/common-hal/_pew/PewPew.c b/ports/atmel-samd/common-hal/_pew/PewPew.c index 84ff7bc16c734..c3f9330faaef9 100644 --- a/ports/atmel-samd/common-hal/_pew/PewPew.c +++ b/ports/atmel-samd/common-hal/_pew/PewPew.c @@ -38,7 +38,7 @@ void pewpew_interrupt_handler(uint8_t index) { tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0; } -void pew_init() { +void pew_init(void) { pew_obj_t *pew = MP_STATE_VM(pew_singleton); common_hal_digitalio_digitalinout_switch_to_input(pew->buttons, PULL_UP); @@ -105,6 +105,6 @@ void pew_reset(void) { MP_STATE_VM(pew_singleton) = NULL; } -uint16_t pew_get_ticks() { +uint16_t pew_get_ticks(void) { return pewpew_ticks; } diff --git a/ports/atmel-samd/common-hal/analogio/AnalogIn.c b/ports/atmel-samd/common-hal/analogio/AnalogIn.c index c633cf44b678c..801ab18f7fd6d 100644 --- a/ports/atmel-samd/common-hal/analogio/AnalogIn.c +++ b/ports/atmel-samd/common-hal/analogio/AnalogIn.c @@ -64,7 +64,7 @@ void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) { self->pin = NULL; } -void analogin_reset() { +void analogin_reset(void) { } uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { diff --git a/ports/atmel-samd/common-hal/touchio/TouchIn.c b/ports/atmel-samd/common-hal/touchio/TouchIn.c index dc31bfe634be5..822d614a60298 100644 --- a/ports/atmel-samd/common-hal/touchio/TouchIn.c +++ b/ports/atmel-samd/common-hal/touchio/TouchIn.c @@ -91,7 +91,7 @@ void common_hal_touchio_touchin_deinit(touchio_touchin_obj_t *self) { self->config.pin = NO_PIN; } -void touchin_reset() { +void touchin_reset(void) { Ptc *ptc = ((Ptc *)PTC); if (ptc->CTRLA.bit.ENABLE == 1) { ptc->CTRLA.bit.ENABLE = 0; diff --git a/ports/broadcom/Makefile b/ports/broadcom/Makefile index 240362e3de7f6..f60ebbf045e1f 100644 --- a/ports/broadcom/Makefile +++ b/ports/broadcom/Makefile @@ -95,7 +95,7 @@ else endif -CFLAGS += $(INC) -Wall -Werror -std=gnu11 $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS) +CFLAGS += $(INC) -Wall -Werror -std=gnu11 $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS) -Werror=old-style-definition $(BUILD)/lib/tlsf/tlsf.o: CFLAGS += -Wno-cast-align diff --git a/ports/broadcom/mpconfigport.mk b/ports/broadcom/mpconfigport.mk index b4b3e2ebf8192..d906b5d2aa467 100644 --- a/ports/broadcom/mpconfigport.mk +++ b/ports/broadcom/mpconfigport.mk @@ -27,7 +27,7 @@ USB_HIGHSPEED = 1 CIRCUITPY_BUILD_EXTENSIONS ?= disk.img.zip,kernel8.img ifeq ($(CHIP_VARIANT), "bcm2711") -CIRCUITPY_MIN_GCC_VERSION ?= 10 +CIRCUITPY_MIN_GCC_VERSION ?= 14 else ifeq ($(CHIP_VARIANT), "bcm2837") -CIRCUITPY_MIN_GCC_VERSION ?= 10 +CIRCUITPY_MIN_GCC_VERSION ?= 14 endif diff --git a/ports/cxd56/common-hal/camera/Camera.c b/ports/cxd56/common-hal/camera/Camera.c index c3c935a168d42..b9fa2787ef767 100644 --- a/ports/cxd56/common-hal/camera/Camera.c +++ b/ports/cxd56/common-hal/camera/Camera.c @@ -44,7 +44,7 @@ static const image_size_t isx019_image_size_table[] = { { VIDEO_HSIZE_QUADVGA, VIDEO_VSIZE_QUADVGA }, }; -static const char *get_imgsensor_name() { +static const char *get_imgsensor_name(void) { static struct v4l2_capability cap; ioctl(camera_dev.fd, VIDIOC_QUERYCAP, (unsigned long)&cap); @@ -113,7 +113,7 @@ static void camera_start_streaming(enum v4l2_buf_type type) { ioctl(camera_dev.fd, VIDIOC_STREAMON, (unsigned long)&type); } -static void camera_start_preview() { +static void camera_start_preview(void) { camera_set_format(V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_PIX_FMT_UYVY, VIDEO_HSIZE_QVGA, VIDEO_VSIZE_QVGA); v4l2_buffer_t buf; diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 542083188e556..ca16b1c2cfed7 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -191,7 +191,7 @@ endif # option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk CFLAGS += $(OPTIMIZATION_FLAGS) -CFLAGS += $(INC) -Werror -Wall -std=gnu11 -Wl,--gc-sections $(BASE_CFLAGS) $(C_DEFS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes +CFLAGS += $(INC) -Werror -Wall -std=gnu11 -Wl,--gc-sections $(BASE_CFLAGS) $(C_DEFS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes -Werror=old-style-definition # Most current ESPs have nano versions of newlib in ROM so we use them. ifneq ($(IDF_TARGET),esp32c6) @@ -440,6 +440,55 @@ CFLAGS += -isystem esp-camera/driver/include CFLAGS += -isystem esp-camera/conversions/include endif +ifneq ($(CIRCUITPY_RCLCPY),0) +CFLAGS += -isystem microros-lib/include +CFLAGS += -isystem microros-lib/include/rcl +CFLAGS += -isystem microros-lib/include/statistics_msgs +CFLAGS += -isystem microros-lib/include/composition_interfaces +CFLAGS += -isystem microros-lib/include/example_interfaces +CFLAGS += -isystem microros-lib/include/rmw_microxrcedds_c +CFLAGS += -isystem microros-lib/include/test_msgs +CFLAGS += -isystem microros-lib/include/std_msgs +CFLAGS += -isystem microros-lib/include/rcutils +CFLAGS += -isystem microros-lib/include/lifecycle_msgs +CFLAGS += -isystem microros-lib/include/rosidl_typesupport_interface +CFLAGS += -isystem microros-lib/include/service_msgs +CFLAGS += -isystem microros-lib/include/visualization_msgs +CFLAGS += -isystem microros-lib/include/rosidl_dynamic_typesupport +CFLAGS += -isystem microros-lib/include/stereo_msgs +CFLAGS += -isystem microros-lib/include/ucdr +CFLAGS += -isystem microros-lib/include/rosidl_typesupport_c +CFLAGS += -isystem microros-lib/include/std_srvs +CFLAGS += -isystem microros-lib/include/rcl_lifecycle +CFLAGS += -isystem microros-lib/include/action_msgs +CFLAGS += -isystem microros-lib/include/micro_ros_utilities +CFLAGS += -isystem microros-lib/include/rcl_action +CFLAGS += -isystem microros-lib/include/rcl_logging_interface +CFLAGS += -isystem microros-lib/include/type_description_interfaces +CFLAGS += -isystem microros-lib/include/nav_msgs +CFLAGS += -isystem microros-lib/include/actionlib_msgs +CFLAGS += -isystem microros-lib/include/rmw +CFLAGS += -isystem microros-lib/include/rclc_parameter +CFLAGS += -isystem microros-lib/include/geometry_msgs +CFLAGS += -isystem microros-lib/include/sensor_msgs +CFLAGS += -isystem microros-lib/include/trajectory_msgs +CFLAGS += -isystem microros-lib/include/shape_msgs +CFLAGS += -isystem microros-lib/include/rosidl_runtime_c +CFLAGS += -isystem microros-lib/include/rclc +CFLAGS += -isystem microros-lib/include/rosgraph_msgs +CFLAGS += -isystem microros-lib/include/rclc_lifecycle +CFLAGS += -isystem microros-lib/include/rcl_interfaces +CFLAGS += -isystem microros-lib/include/diagnostic_msgs +CFLAGS += -isystem microros-lib/include/micro_ros_msgs +CFLAGS += -isystem microros-lib/include/rosidl_typesupport_introspection_c +CFLAGS += -isystem microros-lib/include/uxr +CFLAGS += -isystem microros-lib/include/unique_identifier_msgs +CFLAGS += -isystem microros-lib/include/rosidl_typesupport_microxrcedds_c +CFLAGS += -isystem microros-lib/include/builtin_interfaces +CFLAGS += -isystem microros-lib/include/tracetools +CFLAGS += -isystem microros-lib/include/rmw_microros +endif + ifneq ($(CIRCUITPY_ESPIDF),0) SRC_ESPIDF := \ $(wildcard common-hal/espidf/*.c) \ @@ -523,11 +572,14 @@ ifeq ($(CIRCUITPY_ESP_FLASH_SIZE), 2MB) else UF2_BOOTLOADER ?= $(CIRCUITPY_USB_DEVICE) ifeq ($(UF2_BOOTLOADER), 1) +# UF2-capable board FLASH_SIZE_SDKCONFIG ?= esp-idf-config/sdkconfig-flash-$(CIRCUITPY_ESP_FLASH_SIZE).defaults else +# non-UF2 partition layout ifeq ($(CIRCUITPY_ESP_FLASH_SIZE), 4MB) - ifeq ($(CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT), 1) - FLASH_SIZE_SDKCONFIG ?= esp-idf-config/sdkconfig-flash-$(CIRCUITPY_ESP_FLASH_SIZE)-no-uf2.defaults + ifeq ($(CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT), 1) +# Some boards use a 2MB firmware and almost 2MB user filesystem, for historical reasons. + FLASH_SIZE_SDKCONFIG ?= esp-idf-config/sdkconfig-flash-$(CIRCUITPY_ESP_FLASH_SIZE)-no-ota-no-uf2-large-user_fs.defaults else FLASH_SIZE_SDKCONFIG ?= esp-idf-config/sdkconfig-flash-$(CIRCUITPY_ESP_FLASH_SIZE)-no-ota-no-uf2.defaults endif @@ -685,6 +737,18 @@ ESP_IDF_COMPONENTS_EXPANDED += $(BUILD)/esp-idf/esp-idf/esp-camera/libesp-camera #$(error $(ESP_IDF_COMPONENTS_EXPANDED)) endif +ifneq ($(CIRCUITPY_RCLCPY),0) + ifeq ($(IDF_TARGET),esp32) + BINARY_BLOBS += microros-lib/esp32/libmicroros.a + else ifeq ($(IDF_TARGET),esp32s2) + BINARY_BLOBS+= microros-lib/esp32s2/libmicroros.a + else ifeq ($(IDF_TARGET),esp32s3) + BINARY_BLOBS += microros-lib/esp32s3/libmicroros.a + else + $(error Unsupported Espressif target for Micro-ROS: $(IDF_TARGET).) + endif +endif + ifneq ($(VALID_BOARD),) # From esp-idf/components/bootloader/Kconfig.projbuild # BOOTLOADER_OFFSET is determined by chip type, based on the ROM bootloader, and is not changeable. diff --git a/ports/espressif/boards/01space_lcd042_esp32c3/mpconfigboard.mk b/ports/espressif/boards/01space_lcd042_esp32c3/mpconfigboard.mk index f0067c0d22b49..ad0e985cd6fab 100644 --- a/ports/espressif/boards/01space_lcd042_esp32c3/mpconfigboard.mk +++ b/ports/espressif/boards/01space_lcd042_esp32c3/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 diff --git a/ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.mk b/ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.mk index f39b1594eda7a..28821ed7b481e 100644 --- a/ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.mk @@ -6,3 +6,6 @@ IDF_TARGET = esp32c6 CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB + +# Board was originally defined with a 2MB firmware, almost 2MB user filesystem. Leave it that way. +CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT = 1 diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk b/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk index 8cd3ad0dbfe08..57801b730551c 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_feather_esp32s3_4mbflash_2mbpsram/mpconfigboard.mk @@ -18,5 +18,4 @@ OPTIMIZATION_FLAGS = -Os #CIRCUITPY_PARALLELDISPLAYBUS = 0 CIRCUITPY_BLEIO_NATIVE = 1 -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 0 FLASH_SIZE_SDKCONFIG = esp-idf-config/sdkconfig-flash-$(CIRCUITPY_ESP_FLASH_SIZE)-no-ota.defaults diff --git a/ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.mk b/ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.mk index 24909715b9706..3d53e15942220 100644 --- a/ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index 321a5a1f2c7a0..430079a94dad2 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -141,6 +141,7 @@ void board_init(void) { false, // always_toggle_chip_select true, // grayscale false, // acep + false, // spectra6 false, // two_byte_sequence_length false); // address_little_endian } diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.mk b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.mk index 01b9ec73e9c34..5ab8c995e331c 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/mpconfigboard.mk @@ -10,6 +10,7 @@ CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_PARALLELDISPLAYBUS = 0 # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ConnectionManager diff --git a/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.mk b/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.mk index 1f47795002df9..a17418eff198e 100644 --- a/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.mk @@ -7,12 +7,8 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 -# Not enough flash space. -CIRCUITPY_CODEOP = 0 - # Not enough pins. CIRCUITPY_PARALLELDISPLAYBUS = 0 +CIRCUITPY_RGBMATRIX = 0 diff --git a/ports/espressif/boards/adafruit_sparkle_motion_stick/pins.c b/ports/espressif/boards/adafruit_sparkle_motion_stick/pins.c index a73c0e63f2ef6..a5fdadac1e0f7 100644 --- a/ports/espressif/boards/adafruit_sparkle_motion_stick/pins.c +++ b/ports/espressif/boards/adafruit_sparkle_motion_stick/pins.c @@ -13,7 +13,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO0) }, { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, - { MP_ROM_QSTR(MP_QSTR_IR_RX), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IR), MP_ROM_PTR(&pin_GPIO10) }, { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) }, { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.mk b/ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.mk index 366586c1d5568..9bcaa3473a2c2 100644 --- a/ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.mk +++ b/ports/espressif/boards/ai_thinker_esp32-c3s/mpconfigboard.mk @@ -7,7 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 -CIRCUITPY_TILEPALETTEMAPPER = 0 diff --git a/ports/espressif/boards/beetle-esp32-c3/mpconfigboard.mk b/ports/espressif/boards/beetle-esp32-c3/mpconfigboard.mk index 4341584e4cef3..5ad71b2da59d6 100644 --- a/ports/espressif/boards/beetle-esp32-c3/mpconfigboard.mk +++ b/ports/espressif/boards/beetle-esp32-c3/mpconfigboard.mk @@ -8,7 +8,4 @@ CIRCUITPY_ESP_FLASH_MODE=qio CIRCUITPY_ESP_FLASH_FREQ=80m CIRCUITPY_ESP_FLASH_SIZE=4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 -CIRCUITPY_TILEPALETTEMAPPER = 0 diff --git a/ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.mk b/ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.mk index 3acd161c34088..fe93c7a849a65 100644 --- a/ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.mk +++ b/ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.mk @@ -6,3 +6,6 @@ IDF_TARGET = esp32c6 CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB + +# Board was originally defined with a 2MB firmware, almost 2MB user filesystem. Leave it that way. +CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT = 1 diff --git a/ports/espressif/boards/deneyap_kart/mpconfigboard.mk b/ports/espressif/boards/deneyap_kart/mpconfigboard.mk index df54649ec529d..69d81074fa7e5 100644 --- a/ports/espressif/boards/deneyap_kart/mpconfigboard.mk +++ b/ports/espressif/boards/deneyap_kart/mpconfigboard.mk @@ -10,5 +10,3 @@ CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESP_PSRAM_SIZE = 8MB CIRCUITPY_ESP_PSRAM_MODE = qio CIRCUITPY_ESP_PSRAM_FREQ = 80m - -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 diff --git a/ports/espressif/boards/deneyap_kart_1a/mpconfigboard.mk b/ports/espressif/boards/deneyap_kart_1a/mpconfigboard.mk index 17dfe4fe76863..b1b6c9eab4bf9 100644 --- a/ports/espressif/boards/deneyap_kart_1a/mpconfigboard.mk +++ b/ports/espressif/boards/deneyap_kart_1a/mpconfigboard.mk @@ -10,5 +10,3 @@ CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESP_PSRAM_SIZE = 8MB CIRCUITPY_ESP_PSRAM_MODE = qio CIRCUITPY_ESP_PSRAM_FREQ = 80m - -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 diff --git a/ports/espressif/boards/deneyap_kart_1a_v2/mpconfigboard.mk b/ports/espressif/boards/deneyap_kart_1a_v2/mpconfigboard.mk index cb994090192b5..448ecf3a07477 100644 --- a/ports/espressif/boards/deneyap_kart_1a_v2/mpconfigboard.mk +++ b/ports/espressif/boards/deneyap_kart_1a_v2/mpconfigboard.mk @@ -14,8 +14,6 @@ CIRCUITPY_ESP_PSRAM_SIZE = 8MB CIRCUITPY_ESP_PSRAM_MODE = opi CIRCUITPY_ESP_PSRAM_FREQ = 80m -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESPCAMERA = 0 CIRCUITPY_BITMAPFILTER = 0 CIRCUITPY_CODEOP = 0 diff --git a/ports/espressif/boards/deneyap_kart_g/mpconfigboard.mk b/ports/espressif/boards/deneyap_kart_g/mpconfigboard.mk index 8aaea636b843c..46e0fbb3e2312 100644 --- a/ports/espressif/boards/deneyap_kart_g/mpconfigboard.mk +++ b/ports/espressif/boards/deneyap_kart_g/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 diff --git a/ports/espressif/boards/deneyap_mini/mpconfigboard.mk b/ports/espressif/boards/deneyap_mini/mpconfigboard.mk index 007b7ebc82abd..e446896107088 100644 --- a/ports/espressif/boards/deneyap_mini/mpconfigboard.mk +++ b/ports/espressif/boards/deneyap_mini/mpconfigboard.mk @@ -10,6 +10,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/deneyap_mini_v2/mpconfigboard.mk b/ports/espressif/boards/deneyap_mini_v2/mpconfigboard.mk index 457d4b9316142..9712e8437f772 100644 --- a/ports/espressif/boards/deneyap_mini_v2/mpconfigboard.mk +++ b/ports/espressif/boards/deneyap_mini_v2/mpconfigboard.mk @@ -13,5 +13,3 @@ CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_PSRAM_SIZE = 2MB CIRCUITPY_ESP_PSRAM_MODE = qio CIRCUITPY_ESP_PSRAM_FREQ = 80m - -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 diff --git a/ports/espressif/boards/doit_esp32_devkit_v1/mpconfigboard.mk b/ports/espressif/boards/doit_esp32_devkit_v1/mpconfigboard.mk index 9f657c6552dbe..bdac1e9559f07 100644 --- a/ports/espressif/boards/doit_esp32_devkit_v1/mpconfigboard.mk +++ b/ports/espressif/boards/doit_esp32_devkit_v1/mpconfigboard.mk @@ -6,6 +6,5 @@ IDF_TARGET = esp32 CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_ESPCAMERA = 0 -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 +CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/elecrow_crowpanel_4_2_epaper/board.c b/ports/espressif/boards/elecrow_crowpanel_4_2_epaper/board.c index 4567e2c595627..88150dd401b97 100644 --- a/ports/espressif/boards/elecrow_crowpanel_4_2_epaper/board.c +++ b/ports/espressif/boards/elecrow_crowpanel_4_2_epaper/board.c @@ -96,6 +96,7 @@ void board_init(void) { false, // always_toggle_chip_select false, // grayscale false, // acep + false, // spectra6 false, // two_byte_sequence_length false); // address_little_endian } diff --git a/ports/espressif/boards/espressif_esp32_devkitc_v4_wroom_32e/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32_devkitc_v4_wroom_32e/mpconfigboard.mk index 766196f9b30fc..495a505fe7616 100644 --- a/ports/espressif/boards/espressif_esp32_devkitc_v4_wroom_32e/mpconfigboard.mk +++ b/ports/espressif/boards/espressif_esp32_devkitc_v4_wroom_32e/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/espressif_esp32_eye/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32_eye/mpconfigboard.mk index 92d855842ff33..72eb1db85a012 100644 --- a/ports/espressif/boards/espressif_esp32_eye/mpconfigboard.mk +++ b/ports/espressif/boards/espressif_esp32_eye/mpconfigboard.mk @@ -13,8 +13,6 @@ CIRCUITPY_ESP_PSRAM_SIZE = 8MB CIRCUITPY_ESP_PSRAM_MODE = qio CIRCUITPY_ESP_PSRAM_FREQ = 40m -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_CANIO = 0 CIRCUITPY_NEOPIXEL_WRITE = 0 CIRCUITPY_PIXELBUF = 0 diff --git a/ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.mk index 4865e85502399..b1dd2f9f8774d 100644 --- a/ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.mk +++ b/ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.mk @@ -11,6 +11,4 @@ CIRCUITPY_ESP_PSRAM_SIZE = 4MB CIRCUITPY_ESP_PSRAM_MODE = qio CIRCUITPY_ESP_PSRAM_FREQ = 40m -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.mk index 5b4f4b7ead6d6..1bbb997a710d2 100644 --- a/ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.mk +++ b/ports/espressif/boards/espressif_esp32c3_devkitm_1_n4/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 diff --git a/ports/espressif/boards/espressif_esp32c6_devkitm_1_n4/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32c6_devkitm_1_n4/mpconfigboard.mk index 9685a7e62c59e..43759c3e2b6a2 100644 --- a/ports/espressif/boards/espressif_esp32c6_devkitm_1_n4/mpconfigboard.mk +++ b/ports/espressif/boards/espressif_esp32c6_devkitm_1_n4/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_AUDIOMP3 = 0 diff --git a/ports/espressif/boards/espressif_esp32h2_devkitm_1_n4/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32h2_devkitm_1_n4/mpconfigboard.mk index 82eb611bdf3d3..d1458fecec5fe 100644 --- a/ports/espressif/boards/espressif_esp32h2_devkitm_1_n4/mpconfigboard.mk +++ b/ports/espressif/boards/espressif_esp32h2_devkitm_1_n4/mpconfigboard.mk @@ -6,3 +6,6 @@ IDF_TARGET = esp32h2 CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 48m CIRCUITPY_ESP_FLASH_SIZE = 4MB + +# Board was originally defined with a 2MB firmware, almost 2MB user filesystem. Leave it that way. +CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT = 1 diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/board.c b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/board.c new file mode 100644 index 0000000000000..a3a9eec047145 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.h new file mode 100644 index 0000000000000..02fe72fe4a709 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.h @@ -0,0 +1,16 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup +#define MICROPY_HW_BOARD_NAME "ESP32-S3-DevKitC-1-N8R2 (ROS version)" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO48) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.mk new file mode 100644 index 0000000000000..336b9f4dd8926 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.mk @@ -0,0 +1,16 @@ +USB_VID = 0x303A +USB_PID = 0x7003 +USB_PRODUCT = "ESP32-S3-DevKitC-1-N8R2 CPY/ROS" +USB_MANUFACTURER = "Espressif" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_SIZE = 8MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 2MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 80m + +CIRCUITPY_RCLCPY = 1 diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/pins.c b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/pins.c new file mode 100644 index 0000000000000..3bb64f434d02f --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/pins.c @@ -0,0 +1,55 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO48) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/sdkconfig b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/sdkconfig new file mode 100644 index 0000000000000..e962866216039 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/espressif_esp8684_devkitc_02_n4/mpconfigboard.mk b/ports/espressif/boards/espressif_esp8684_devkitc_02_n4/mpconfigboard.mk index 0925e8de64d2b..3631493c26718 100644 --- a/ports/espressif/boards/espressif_esp8684_devkitc_02_n4/mpconfigboard.mk +++ b/ports/espressif/boards/espressif_esp8684_devkitc_02_n4/mpconfigboard.mk @@ -6,3 +6,6 @@ IDF_TARGET = esp32c2 CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 60m CIRCUITPY_ESP_FLASH_SIZE = 4MB + +# Board was originally defined with a 2MB firmware, almost 2MB user filesystem. Leave it that way. +CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT = 1 diff --git a/ports/espressif/boards/heltec_esp32s3_wifi_lora_v3/board.c b/ports/espressif/boards/heltec_esp32s3_wifi_lora_v3/board.c index 317fb0d88a1f0..d0ae146504234 100644 --- a/ports/espressif/boards/heltec_esp32s3_wifi_lora_v3/board.c +++ b/ports/espressif/boards/heltec_esp32s3_wifi_lora_v3/board.c @@ -34,10 +34,10 @@ uint8_t display_init_sequence[] = { // SSD1306 digitalio_digitalinout_obj_t display_on; static void display_init(void) { - // Need to bring GPIO21 high or the screen doesn't get power + // Need to bring GPIO36 high or the screen doesn't get power // & the board can't see the i2c bus at all. - common_hal_digitalio_digitalinout_construct(&display_on, &pin_GPIO21); - common_hal_digitalio_digitalinout_switch_to_output(&display_on, true, DRIVE_MODE_PUSH_PULL); + common_hal_digitalio_digitalinout_construct(&display_on, &pin_GPIO36); + common_hal_digitalio_digitalinout_switch_to_output(&display_on, false, DRIVE_MODE_PUSH_PULL); common_hal_digitalio_digitalinout_never_reset(&display_on); busio_i2c_obj_t *i2c = common_hal_board_create_i2c(0); @@ -48,7 +48,7 @@ static void display_init(void) { bus, i2c, 0x3c, - NULL + &pin_GPIO21 // broken-out on V3 ); busdisplay_busdisplay_obj_t *display = &allocate_display()->display; diff --git a/ports/espressif/boards/heltec_vision_master_e290/board.c b/ports/espressif/boards/heltec_vision_master_e290/board.c index cc8afe226be95..e392f65a76432 100644 --- a/ports/espressif/boards/heltec_vision_master_e290/board.c +++ b/ports/espressif/boards/heltec_vision_master_e290/board.c @@ -94,6 +94,7 @@ void board_init(void) { false, // always_toggle_chip_select false, // grayscale false, // acep + false, // spectra6 false, // two_byte_sequence_length true); // address_little_endian } diff --git a/ports/espressif/boards/heltec_wireless_paper/board.c b/ports/espressif/boards/heltec_wireless_paper/board.c index 2807f2d1a2012..28fb6ae41b9a1 100644 --- a/ports/espressif/boards/heltec_wireless_paper/board.c +++ b/ports/espressif/boards/heltec_wireless_paper/board.c @@ -134,6 +134,7 @@ void board_init(void) { false, // always_toggle_chip_select false, // grayscale false, // acep + false, // spectra6 false, // two_byte_sequence_length false); // address_little_endian } diff --git a/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk b/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk index 0fd65d99d6eea..8550c526defc4 100644 --- a/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk +++ b/ports/espressif/boards/lilygo_ttgo_t-01c3/mpconfigboard.mk @@ -8,3 +8,6 @@ CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 + +# Board was originally defined with a 2MB firmware, almost 2MB user filesystem. Leave it that way. +CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT = 1 diff --git a/ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.mk b/ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.mk index d7eba6ea262ce..35ac1d44c6230 100644 --- a/ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.mk +++ b/ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 diff --git a/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_4m/mpconfigboard.mk b/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_4m/mpconfigboard.mk index af1bd8b178980..56912e66645ac 100644 --- a/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_4m/mpconfigboard.mk +++ b/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_4m/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/lolin_c3_mini/mpconfigboard.mk b/ports/espressif/boards/lolin_c3_mini/mpconfigboard.mk index 5d5ab2d91ec50..99c910e6d2456 100644 --- a/ports/espressif/boards/lolin_c3_mini/mpconfigboard.mk +++ b/ports/espressif/boards/lolin_c3_mini/mpconfigboard.mk @@ -7,10 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE=qio CIRCUITPY_ESP_FLASH_FREQ=80m CIRCUITPY_ESP_FLASH_SIZE=4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - -# Not enough flash -CIRCUITPY_SOCKETPOOL_IPV6 = 0 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 -CIRCUITPY_TILEPALETTEMAPPER = 0 diff --git a/ports/espressif/boards/lolin_c3_pico/mpconfigboard.mk b/ports/espressif/boards/lolin_c3_pico/mpconfigboard.mk index 25027d4c97b8d..6778550a2d108 100644 --- a/ports/espressif/boards/lolin_c3_pico/mpconfigboard.mk +++ b/ports/espressif/boards/lolin_c3_pico/mpconfigboard.mk @@ -7,12 +7,7 @@ CIRCUITPY_ESP_FLASH_MODE=qio CIRCUITPY_ESP_FLASH_FREQ=80m CIRCUITPY_ESP_FLASH_SIZE=4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 -# Not enough flash -CIRCUITPY_SOCKETPOOL_IPV6 = 0 - # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel diff --git a/ports/espressif/boards/lolin_c3_pico/sdkconfig b/ports/espressif/boards/lolin_c3_pico/sdkconfig index 3d0800e10d9ac..e962866216039 100644 --- a/ports/espressif/boards/lolin_c3_pico/sdkconfig +++ b/ports/espressif/boards/lolin_c3_pico/sdkconfig @@ -7,7 +7,6 @@ # # LWIP # -# CONFIG_LWIP_IPV6 is not set # end of LWIP # end of Component config diff --git a/ports/espressif/boards/luatos_core_esp32c3/mpconfigboard.mk b/ports/espressif/boards/luatos_core_esp32c3/mpconfigboard.mk index ea3c7a44621f1..03f5171a3102c 100644 --- a/ports/espressif/boards/luatos_core_esp32c3/mpconfigboard.mk +++ b/ports/espressif/boards/luatos_core_esp32c3/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE=dio CIRCUITPY_ESP_FLASH_FREQ=80m CIRCUITPY_ESP_FLASH_SIZE=4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 diff --git a/ports/espressif/boards/luatos_core_esp32c3_ch343/mpconfigboard.mk b/ports/espressif/boards/luatos_core_esp32c3_ch343/mpconfigboard.mk index bb793f0f26297..9e777889c0f73 100644 --- a/ports/espressif/boards/luatos_core_esp32c3_ch343/mpconfigboard.mk +++ b/ports/espressif/boards/luatos_core_esp32c3_ch343/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE=dio CIRCUITPY_ESP_FLASH_FREQ=80m CIRCUITPY_ESP_FLASH_SIZE=4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 diff --git a/ports/espressif/boards/m5stack_atom_echo/mpconfigboard.mk b/ports/espressif/boards/m5stack_atom_echo/mpconfigboard.mk index a40381f8a3487..8ae3dfce95fa7 100644 --- a/ports/espressif/boards/m5stack_atom_echo/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_atom_echo/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/m5stack_atom_lite/mpconfigboard.mk b/ports/espressif/boards/m5stack_atom_lite/mpconfigboard.mk index 215fd976df361..ff7db6a63b723 100644 --- a/ports/espressif/boards/m5stack_atom_lite/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_atom_lite/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.mk b/ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.mk index 081750d143f9b..298082eb6bed3 100644 --- a/ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/m5stack_atom_u/mpconfigboard.mk b/ports/espressif/boards/m5stack_atom_u/mpconfigboard.mk index abcd5f8724d8e..20ef88d601c71 100644 --- a/ports/espressif/boards/m5stack_atom_u/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_atom_u/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/m5stack_cardputer_ros/board.c b/ports/espressif/boards/m5stack_cardputer_ros/board.c new file mode 100644 index 0000000000000..6fdc2f8ea5c46 --- /dev/null +++ b/ports/espressif/boards/m5stack_cardputer_ros/board.c @@ -0,0 +1,95 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "mpconfigboard.h" +#include "supervisor/board.h" +#include "supervisor/shared/serial.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" +#include "py/runtime.h" +#include "py/ringbuf.h" +#include "shared/runtime/interrupt_char.h" + + +#define DELAY 0x80 + +uint8_t display_init_sequence[] = { + // SWRESET and Delay 140ms + 0x01, 0 | DELAY, 140, + // SLPOUT and Delay 10ms + 0x11, 0 | DELAY, 10, + // COLMOD 65k colors and 16 bit 5-6-5 + 0x3A, 1, 0x55, + // INVON Iiversion on + 0x21, 0, + // NORON normal operation (full update) + 0x13, 0, + // MADCTL columns RTL, page/column reverse order + 0x36, 1, 0x60, + // RAMCTRL color word little endian + 0xB0, 2, 0x00, 0xF8, + // DIPON display on + 0x29, 0, +}; + + +// Overrides the weakly linked function from supervisor/shared/board.c +void board_init(void) { + busio_spi_obj_t *spi = common_hal_board_create_spi(0); + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + bus->base.type = &fourwire_fourwire_type; + + // see here for inspiration: https://github.com/m5stack/M5GFX/blob/33d7d3135e816a86a008fae8ab3757938cee95d2/src/M5GFX.cpp#L1350 + common_hal_fourwire_fourwire_construct( + bus, + spi, + &pin_GPIO34, // DC + &pin_GPIO37, // CS + &pin_GPIO33, // RST + 40000000, // baudrate + 0, // polarity + 0 // phase + ); + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 240, // width (after rotation) + 135, // height (after rotation) + 40, // column start + 53, // row start + 0, // rotation + 16, // color depth + false, // grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + false, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO38, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 350 // backlight pwm frequency + ); +} + +// TODO: Should we turn off the display when asleep, in board_deinit() ? diff --git a/ports/espressif/boards/m5stack_cardputer_ros/cardputer_keyboard.c b/ports/espressif/boards/m5stack_cardputer_ros/cardputer_keyboard.c new file mode 100644 index 0000000000000..73880f66e19d9 --- /dev/null +++ b/ports/espressif/boards/m5stack_cardputer_ros/cardputer_keyboard.c @@ -0,0 +1,238 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/objstr.h" +#include "py/runtime.h" + +#include "supervisor/shared/serial.h" +#include "shared-bindings/keypad/EventQueue.h" +#include "shared-bindings/keypad_demux/DemuxKeyMatrix.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/keypad/EventQueue.h" +#include "shared-module/keypad_demux/DemuxKeyMatrix.h" +#include "supervisor/shared/reload.h" + +#include "keymap.h" + +//| """M5Stack Cardputer keyboard integration. +//| """ +//| +//| """The KEYBOARD object is an instance of DemuxKeyMatrix, configured with correct pins. +//| The pins cannot be used for any other purposes (even though exposed in the board module). +//| By default all keyboard events are consumed and routed to the standard input - there is +//| not much use of the KEYBOARD object in this configuration - just read the input via sys.stdin. +//| +//| If you need to manually process individual key up / key down events via KEYBOARD.events, +//| call `detach_serial()`. +//| """" +//| KEYBOARD: keypad_demux.DemuxKeymatrix +//| +keypad_demux_demuxkeymatrix_obj_t cardputer_keyboard_obj; +bool cardputer_keyboard_serial_attached = false; + +void cardputer_keyboard_init(void); +void keyboard_seq(const char *seq); +void update_keyboard(keypad_eventqueue_obj_t *queue); + +//| def detach_serial() -> None: +//| """Stops consuming keyboard events and routing them to sys.stdin.""" +//| ... +//| +static mp_obj_t detach_serial(void) { + cardputer_keyboard_serial_attached = false; + common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard_obj.events, NULL); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_0(detach_serial_obj, detach_serial); + +//| def attach_serial() -> None: +//| """Starts consuming keyboard events and routing them to sys.stdin.""" +//| ... +//| +static mp_obj_t attach_serial(void) { + common_hal_keypad_eventqueue_set_event_handler(cardputer_keyboard_obj.events, update_keyboard); + cardputer_keyboard_serial_attached = true; + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_0(attach_serial_obj, attach_serial); + +//| def key_to_char(key: int, shifted: bool) -> str | None: +//| """Converts a key index to the respective key (with or without shift modifier). +//| Returns None for functional & modifier keys or whenever not 0 <= key < 56. +//| """ +//| ... +//| +static mp_obj_t key_to_char(mp_obj_t key_obj, mp_obj_t shifted_obj) { + mp_int_t key = mp_obj_get_int(key_obj); + if (key < 0 || key > (mp_int_t)(sizeof keymap / sizeof *keymap) || keymap[key] == 0) { + return mp_const_none; + } else if (shifted_obj == mp_const_true) { + return mp_obj_new_str(&keymap_shifted[key], 1); + } else { + return mp_obj_new_str(&keymap[key], 1); + } +} +static MP_DEFINE_CONST_FUN_OBJ_2(key_to_char_obj, key_to_char); + +// Ring buffer of characters consumed from keyboard events (when serial attached) +ringbuf_t keyqueue; +char keybuf[32]; + +keypad_event_obj_t event; +char keystate[56]; + +// Keyboard pins +const mcu_pin_obj_t *row_addr_pins[] = { + &pin_GPIO8, + &pin_GPIO9, + &pin_GPIO11, +}; + +const mcu_pin_obj_t *column_pins[] = { + &pin_GPIO13, + &pin_GPIO15, + &pin_GPIO3, + &pin_GPIO4, + &pin_GPIO5, + &pin_GPIO6, + &pin_GPIO7 +}; + +void cardputer_keyboard_init(void) { + cardputer_keyboard_obj.base.type = &keypad_demux_demuxkeymatrix_type; + common_hal_keypad_demux_demuxkeymatrix_construct( + &cardputer_keyboard_obj, // self + 3, // num_row_addr_pins + row_addr_pins, // row_addr_pins + 7, // num_column_pins + column_pins, // column_pins + true, // columns_to_anodes + false, // transpose + 0.01f, // interval + 20, // max_events + 2 // debounce_threshold + ); + demuxkeymatrix_never_reset(&cardputer_keyboard_obj); + + ringbuf_init(&keyqueue, (uint8_t *)keybuf, sizeof(keybuf)); + attach_serial(); +} + +// Overrides the weakly linked function from supervisor/shared/serial.c +void board_serial_init(void) { + cardputer_keyboard_init(); +} + +// Overrides the weakly linked function from supervisor/shared/serial.c +bool board_serial_connected(void) { + return cardputer_keyboard_serial_attached; +} + +// Overrides the weakly linked function from supervisor/shared/serial.c +uint32_t board_serial_bytes_available(void) { + if (cardputer_keyboard_serial_attached) { + return ringbuf_num_filled(&keyqueue); + } else { + return 0; + } +} + +// Overrides the weakly linked function from supervisor/shared/serial.c +char board_serial_read(void) { + if (cardputer_keyboard_serial_attached) { + return ringbuf_get(&keyqueue); + } else { + return 0; + } +} + +void keyboard_seq(const char *seq) { + while (*seq) { + ringbuf_put(&keyqueue, *seq++); + } +} + +void update_keyboard(keypad_eventqueue_obj_t *queue) { + uint8_t ascii = 0; + + if (common_hal_keypad_eventqueue_get_length(queue) == 0) { + return; + } + + while (common_hal_keypad_eventqueue_get_into(queue, &event)) { + if (event.pressed) { + keystate[event.key_number] = 1; + + if (keystate[KEY_CTRL]) { + if (keystate[KEY_ALT] && keystate[KEY_BACKSPACE]) { + reload_initiate(RUN_REASON_REPL_RELOAD); + } + ascii = keymap[event.key_number]; + if (ascii >= 'a' && ascii <= 'z') { + ascii -= 'a' - 1; + } + + if (ascii == mp_interrupt_char) { + mp_sched_keyboard_interrupt(); + } + } else if (keystate[KEY_SHIFT]) { + ascii = keymap_shifted[event.key_number]; + } else if (keystate[KEY_FN] && event.key_number != KEY_FN) { + switch (event.key_number | FN_MOD) + { + case KEY_DOWN: + keyboard_seq("\e[B"); + break; + case KEY_UP: + keyboard_seq("\e[A"); + break; + case KEY_DELETE: + keyboard_seq("\e[3~"); + break; + case KEY_LEFT: + keyboard_seq("\e[D"); + break; + case KEY_RIGHT: + keyboard_seq("\e[C"); + break; + case KEY_ESC: + ringbuf_put(&keyqueue, '\e'); + break; + } + } else { + ascii = keymap[event.key_number]; + } + + if (ascii > 0) { + if (keystate[KEY_ALT]) { + ringbuf_put(&keyqueue, '\e'); + } else if (keystate[KEY_OPT]) { + ringbuf_put(&keyqueue, '\x10'); + } + ringbuf_put(&keyqueue, ascii); + } + } else { + keystate[event.key_number] = 0; + } + } +} + +static const mp_rom_map_elem_t cardputer_keyboard_module_globals_table[] = { + {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_cardputer_keyboard)}, + {MP_ROM_QSTR(MP_QSTR_KEYBOARD), MP_ROM_PTR(&cardputer_keyboard_obj)}, + {MP_ROM_QSTR(MP_QSTR_attach_serial), MP_ROM_PTR(&attach_serial_obj)}, + {MP_ROM_QSTR(MP_QSTR_detach_serial), MP_ROM_PTR(&detach_serial_obj)}, + {MP_ROM_QSTR(MP_QSTR_key_to_char), MP_ROM_PTR(&key_to_char_obj)}, +}; +MP_DEFINE_CONST_DICT(cardputer_keyboard_module_globals, cardputer_keyboard_module_globals_table); + +const mp_obj_module_t cardputer_keyboard_module = { + .base = {&mp_type_module}, + .globals = (mp_obj_dict_t *)&cardputer_keyboard_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_cardputer_keyboard, cardputer_keyboard_module); diff --git a/ports/espressif/boards/m5stack_cardputer_ros/keymap.h b/ports/espressif/boards/m5stack_cardputer_ros/keymap.h new file mode 100644 index 0000000000000..0256fafaa0f57 --- /dev/null +++ b/ports/espressif/boards/m5stack_cardputer_ros/keymap.h @@ -0,0 +1,214 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define SHIFT_MOD 0x40 +#define FN_MOD 0x80 + +#define KEY_OPT 0 +#define KEY_Z 1 +#define KEY_C 2 +#define KEY_B 3 +#define KEY_M 4 +#define KEY_DOT 5 +#define KEY_SPACE 6 +#define KEY_SHIFT 7 +#define KEY_S 8 +#define KEY_F 9 +#define KEY_H 10 +#define KEY_K 11 +#define KEY_SEMICOLON 12 +#define KEY_ENTER 13 +#define KEY_Q 14 +#define KEY_E 15 +#define KEY_T 16 +#define KEY_U 17 +#define KEY_O 18 +#define KEY_LEFT_BRACKET 19 +#define KEY_BACKSLASH 20 +#define KEY_1 21 +#define KEY_3 22 +#define KEY_5 23 +#define KEY_7 24 +#define KEY_9 25 +#define KEY_UNDERSCORE 26 +#define KEY_BACKSPACE 27 +#define KEY_CTRL 28 +#define KEY_ALT 29 +#define KEY_X 30 +#define KEY_V 31 +#define KEY_N 32 +#define KEY_COMMA 33 +#define KEY_SLASH 34 +#define KEY_FN 35 +#define KEY_A 36 +#define KEY_D 37 +#define KEY_G 38 +#define KEY_J 39 +#define KEY_L 40 +#define KEY_APOSTROPHE 41 +#define KEY_TAB 42 +#define KEY_W 43 +#define KEY_R 44 +#define KEY_Y 45 +#define KEY_I 46 +#define KEY_P 47 +#define KEY_RIGHT_BRACKET 48 +#define KEY_GRAVE 49 +#define KEY_2 50 +#define KEY_4 51 +#define KEY_6 52 +#define KEY_8 53 +#define KEY_0 54 +#define KEY_EQUALS 55 + +#define KEY_GREATER (5 | SHIFT_MOD) +#define KEY_COLON (12 | SHIFT_MOD) +#define KEY_LEFT_CURLY_BRACKET (19 | SHIFT_MOD) +#define KEY_PIPE (20 | SHIFT_MOD) +#define KEY_EXCLAMATION (21 | SHIFT_MOD) +#define KEY_HASH (22 | SHIFT_MOD) +#define KEY_PERCENT (23 | SHIFT_MOD) +#define KEY_AMPERSAND (24 | SHIFT_MOD) +#define KEY_OPEN_PARENTHESIS (25 | SHIFT_MOD) +#define KEY_MINUS (26 | SHIFT_MOD) +#define KEY_LESS (33 | SHIFT_MOD) +#define KEY_QUESTION (34 | SHIFT_MOD) +#define KEY_DOUBLE_QUOTE (41 | SHIFT_MOD) +#define KEY_RIGHT_CURLY_BRACKET (48 | SHIFT_MOD) +#define KEY_TILDE (49 | SHIFT_MOD) +#define KEY_AT (50 | SHIFT_MOD) +#define KEY_DOLLAR (51 | SHIFT_MOD) +#define KEY_CARET (52 | SHIFT_MOD) +#define KEY_ASTERISK (53 | SHIFT_MOD) +#define KEY_CLOSE_PARENTHESIS (54 | SHIFT_MOD) +#define KEY_PLUS (55 | SHIFT_MOD) + +#define KEY_DOWN (5 | FN_MOD) +#define KEY_UP (12 | FN_MOD) +#define KEY_DELETE (27 | FN_MOD) +#define KEY_LEFT (33 | FN_MOD) +#define KEY_RIGHT (34 | FN_MOD) +#define KEY_ESC (49 | FN_MOD) + +const char keymap[56] = { + 0, // KEY_OPT + 'z', // KEY_Z + 'c', // KEY_C + 'b', // KEY_B + 'm', // KEY_M + '.', // KEY_DOT + ' ', // KEY_SPACE + 0, // KEY_SHIFT + 's', // KEY_S + 'f', // KEY_F + 'h', // KEY_H + 'k', // KEY_K + ';', // KEY_SEMICOLON + '\r',// KEY_ENTER + 'q', // KEY_Q + 'e', // KEY_E + 't', // KEY_T + 'u', // KEY_U + 'o', // KEY_O + '[', // KEY_LEFT_BRACKET + '\\',// KEY_BACKSLASH + '1', // KEY_1 + '3', // KEY_3 + '5', // KEY_5 + '7', // KEY_7 + '9', // KEY_9 + '_', // KEY_UNDERSCORE + '\b',// KEY_BACKSPACE + 0, // KEY_CTRL + 0, // KEY_ALT + 'x', // KEY_X + 'v', // KEY_V + 'n', // KEY_N + ',', // KEY_COMMA + '/', // KEY_SLASH + 0, // KEY_FN + 'a', // KEY_A + 'd', // KEY_D + 'g', // KEY_G + 'j', // KEY_J + 'l', // KEY_L + '\'',// KEY_APOSTROPHE + '\t',// KEY_TAB + 'w', // KEY_W + 'r', // KEY_R + 'y', // KEY_Y + 'i', // KEY_I + 'p', // KEY_P + ']', // KEY_RIGHT_BRACKET + '`', // KEY_GRAVE + '2', // KEY_2 + '4', // KEY_4 + '6', // KEY_6 + '8', // KEY_8 + '0', // KEY_0 + '=' // KEY_EQUALS +}; + +const char keymap_shifted[56] = { + 0, // KEY_OPT + 'Z', // KEY_Z + 'C', // KEY_C + 'B', // KEY_B + 'M', // KEY_M + '>', // KEY_DOT -> '>' + ' ', // KEY_SPACE + 0, // KEY_SHIFT + 'S', // KEY_S + 'F', // KEY_F + 'H', // KEY_H + 'K', // KEY_K + ':', // KEY_SEMICOLON -> ':' + '\r',// KEY_ENTER + 'Q', // KEY_Q + 'E', // KEY_E + 'T', // KEY_T + 'U', // KEY_U + 'O', // KEY_O + '{', // KEY_LEFT_BRACKET -> '{' + '|', // KEY_BACKSLASH -> '|' + '!', // KEY_1 -> '!' + '#', // KEY_3 -> '#' + '%', // KEY_5 -> '%' + '&', // KEY_7 -> '&' + '(', // KEY_9 -> '(' + '-', // KEY_UNDERSCORE -> '-' + '\b',// KEY_BACKSPACE + 0, // KEY_CTRL + 0, // KEY_ALT + 'X', // KEY_X + 'V', // KEY_V + 'N', // KEY_N + '<', // KEY_COMMA -> '<' + '?', // KEY_SLASH -> '?' + 0, // KEY_FN + 'A', // KEY_A + 'D', // KEY_D + 'G', // KEY_G + 'J', // KEY_J + 'L', // KEY_L + '"', // KEY_APOSTROPHE -> '"' + '\t',// KEY_TAB + 'W', // KEY_W + 'R', // KEY_R + 'Y', // KEY_Y + 'I', // KEY_I + 'P', // KEY_P + '}', // KEY_RIGHT_BRACKET -> '}' + '~', // KEY_GRAVE -> '~' + '@', // KEY_2 -> '@' + '$', // KEY_4 -> '$' + '^', // KEY_6 -> '^' + '*', // KEY_8 -> '*' + ')', // KEY_0 -> ')' + '+' // KEY_EQUALS -> '+' +}; diff --git a/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.h b/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.h new file mode 100644 index 0000000000000..4b62c7d76e6a1 --- /dev/null +++ b/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.h @@ -0,0 +1,19 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "M5Stack Cardputer (ROS version)" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO21) +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO1) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO2) +#define CIRCUITPY_BOARD_SPI (2) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO36, .mosi = &pin_GPIO35}, \ + {.clock = &pin_GPIO40, .mosi = &pin_GPIO14, .miso = &pin_GPIO39}} diff --git a/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk b/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk new file mode 100644 index 0000000000000..8d296939a1a7b --- /dev/null +++ b/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk @@ -0,0 +1,17 @@ +USB_VID = 0x303A +USB_PID = 0x81DA +USB_PRODUCT = "M5Stack Cardputer - Circuitpython/ROS" +USB_MANUFACTURER = "M5STACK" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB +CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_RCLCPY = 1 + +CIRCUITPY_GIFIO = 1 +CIRCUITPY_MAX3421E = 0 + +SRC_C += boards/$(BOARD)/cardputer_keyboard.c diff --git a/ports/espressif/boards/m5stack_cardputer_ros/pins.c b/ports/espressif/boards/m5stack_cardputer_ros/pins.c new file mode 100644 index 0000000000000..ba309e0dcbff1 --- /dev/null +++ b/ports/espressif/boards/m5stack_cardputer_ros/pins.c @@ -0,0 +1,86 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +#include "shared-module/displayio/__init__.h" +CIRCUITPY_BOARD_BUS_SINGLETON(sd_spi, spi, 1) +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // Port A + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_PORTA1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_G1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_PORTA2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_G2), MP_ROM_PTR(&pin_GPIO2) }, + + // Keyboard + { MP_ROM_QSTR(MP_QSTR_KB_COL_0), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_KB_COL_1), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_KB_COL_2), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_KB_COL_3), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_KB_COL_4), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_KB_COL_5), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_KB_COL_6), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_KB_A_0), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_KB_A_1), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_KB_A_2), MP_ROM_PTR(&pin_GPIO11) }, + + // Neopixel + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO21) }, + + // Speaker + { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DATA), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WORD_SELECT), MP_ROM_PTR(&pin_GPIO43) }, + + // Mic + { MP_ROM_QSTR(MP_QSTR_MIC_DATA), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_MIC_CLK), MP_ROM_PTR(&pin_GPIO43) }, + + // IR + { MP_ROM_QSTR(MP_QSTR_IR_TX), MP_ROM_PTR(&pin_GPIO44) }, + + // SD + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO12) }, + + + // Display + { MP_ROM_QSTR(MP_QSTR_TFT_RST), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_TFT_RS), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_TFT_MOSI), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_TFT_DATA), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_TFT_SCK), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_TFT_BACKLIGHT), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_TFT_BL), MP_ROM_PTR(&pin_GPIO38) }, + + // Button + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO0) }, + + // Battery + { MP_ROM_QSTR(MP_QSTR_BAT_ADC), MP_ROM_PTR(&pin_GPIO10) }, + + // Other + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_PORTA_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_TFT_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_SD_SPI), MP_ROM_PTR(&board_sd_spi_obj) }, + + // Display object + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/m5stack_cardputer_ros/sdkconfig b/ports/espressif/boards/m5stack_cardputer_ros/sdkconfig new file mode 100644 index 0000000000000..e962866216039 --- /dev/null +++ b/ports/espressif/boards/m5stack_cardputer_ros/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/m5stack_m5paper/board.c b/ports/espressif/boards/m5stack_m5paper/board.c index fbf66fa5ccdf9..db68df79c4291 100644 --- a/ports/espressif/boards/m5stack_m5paper/board.c +++ b/ports/espressif/boards/m5stack_m5paper/board.c @@ -74,6 +74,7 @@ void board_init(void) { // false, // always_toggle_chip_select // false, // grayscale // true, // acep + // false, // spectra6 // false, // two_byte_sequence_length // false // address_little_endian // ); diff --git a/ports/espressif/boards/m5stack_stamp_c3/mpconfigboard.mk b/ports/espressif/boards/m5stack_stamp_c3/mpconfigboard.mk index 2c856c6fc0030..2f3b62f90fac9 100644 --- a/ports/espressif/boards/m5stack_stamp_c3/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_stamp_c3/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE=qio CIRCUITPY_ESP_FLASH_FREQ=80m CIRCUITPY_ESP_FLASH_SIZE=4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 diff --git a/ports/espressif/boards/m5stack_stick_c/mpconfigboard.mk b/ports/espressif/boards/m5stack_stick_c/mpconfigboard.mk index ce94e71dff2a0..4454fdb9d712c 100644 --- a/ports/espressif/boards/m5stack_stick_c/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_stick_c/mpconfigboard.mk @@ -6,8 +6,7 @@ IDF_TARGET = esp32 CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_ESPCAMERA = 0 -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 +CIRCUITPY_ESPCAMERA = 0 SRC_C += pmic/axp192/axp192.c diff --git a/ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.mk b/ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.mk index bee1fc7e7811f..6941931977d18 100644 --- a/ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.mk @@ -6,8 +6,7 @@ IDF_TARGET = esp32 CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_ESPCAMERA = 0 -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 +CIRCUITPY_ESPCAMERA = 0 SRC_C += pmic/axp192/axp192.c diff --git a/ports/espressif/boards/m5stack_timer_camera_x/mpconfigboard.mk b/ports/espressif/boards/m5stack_timer_camera_x/mpconfigboard.mk index 4fcacd94d3d29..e17f5061d9e85 100644 --- a/ports/espressif/boards/m5stack_timer_camera_x/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_timer_camera_x/mpconfigboard.mk @@ -10,5 +10,3 @@ CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESP_PSRAM_SIZE = 8MB CIRCUITPY_ESP_PSRAM_MODE = opi CIRCUITPY_ESP_PSRAM_FREQ = 80m - -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 diff --git a/ports/espressif/boards/makergo_esp32c3_supermini/mpconfigboard.mk b/ports/espressif/boards/makergo_esp32c3_supermini/mpconfigboard.mk index 37c27203af31c..d82f62df37791 100644 --- a/ports/espressif/boards/makergo_esp32c3_supermini/mpconfigboard.mk +++ b/ports/espressif/boards/makergo_esp32c3_supermini/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE=dio CIRCUITPY_ESP_FLASH_FREQ=80m CIRCUITPY_ESP_FLASH_SIZE=4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 diff --git a/ports/espressif/boards/makergo_esp32c6_supermini/mpconfigboard.mk b/ports/espressif/boards/makergo_esp32c6_supermini/mpconfigboard.mk index 54078559d7be2..ca425c0159332 100644 --- a/ports/espressif/boards/makergo_esp32c6_supermini/mpconfigboard.mk +++ b/ports/espressif/boards/makergo_esp32c6_supermini/mpconfigboard.mk @@ -6,3 +6,6 @@ IDF_TARGET = esp32c6 CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB + +# Board was originally defined with a 2MB firmware, almost 2MB user filesystem. Leave it that way. +CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT = 1 diff --git a/ports/espressif/boards/microdev_micro_c3/mpconfigboard.mk b/ports/espressif/boards/microdev_micro_c3/mpconfigboard.mk index fa51216e911a1..79821f7c0e5d1 100644 --- a/ports/espressif/boards/microdev_micro_c3/mpconfigboard.mk +++ b/ports/espressif/boards/microdev_micro_c3/mpconfigboard.mk @@ -7,7 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 -CIRCUITPY_TILEPALETTEMAPPER = 0 diff --git a/ports/espressif/boards/nodemcu_esp32c2/mpconfigboard.mk b/ports/espressif/boards/nodemcu_esp32c2/mpconfigboard.mk index dd90b325b6d3b..249dd80bebdd1 100644 --- a/ports/espressif/boards/nodemcu_esp32c2/mpconfigboard.mk +++ b/ports/espressif/boards/nodemcu_esp32c2/mpconfigboard.mk @@ -6,3 +6,6 @@ IDF_TARGET = esp32c2 CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 60m CIRCUITPY_ESP_FLASH_SIZE = 4MB + +# Board was originally defined with a 2MB firmware, almost 2MB user filesystem. Leave it that way. +CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT = 1 diff --git a/ports/espressif/boards/seeed_xiao_esp32c3/mpconfigboard.mk b/ports/espressif/boards/seeed_xiao_esp32c3/mpconfigboard.mk index b71a41ef6e31a..c5b266ca74435 100644 --- a/ports/espressif/boards/seeed_xiao_esp32c3/mpconfigboard.mk +++ b/ports/espressif/boards/seeed_xiao_esp32c3/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 diff --git a/ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.mk b/ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.mk index 9d95fe9444969..ce6763afbcc3c 100644 --- a/ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.mk +++ b/ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.mk @@ -6,3 +6,6 @@ IDF_TARGET = esp32c6 CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB + +# Board was originally defined with a 2MB firmware, almost 2MB user filesystem. Leave it that way. +CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT = 1 diff --git a/ports/espressif/boards/spotpear_esp32c3_lcd_1_44/mpconfigboard.mk b/ports/espressif/boards/spotpear_esp32c3_lcd_1_44/mpconfigboard.mk index 87fc8a72f3edf..c876b7c7a4eef 100644 --- a/ports/espressif/boards/spotpear_esp32c3_lcd_1_44/mpconfigboard.mk +++ b/ports/espressif/boards/spotpear_esp32c3_lcd_1_44/mpconfigboard.mk @@ -8,4 +8,3 @@ CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 diff --git a/ports/espressif/boards/sqfmi_watchy/board.c b/ports/espressif/boards/sqfmi_watchy/board.c index 25a7be4613c6e..393b8b759028a 100644 --- a/ports/espressif/boards/sqfmi_watchy/board.c +++ b/ports/espressif/boards/sqfmi_watchy/board.c @@ -190,6 +190,7 @@ void board_init(void) { false, // always_toggle_chip_select false, // grayscale false, // acep + false, // spectra6 false, // two_byte_sequence_length true // address_little_endian ); diff --git a/ports/espressif/boards/sqfmi_watchy/mpconfigboard.mk b/ports/espressif/boards/sqfmi_watchy/mpconfigboard.mk index 520894ea70a11..7451083de642d 100644 --- a/ports/espressif/boards/sqfmi_watchy/mpconfigboard.mk +++ b/ports/espressif/boards/sqfmi_watchy/mpconfigboard.mk @@ -1,13 +1,10 @@ CIRCUITPY_CREATOR_ID = 0x4496E3F4 CIRCUITPY_CREATION_ID = 0x00320024 - -CIRCUITPY_ESPCAMERA = 0 +IDF_TARGET = esp32 CIRCUITPY_ESP_FLASH_MODE=dio CIRCUITPY_ESP_FLASH_FREQ=40m CIRCUITPY_ESP_FLASH_SIZE=4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - -IDF_TARGET = esp32 +CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/sunton_esp32_2424S012/mpconfigboard.mk b/ports/espressif/boards/sunton_esp32_2424S012/mpconfigboard.mk index 2a84d801bc325..e08fc26babf25 100644 --- a/ports/espressif/boards/sunton_esp32_2424S012/mpconfigboard.mk +++ b/ports/espressif/boards/sunton_esp32_2424S012/mpconfigboard.mk @@ -7,6 +7,7 @@ CIRCUITPY_ESP_FLASH_MODE=qio CIRCUITPY_ESP_FLASH_FREQ=80m CIRCUITPY_ESP_FLASH_SIZE=4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 + +# Not enough flash space. +CIRCUITPY_CODEOP = 0 diff --git a/ports/espressif/boards/sunton_esp32_2432S024C/mpconfigboard.mk b/ports/espressif/boards/sunton_esp32_2432S024C/mpconfigboard.mk index 0b988886cb675..dadd6e11f3df6 100644 --- a/ports/espressif/boards/sunton_esp32_2432S024C/mpconfigboard.mk +++ b/ports/espressif/boards/sunton_esp32_2432S024C/mpconfigboard.mk @@ -8,7 +8,3 @@ CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESPCAMERA = 0 - -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - -CIRCUITPY_BUILD_EXTENSIONS = bin diff --git a/ports/espressif/boards/sunton_esp32_2432S028/mpconfigboard.mk b/ports/espressif/boards/sunton_esp32_2432S028/mpconfigboard.mk index 444c80227ab01..a37e9420d6ae5 100644 --- a/ports/espressif/boards/sunton_esp32_2432S028/mpconfigboard.mk +++ b/ports/espressif/boards/sunton_esp32_2432S028/mpconfigboard.mk @@ -8,5 +8,3 @@ CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESPCAMERA = 0 - -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 diff --git a/ports/espressif/boards/unexpectedmaker_tinypico/mpconfigboard.mk b/ports/espressif/boards/unexpectedmaker_tinypico/mpconfigboard.mk index 4086abba11ea2..80acff0ca4905 100644 --- a/ports/espressif/boards/unexpectedmaker_tinypico/mpconfigboard.mk +++ b/ports/espressif/boards/unexpectedmaker_tinypico/mpconfigboard.mk @@ -10,5 +10,3 @@ CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_PSRAM_SIZE = 8MB CIRCUITPY_ESP_PSRAM_MODE = qio CIRCUITPY_ESP_PSRAM_FREQ = 80m - -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 diff --git a/ports/espressif/boards/unexpectedmaker_tinypico_nano/mpconfigboard.mk b/ports/espressif/boards/unexpectedmaker_tinypico_nano/mpconfigboard.mk index 550e0d4a76c32..c919aff8aef23 100644 --- a/ports/espressif/boards/unexpectedmaker_tinypico_nano/mpconfigboard.mk +++ b/ports/espressif/boards/unexpectedmaker_tinypico_nano/mpconfigboard.mk @@ -10,5 +10,3 @@ CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_PSRAM_SIZE = 8MB CIRCUITPY_ESP_PSRAM_MODE = qio CIRCUITPY_ESP_PSRAM_FREQ = 80m - -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 diff --git a/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.mk index 0d0930984ebd7..e838f8ad2e5e8 100644 --- a/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.mk +++ b/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.mk @@ -6,3 +6,6 @@ IDF_TARGET = esp32c6 CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB + +# Board was originally defined with a 2MB firmware, almost 2MB user filesystem. Leave it that way. +CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT = 1 diff --git a/ports/espressif/boards/waveshare_esp32_s3_zero/pins.c b/ports/espressif/boards/waveshare_esp32_s3_zero/pins.c index 868c26be20140..15225b1c57c5d 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_zero/pins.c +++ b/ports/espressif/boards/waveshare_esp32_s3_zero/pins.c @@ -152,8 +152,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO21) }, - { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, - { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + // UART - using TX RX on silkscreen { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) } }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/weact_esp32c6_n4/mpconfigboard.mk b/ports/espressif/boards/weact_esp32c6_n4/mpconfigboard.mk index 45309d289048e..ad4832699ee0b 100644 --- a/ports/espressif/boards/weact_esp32c6_n4/mpconfigboard.mk +++ b/ports/espressif/boards/weact_esp32c6_n4/mpconfigboard.mk @@ -7,6 +7,4 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 - CIRCUITPY_AUDIOMP3 = 0 diff --git a/ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.mk b/ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.mk index 3c456881819d1..8e44971792a67 100644 --- a/ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.mk +++ b/ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.mk @@ -8,5 +8,3 @@ CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 4MB CIRCUITPY_ESPCAMERA = 0 - -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT = 1 diff --git a/ports/espressif/common-hal/_bleio/__init__.c b/ports/espressif/common-hal/_bleio/__init__.c index f3637a8fddb99..119fe55921e8a 100644 --- a/ports/espressif/common-hal/_bleio/__init__.c +++ b/ports/espressif/common-hal/_bleio/__init__.c @@ -31,7 +31,7 @@ static uint64_t _timeout_start_time; background_callback_t bleio_background_callback; -void bleio_user_reset() { +void bleio_user_reset(void) { // Stop any user scanning or advertising. common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); @@ -43,7 +43,7 @@ void bleio_user_reset() { } // Turn off BLE on a reset or reload. -void bleio_reset() { +void bleio_reset(void) { // Set this explicitly to save data. if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { return; diff --git a/ports/espressif/common-hal/audiobusio/__init__.c b/ports/espressif/common-hal/audiobusio/__init__.c index 226e371c5b0b0..d07a0b521ba9b 100644 --- a/ports/espressif/common-hal/audiobusio/__init__.c +++ b/ports/espressif/common-hal/audiobusio/__init__.c @@ -184,7 +184,7 @@ void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) { self->next_buffer_size = sizeof(starting_frame); i2s_fill_buffer(self); i2s_channel_preload_data(self->handle, &starting_frame, sizeof(uint32_t), &bytes_loaded); - preloaded += 1; + preloaded += bytes_loaded; } // enable the channel diff --git a/ports/espressif/common-hal/pulseio/PulseIn.c b/ports/espressif/common-hal/pulseio/PulseIn.c index f7e500790562a..a90f9796ab8c5 100644 --- a/ports/espressif/common-hal/pulseio/PulseIn.c +++ b/ports/espressif/common-hal/pulseio/PulseIn.c @@ -80,8 +80,9 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self, const mcu } // We add one to the maxlen version to ensure that two symbols at lease are // captured because we may skip the first portion of a symbol. - self->raw_symbols_size = MIN(64, maxlen / 2 + 1) * sizeof(rmt_symbol_word_t); - self->raw_symbols = (rmt_symbol_word_t *)m_malloc_without_collect(self->raw_symbols_size); + self->raw_symbols_size = (maxlen / 2 + 1) * sizeof(rmt_symbol_word_t); + // RMT DMA mode cannot access PSRAM -> ensure raw_symbols is in internal ram + self->raw_symbols = (rmt_symbol_word_t *)port_malloc(self->raw_symbols_size, true); if (self->raw_symbols == NULL) { m_free(self->buffer); m_malloc_fail(self->raw_symbols_size); @@ -109,17 +110,26 @@ void common_hal_pulseio_pulsein_construct(pulseio_pulsein_obj_t *self, const mcu .clk_src = RMT_CLK_SRC_DEFAULT, // 2 us resolution so we can capture 65ms pulses. The RMT period is only 15 bits. .resolution_hz = 1000000 / 2, - .mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL, + .mem_block_symbols = self->raw_symbols_size, + .flags.with_dma = 1 }; - // If we fail here, the buffers allocated above will be garbage collected. - CHECK_ESP_RESULT(rmt_new_rx_channel(&config, &self->channel)); + // If we fail here, the self->buffer will be garbage collected. + esp_err_t result = rmt_new_rx_channel(&config, &self->channel); + if (result != ESP_OK) { + port_free(self->raw_symbols); + raise_esp_error(result); + } rmt_rx_event_callbacks_t rx_callback = { .on_recv_done = _done_callback }; rmt_rx_register_event_callbacks(self->channel, &rx_callback, self); rmt_enable(self->channel); - rmt_receive(self->channel, self->raw_symbols, self->raw_symbols_size, &rx_config); + result = rmt_receive(self->channel, self->raw_symbols, self->raw_symbols_size, &rx_config); + if (result != ESP_OK) { + port_free(self->raw_symbols); + raise_esp_error(result); + } } bool common_hal_pulseio_pulsein_deinited(pulseio_pulsein_obj_t *self) { diff --git a/ports/espressif/common-hal/rclcpy/Node.c b/ports/espressif/common-hal/rclcpy/Node.c new file mode 100644 index 0000000000000..f68daa44fc34d --- /dev/null +++ b/ports/espressif/common-hal/rclcpy/Node.c @@ -0,0 +1,47 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Lucian Copeland +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/rclcpy/Node.h" +#include "shared-bindings/rclcpy/__init__.h" + +#include "esp_log.h" + +void common_hal_rclcpy_node_construct(rclcpy_node_obj_t *self, + const char *node_name, const char *node_namespace) { + + rclc_node_init_default(&self->rcl_node, node_name, node_namespace, &rclcpy_default_context.rcl_support); + if (!rcl_node_is_valid(&self->rcl_node)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ROS node failed to initialize")); + } + self->deinited = false; +} + +bool common_hal_rclcpy_node_deinited(rclcpy_node_obj_t *self) { + return self->deinited; +} + +void common_hal_rclcpy_node_deinit(rclcpy_node_obj_t *self) { + if (common_hal_rclcpy_node_deinited(self)) { + return; + } + // Clean up Micro-ROS object + rcl_ret_t ret = rcl_node_fini(&self->rcl_node); + if (ret != RCL_RET_OK) { + // TODO: node_fini returns a fail here, but doesn't impede microros + // from restarting. Debug left for future investigation. + ESP_LOGW("RCLCPY", "Node cleanup error: %d", ret); + // rclcpy_default_context.critical_fail=RCLCPY_NODE_FAIL; + } + self->deinited = true; +} + +const char *common_hal_rclcpy_node_get_name(rclcpy_node_obj_t *self) { + return rcl_node_get_name(&self->rcl_node); +} + +const char *common_hal_rclcpy_node_get_namespace(rclcpy_node_obj_t *self) { + return rcl_node_get_namespace(&self->rcl_node); +} diff --git a/ports/espressif/common-hal/rclcpy/Node.h b/ports/espressif/common-hal/rclcpy/Node.h new file mode 100644 index 0000000000000..c019a654e5add --- /dev/null +++ b/ports/espressif/common-hal/rclcpy/Node.h @@ -0,0 +1,23 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Lucian Copeland +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "py/runtime.h" + +#include +#include +#include +#include +#include + + +typedef struct { + mp_obj_base_t base; + bool deinited; + rcl_node_t rcl_node; +} rclcpy_node_obj_t; diff --git a/ports/espressif/common-hal/rclcpy/Publisher.c b/ports/espressif/common-hal/rclcpy/Publisher.c new file mode 100644 index 0000000000000..81df154687ace --- /dev/null +++ b/ports/espressif/common-hal/rclcpy/Publisher.c @@ -0,0 +1,64 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Lucian Copeland +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/rclcpy/Publisher.h" + +#include "esp_log.h" + +void common_hal_rclcpy_publisher_construct(rclcpy_publisher_obj_t *self, rclcpy_node_obj_t *node, + const char *topic_name) { + + // Create Int32 type object + // TODO: support other message types through class imports + const rosidl_message_type_support_t *type_support = ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32); + + // Creates a reliable Int32 publisher + rcl_ret_t rc = rclc_publisher_init_default( + &self->rcl_publisher, &node->rcl_node, + type_support, topic_name); + if (RCL_RET_OK != rc) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ROS topic failed to initialize")); + } + + self->node = node; +} + +bool common_hal_rclcpy_publisher_deinited(rclcpy_publisher_obj_t *self) { + return self->node == NULL; +} + +void common_hal_rclcpy_publisher_deinit(rclcpy_publisher_obj_t *self) { + if (common_hal_rclcpy_publisher_deinited(self)) { + return; + } + // Clean up Micro-ROS object + rcl_ret_t ret = rcl_publisher_fini(&self->rcl_publisher, &self->node->rcl_node); + if (ret != RCL_RET_OK) { + // TODO: publisher_fini returns a fail here, but doesn't impede microros + // from restarting. Debug left for future investigation. + ESP_LOGW("RCLCPY", "Publisher cleanup error: %d", ret); + // rclcpy_default_context.critical_fail=RCLCPY_PUB_FAIL; + } + self->node = NULL; +} + +void common_hal_rclcpy_publisher_publish_int32(rclcpy_publisher_obj_t *self, int32_t data) { + // Int32 message object + std_msgs__msg__Int32 msg; + + // Set message value + msg.data = data; + + // Publish message + rcl_ret_t rc = rcl_publish(&self->rcl_publisher, &msg, NULL); + if (RCL_RET_OK != rc) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Could not publish to ROS topic")); + } +} + +const char *common_hal_rclcpy_publisher_get_topic_name(rclcpy_publisher_obj_t *self) { + return rcl_publisher_get_topic_name(&self->rcl_publisher); +} diff --git a/ports/espressif/common-hal/rclcpy/Publisher.h b/ports/espressif/common-hal/rclcpy/Publisher.h new file mode 100644 index 0000000000000..fdc45293cd270 --- /dev/null +++ b/ports/espressif/common-hal/rclcpy/Publisher.h @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Lucian Copeland +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +#include "common-hal/rclcpy/Node.h" +#include "common-hal/rclcpy/__init__.h" + +#include +#include +#include +#include +#include +#include + + +typedef struct { + mp_obj_base_t base; + rclcpy_node_obj_t *node; + rcl_publisher_t rcl_publisher; +} rclcpy_publisher_obj_t; diff --git a/ports/espressif/common-hal/rclcpy/__init__.c b/ports/espressif/common-hal/rclcpy/__init__.c new file mode 100644 index 0000000000000..e0e6fd8b4f4fc --- /dev/null +++ b/ports/espressif/common-hal/rclcpy/__init__.c @@ -0,0 +1,122 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Lucian Copeland +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/rclcpy/__init__.h" + +#include "esp_log.h" + +#define RCLCPY_SUPPORT_FAIL 1 +#define RCLCPY_OPTIONS_FAIL 2 + +rclcpy_context_t rclcpy_default_context = { + .initialized = false, + .critical_fail = 0, +}; + +static void *microros_allocate(size_t size, void *state) { + (void)state; + return m_malloc(size); +} + +static void microros_deallocate(void *pointer, void *state) { + (void)state; + m_free(pointer); +} + +static void *microros_reallocate(void *pointer, size_t size, void *state) { + (void)state; + return m_realloc(pointer, size); +} + +static void *microros_zero_allocate(size_t number_of_elements, size_t size_of_element, void *state) { + (void)state; + size_t total_size = number_of_elements * size_of_element; + void *ptr = m_malloc(total_size); + if (ptr != NULL) { + memset(ptr, 0, total_size); + } + return ptr; +} + +void rclcpy_reset(void) { + if (rclcpy_default_context.initialized) { + // Clean up micro-ROS objects + rcl_ret_t ret = rclc_support_fini(&rclcpy_default_context.rcl_support); + if (ret != RCL_RET_OK) { + // ESP_LOGW("RCLCPY", "Support cleanup error: %d", ret); + rclcpy_default_context.critical_fail = RCLCPY_SUPPORT_FAIL; + } + ret = rcl_init_options_fini(&rclcpy_default_context.init_options); + if (ret != RCL_RET_OK) { + // ESP_LOGW("RCLCPY", "Init options cleanup error: %d", ret); + rclcpy_default_context.critical_fail = RCLCPY_OPTIONS_FAIL; + } + + // Reset context state + memset(&rclcpy_default_context, 0, sizeof(rclcpy_default_context)); + rclcpy_default_context.initialized = false; + } +} + +void common_hal_rclcpy_init(const char *agent_ip, const char *agent_port, int16_t domain_id) { + if (rclcpy_default_context.critical_fail != 0) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("Critical ROS failure during soft reboot, reset required: %d"), rclcpy_default_context.critical_fail); + } + + // Set up circuitpython-friendly allocator + rcl_allocator_t custom_allocator = rcutils_get_zero_initialized_allocator(); + custom_allocator.allocate = microros_allocate; + custom_allocator.deallocate = microros_deallocate; + custom_allocator.reallocate = microros_reallocate; + custom_allocator.zero_allocate = microros_zero_allocate; + if (!rcutils_set_default_allocator(&custom_allocator)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ROS memory allocator failure")); + } + rclcpy_default_context.rcl_allocator = custom_allocator; + + rcl_ret_t ret; + + // Micro-ROS options initialization + rclcpy_default_context.init_options = rcl_get_zero_initialized_init_options(); + ret = rcl_init_options_init(&rclcpy_default_context.init_options, rclcpy_default_context.rcl_allocator); + if (ret != RCL_RET_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ROS internal setup failure")); + } + if (domain_id < 0) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Invalid ROS domain ID")); + } + ret = rcl_init_options_set_domain_id(&rclcpy_default_context.init_options, domain_id); + if (ret != RCL_RET_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ROS internal setup failure")); + } + + // Set up Micro-ROS Agent + rclcpy_default_context.rmw_options = rcl_init_options_get_rmw_init_options(&rclcpy_default_context.init_options); + ret = rmw_uros_options_set_udp_address(agent_ip, agent_port, rclcpy_default_context.rmw_options); + if (ret != RCL_RET_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ROS internal setup failure")); + } + + // Final support object init requires a connected agent + ret = rclc_support_init_with_options(&rclcpy_default_context.rcl_support, + 0, + NULL, + &rclcpy_default_context.init_options, + &rclcpy_default_context.rcl_allocator); + if (ret != RCL_RET_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("ROS failed to initialize. Is agent connected?")); + } else { + rclcpy_default_context.initialized = true; + } +} + +rclcpy_context_t *common_hal_rclcpy_get_default_context(void) { + return &rclcpy_default_context; +} + +bool common_hal_rclcpy_default_context_is_initialized(void) { + return rclcpy_default_context.initialized; +} diff --git a/ports/espressif/common-hal/rclcpy/__init__.h b/ports/espressif/common-hal/rclcpy/__init__.h new file mode 100644 index 0000000000000..f3ebd4787e757 --- /dev/null +++ b/ports/espressif/common-hal/rclcpy/__init__.h @@ -0,0 +1,30 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Lucian Copeland +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "py/runtime.h" + +#include +#include +#include +#include +#include +#include + + +typedef struct { + bool initialized; + uint8_t critical_fail; + rcl_allocator_t rcl_allocator; + rclc_support_t rcl_support; + rcl_init_options_t init_options; + rmw_init_options_t *rmw_options; +} rclcpy_context_t; + +extern rclcpy_context_t rclcpy_default_context; +void rclcpy_reset(void); diff --git a/ports/espressif/common-hal/sdioio/SDCard.c b/ports/espressif/common-hal/sdioio/SDCard.c index 6fd27c289459c..87ba32f802095 100644 --- a/ports/espressif/common-hal/sdioio/SDCard.c +++ b/ports/espressif/common-hal/sdioio/SDCard.c @@ -245,7 +245,7 @@ void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self) { } } -void sdioio_reset() { +void sdioio_reset(void) { for (size_t i = 0; i < MP_ARRAY_SIZE(slot_in_use); i++) { if (!never_reset_sdio[i]) { slot_in_use[i] = false; diff --git a/ports/espressif/esp-idf-config/partitions-4MB-no-ota-no-uf2-large-user_fs.csv b/ports/espressif/esp-idf-config/partitions-4MB-no-ota-no-uf2-large-user_fs.csv new file mode 100644 index 0000000000000..59e0d9d1212bf --- /dev/null +++ b/ports/espressif/esp-idf-config/partitions-4MB-no-ota-no-uf2-large-user_fs.csv @@ -0,0 +1,7 @@ +# Name, Type, SubType, Offset, Size +# bootloader, app, boot, 0x1000/0x0, 28/32K +# partition_table, data, table, 0x8000, 4K +nvs, data, nvs, 0x9000, 20K +otadata, data, ota, 0xe000, 8K +ota_0, app, ota_0, 0x10000, 2048K +user_fs, data, fat, 0x210000, 1984K diff --git a/ports/espressif/esp-idf-config/partitions-4MB-no-ota-no-uf2.csv b/ports/espressif/esp-idf-config/partitions-4MB-no-ota-no-uf2.csv index 59e0d9d1212bf..49d043d767252 100644 --- a/ports/espressif/esp-idf-config/partitions-4MB-no-ota-no-uf2.csv +++ b/ports/espressif/esp-idf-config/partitions-4MB-no-ota-no-uf2.csv @@ -3,5 +3,5 @@ # partition_table, data, table, 0x8000, 4K nvs, data, nvs, 0x9000, 20K otadata, data, ota, 0xe000, 8K -ota_0, app, ota_0, 0x10000, 2048K -user_fs, data, fat, 0x210000, 1984K +ota_0, app, ota_0, 0x10000, 2816K +user_fs, data, fat, 0x2d0000, 1216K diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-4MB-no-ota-no-uf2-large-user_fs.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-4MB-no-ota-no-uf2-large-user_fs.defaults new file mode 100644 index 0000000000000..0a585e9d523e5 --- /dev/null +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-4MB-no-ota-no-uf2-large-user_fs.defaults @@ -0,0 +1,25 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Serial flasher config +# +# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_32MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_64MB is not set +# CONFIG_ESPTOOLPY_FLASHSIZE_128MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE="4MB" +# end of Serial flasher config + +# +# Partition Table +# +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-4MB-no-ota-no-uf2-large-user_fs.csv" +CONFIG_PARTITION_TABLE_FILENAME="esp-idf-config/partitions-4MB-no-ota-no-uf2-large-user_fs.csv" +# end of Partition Table + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/microros-lib b/ports/espressif/microros-lib new file mode 160000 index 0000000000000..4b2a696dec7f0 --- /dev/null +++ b/ports/espressif/microros-lib @@ -0,0 +1 @@ +Subproject commit 4b2a696dec7f0f865e014ea4b83f2332df7e9560 diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index ccc305761c4dc..de3844e632840 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -30,9 +30,10 @@ LONGINT_IMPL = MPZ # Default to no-psram CIRCUITPY_ESP_PSRAM_SIZE ?= 0 -# New 4MB boards will not have OTA support but more room for alarm, ble and other -# newer features. -CIRCUITPY_LEGACY_4MB_FLASH_LAYOUT ?= 0 +# Some 4MB non-USB boards were initially defined with 2MB firmware, almost 2MB user_fs partitions. +# Others were defined with 1.4M+1.4M (now a single 2.8MB) firmware partitions / 1.2MB user_fs. +# Keep the former as is, so that the user filesystem will be unchanged. +CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT ?= 0 # Enable more features CIRCUITPY_FULL_BUILD ?= 1 @@ -64,6 +65,7 @@ CIRCUITPY_HASHLIB ?= 1 CIRCUITPY_I2CTARGET ?= 0 CIRCUITPY_MAX3421E ?= 1 CIRCUITPY_MEMORYMAP ?= 1 +CIRCUITPY_RCLCPY ?= 0 CIRCUITPY_NVM ?= 1 CIRCUITPY_PARALLELDISPLAYBUS ?= 1 CIRCUITPY_PS2IO ?= 1 diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index e72eab7e32a56..48ae29ab4f927 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -55,6 +55,10 @@ #include "esp_camera.h" #endif +#if CIRCUITPY_RCLCPY +#include "common-hal/rclcpy/__init__.h" +#endif + #include "soc/efuse_reg.h" #if defined(SOC_LP_AON_SUPPORTED) #include "soc/lp_aon_reg.h" @@ -304,18 +308,18 @@ void port_heap_init(void) { } void *port_malloc(size_t size, bool dma_capable) { - size_t caps = MALLOC_CAP_8BIT; if (dma_capable) { - caps |= MALLOC_CAP_DMA; + // SPIRAM is not DMA-capable, so don't bother to ask for it. + return heap_caps_malloc(size, MALLOC_CAP_8BIT | MALLOC_CAP_DMA); } void *ptr = NULL; - // Try SPIRAM first when available. + // Try SPIRAM first if available. #ifdef CONFIG_SPIRAM - ptr = heap_caps_malloc(size, caps | MALLOC_CAP_SPIRAM); + ptr = heap_caps_malloc(size, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); #endif if (ptr == NULL) { - ptr = heap_caps_malloc(size, caps); + ptr = heap_caps_malloc(size, MALLOC_CAP_8BIT); } return ptr; } @@ -378,6 +382,10 @@ void reset_port(void) { ps2_reset(); #endif + #if CIRCUITPY_RCLCPY + rclcpy_reset(); + #endif + #if CIRCUITPY_RTC rtc_reset(); #endif @@ -461,11 +469,11 @@ void port_disable_tick(void) { esp_timer_stop(_tick_timer); } -void port_wake_main_task() { +void port_wake_main_task(void) { xTaskNotifyGive(circuitpython_task); } -void port_wake_main_task_from_isr() { +void port_wake_main_task_from_isr(void) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; vTaskNotifyGiveFromISR(circuitpython_task, &xHigherPriorityTaskWoken); if (xHigherPriorityTaskWoken == pdTRUE) { @@ -473,7 +481,7 @@ void port_wake_main_task_from_isr() { } } -void port_yield() { +void port_yield(void) { vTaskDelay(4); } diff --git a/ports/litex/Makefile b/ports/litex/Makefile index bb1d88e755201..98abe985699cf 100644 --- a/ports/litex/Makefile +++ b/ports/litex/Makefile @@ -38,7 +38,7 @@ endif # option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk CFLAGS += $(OPTIMIZATION_FLAGS) -CFLAGS += $(INC) -Werror -Wall -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(C_DEFS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes +CFLAGS += $(INC) -Werror -Wall -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(C_DEFS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes -Werror=old-style-definition # TODO: check this CFLAGS += -D__START=main -DFOMU diff --git a/ports/mimxrt10xx/Makefile b/ports/mimxrt10xx/Makefile index 57a8beb069129..e6928eead619d 100644 --- a/ports/mimxrt10xx/Makefile +++ b/ports/mimxrt10xx/Makefile @@ -45,7 +45,7 @@ ifeq ($(DEBUG), 1) CFLAGS += -fno-ipa-sra endif -CFLAGS += $(INC) -ggdb -Wall -Werror -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes +CFLAGS += $(INC) -ggdb -Wall -Werror -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes -Werror=old-style-definition # TODO: add these when -Werror is applied # Disable some warnings, as do most ports. NXP SDK causes undef, tinyusb causes cast-align diff --git a/ports/mimxrt10xx/boards/teensy40/mpconfigboard.h b/ports/mimxrt10xx/boards/teensy40/mpconfigboard.h index e7565d64438f6..e6931752e3e58 100644 --- a/ports/mimxrt10xx/boards/teensy40/mpconfigboard.h +++ b/ports/mimxrt10xx/boards/teensy40/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO_AD_B0_03) #define DEFAULT_UART_BUS_TX (&pin_GPIO_AD_B0_02) + +#define CIRCUITPY_USB_DEVICE_INSTANCE 0 +#define CIRCUITPY_USB_HOST_INSTANCE 1 diff --git a/ports/mimxrt10xx/boards/teensy40/mpconfigboard.mk b/ports/mimxrt10xx/boards/teensy40/mpconfigboard.mk index 9cb1e636b6f33..f26f8dbd72b79 100644 --- a/ports/mimxrt10xx/boards/teensy40/mpconfigboard.mk +++ b/ports/mimxrt10xx/boards/teensy40/mpconfigboard.mk @@ -7,4 +7,5 @@ CHIP_VARIANT = MIMXRT1062DVJ6A CHIP_FAMILY = MIMXRT1062 FLASH = W25Q16JV CIRCUITPY__EVE = 1 +CIRCUITPY_USB_HOST = 1 CIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY = 1 diff --git a/ports/mimxrt10xx/boards/teensy40/pins.c b/ports/mimxrt10xx/boards/teensy40/pins.c index 7aacdf95e15ff..dc8b07605b256 100644 --- a/ports/mimxrt10xx/boards/teensy40/pins.c +++ b/ports/mimxrt10xx/boards/teensy40/pins.c @@ -120,6 +120,10 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj)}, {MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj)}, + // USB Host (pads) + {MP_ROM_QSTR(MP_QSTR_USB_HOST_DP), MP_ROM_PTR(&pin_USB_OTG2_DP)}, + {MP_ROM_QSTR(MP_QSTR_USB_HOST_DM), MP_ROM_PTR(&pin_USB_OTG2_DN)}, + // other i2c ports defined {MP_OBJ_NEW_QSTR(MP_QSTR_SDA1), MP_ROM_PTR(&pin_GPIO_AD_B1_06)}, {MP_OBJ_NEW_QSTR(MP_QSTR_SCL1), MP_ROM_PTR(&pin_GPIO_AD_B1_07)}, diff --git a/ports/mimxrt10xx/common-hal/audiobusio/__init__.c b/ports/mimxrt10xx/common-hal/audiobusio/__init__.c index 196e52dbf0369..f1030bfcd848c 100644 --- a/ports/mimxrt10xx/common-hal/audiobusio/__init__.c +++ b/ports/mimxrt10xx/common-hal/audiobusio/__init__.c @@ -439,6 +439,6 @@ void port_i2s_resume(i2s_t *self) { self->paused = false; } -void i2s_reset() { +void i2s_reset(void) { // this port relies on object finalizers for reset } diff --git a/ports/nordic/Makefile b/ports/nordic/Makefile index e60b4072a8d48..aa614e097ba3c 100755 --- a/ports/nordic/Makefile +++ b/ports/nordic/Makefile @@ -47,7 +47,7 @@ endif # option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk CFLAGS += $(OPTIMIZATION_FLAGS) -CFLAGS += $(INC) -Wall -Werror -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes +CFLAGS += $(INC) -Wall -Werror -std=gnu11 -nostdlib -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes -Werror=old-style-definition # Nordic Softdevice SDK header files contains inline assembler that has # broken constraints. As a result the IPA-modref pass, introduced in gcc-11, diff --git a/ports/nordic/boards/circuitplayground_bluefruit/mpconfigboard.h b/ports/nordic/boards/circuitplayground_bluefruit/mpconfigboard.h index 91cf68095d27d..d63a9ccd5d8d5 100644 --- a/ports/nordic/boards/circuitplayground_bluefruit/mpconfigboard.h +++ b/ports/nordic/boards/circuitplayground_bluefruit/mpconfigboard.h @@ -50,3 +50,7 @@ #define DEFAULT_UART_BUS_TX (&pin_P0_14) #define SPEAKER_ENABLE_PIN (&pin_P1_04) + +// Uncomment to allow debugging over console UART +// #define CIRCUITPY_CONSOLE_UART_TX (&pin_P0_14) +// #define CIRCUITPY_CONSOLE_UART_RX (&pin_P0_30) diff --git a/ports/nordic/common-hal/_bleio/__init__.c b/ports/nordic/common-hal/_bleio/__init__.c index 095723194cfbf..454937dcd354a 100644 --- a/ports/nordic/common-hal/_bleio/__init__.c +++ b/ports/nordic/common-hal/_bleio/__init__.c @@ -80,7 +80,7 @@ void check_sec_status(uint8_t sec_status) { void common_hal_bleio_init(void) { } -void bleio_user_reset() { +void bleio_user_reset(void) { if (common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { // Stop any user scanning or advertising. common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); @@ -94,7 +94,7 @@ void bleio_user_reset() { } // Turn off BLE on a reset or reload. -void bleio_reset() { +void bleio_reset(void) { // Set this explicitly to save data. common_hal_bleio_adapter_obj.base.type = &bleio_adapter_type; if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { diff --git a/ports/nordic/common-hal/alarm/__init__.h b/ports/nordic/common-hal/alarm/__init__.h index 91d717ccce273..336447689ff4e 100644 --- a/ports/nordic/common-hal/alarm/__init__.h +++ b/ports/nordic/common-hal/alarm/__init__.h @@ -13,7 +13,7 @@ #include "common-hal/alarm/touch/TouchAlarm.h" typedef enum { - NRF_SLEEP_WAKEUP_UNDEFINED, + NRF_SLEEP_WAKEUP_UNDEFINED = 0, NRF_SLEEP_WAKEUP_GPIO, NRF_SLEEP_WAKEUP_TIMER, NRF_SLEEP_WAKEUP_TOUCHPAD, @@ -33,8 +33,9 @@ extern const alarm_sleep_memory_obj_t alarm_sleep_memory_obj; enum { SLEEPMEM_WAKEUP_BY_NONE = 0, - SLEEPMEM_WAKEUP_BY_PIN = 1, - SLEEPMEM_WAKEUP_BY_TIMER = 2, + SLEEPMEM_WAKEUP_BY_PIN, + SLEEPMEM_WAKEUP_BY_TIMER, + SLEEPMEM_WAKEUP_BY_TOUCH, }; #define WAKEUP_PIN_UNDEF 0xFF extern uint8_t sleepmem_wakeup_event; diff --git a/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c b/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c index 53be11bcd7485..b48a03e09c601 100644 --- a/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +++ b/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c @@ -136,7 +136,7 @@ static void audiopwmout_background_obj(audiopwmio_pwmaudioout_obj_t *self) { } } -void audiopwmout_background() { +void audiopwmout_background(void) { // Check the NVIC first because it is part of the CPU and fast to read. if (!NVIC_GetPendingIRQ(PWM0_IRQn) && !NVIC_GetPendingIRQ(PWM1_IRQn) && diff --git a/ports/nordic/common-hal/microcontroller/__init__.c b/ports/nordic/common-hal/microcontroller/__init__.c index 38a3b1ee60938..fbb40afe0449d 100644 --- a/ports/nordic/common-hal/microcontroller/__init__.c +++ b/ports/nordic/common-hal/microcontroller/__init__.c @@ -35,7 +35,7 @@ void common_hal_mcu_delay_us(uint32_t delay) { static volatile uint32_t nesting_count = 0; static uint8_t is_nested_critical_region; -void common_hal_mcu_disable_interrupts() { +void common_hal_mcu_disable_interrupts(void) { if (nesting_count == 0) { // Unlike __disable_irq(), this should only be called the first time // "is_nested_critical_region" is sd's equivalent of our nesting count @@ -51,7 +51,7 @@ void common_hal_mcu_disable_interrupts() { nesting_count++; } -void common_hal_mcu_enable_interrupts() { +void common_hal_mcu_enable_interrupts(void) { if (nesting_count == 0) { // This is very very bad because it means there was mismatched disable/enables. reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR); diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 582c04282734c..6565af79bf3e1 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -223,7 +223,7 @@ endif DISABLE_WARNINGS = -Wno-cast-align -CFLAGS += $(INC) -Wtype-limits -Wall -Werror -std=gnu11 -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS) -Werror=missing-prototypes +CFLAGS += $(INC) -Wtype-limits -Wall -Werror -std=gnu11 -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS) -Werror=missing-prototypes -Wold-style-definition PICO_LDFLAGS = --specs=nosys.specs --specs=nano.specs @@ -562,12 +562,15 @@ SRC_C += \ common-hal/picodvi/Framebuffer_$(CHIP_VARIANT).c \ ifeq ($(CHIP_VARIANT),RP2040) -SRC_C += \ +SRC_PICODVI := \ lib/PicoDVI/software/libdvi/dvi.c \ lib/PicoDVI/software/libdvi/dvi_serialiser.c \ lib/PicoDVI/software/libdvi/dvi_timing.c \ lib/PicoDVI/software/libdvi/tmds_encode.c \ +SRC_C += $(SRC_PICODVI) +$(patsubst %.c,$(BUILD)/%.o,$(SRC_PICODVI))): CFLAGS += -Wno-old-style-definition + endif endif diff --git a/ports/raspberrypi/bindings/cyw43/__init__.c b/ports/raspberrypi/bindings/cyw43/__init__.c index a699a5e91ebba..93755d6ce1e04 100644 --- a/ports/raspberrypi/bindings/cyw43/__init__.c +++ b/ports/raspberrypi/bindings/cyw43/__init__.c @@ -43,7 +43,7 @@ MP_DEFINE_CONST_OBJ_TYPE( print, shared_bindings_microcontroller_pin_print ); -uint32_t cyw43_get_power_management_value() { +uint32_t cyw43_get_power_management_value(void) { return power_management_value; } @@ -103,7 +103,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(cyw43_set_power_management_obj, cyw43_set_power //| """Retrieve the power management register""" //| //| -static mp_obj_t cyw43_get_power_management() { +static mp_obj_t cyw43_get_power_management(void) { return mp_obj_new_int(power_management_value); } static MP_DEFINE_CONST_FUN_OBJ_0(cyw43_get_power_management_obj, cyw43_get_power_management); diff --git a/ports/raspberrypi/boards/42keebs_frood/pins.c b/ports/raspberrypi/boards/42keebs_frood/pins.c index 4543625051869..2e7ac22475b22 100644 --- a/ports/raspberrypi/boards/42keebs_frood/pins.c +++ b/ports/raspberrypi/boards/42keebs_frood/pins.c @@ -49,6 +49,9 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_GPIO19) }, diff --git a/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c b/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c index a20b16473174c..19e18bd544bee 100644 --- a/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c +++ b/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c @@ -281,6 +281,7 @@ void board_init(void) { true, // always_toggle_chip_select false, // not grayscale false, // not acep + false, // not spectra6 false, // not two_byte_sequence_length true); // address_little_endian } else if (vid_setting == 2) { // Explorer SSD1608 BW @@ -314,6 +315,7 @@ void board_init(void) { true, // always_toggle_chip_select false, // not grayscale false, // not acep + false, // not spectra6 false, // not two_byte_sequence_length true); // address_little_endian } else { diff --git a/ports/raspberrypi/boards/orpheus_pico/board.c b/ports/raspberrypi/boards/orpheus_pico/board.c new file mode 100644 index 0000000000000..e6a868ab21226 --- /dev/null +++ b/ports/raspberrypi/boards/orpheus_pico/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/orpheus_pico/mpconfigboard.h b/ports/raspberrypi/boards/orpheus_pico/mpconfigboard.h new file mode 100644 index 0000000000000..8c6269771fdfc --- /dev/null +++ b/ports/raspberrypi/boards/orpheus_pico/mpconfigboard.h @@ -0,0 +1,13 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Orpheus Pico" +#define MICROPY_HW_MCU_NAME "rp2040" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO25) +#define MICROPY_HW_LED_STATUS (&pin_GPIO23) diff --git a/ports/raspberrypi/boards/orpheus_pico/mpconfigboard.mk b/ports/raspberrypi/boards/orpheus_pico/mpconfigboard.mk new file mode 100644 index 0000000000000..9b570211c8f77 --- /dev/null +++ b/ports/raspberrypi/boards/orpheus_pico/mpconfigboard.mk @@ -0,0 +1,11 @@ +USB_VID = 0x2E8A +USB_PID = 0x10D0 +USB_PRODUCT = "Orpheus Pico" +USB_MANUFACTURER = "Hack Club" + +CHIP_VARIANT = RP2040 +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" + +CIRCUITPY__EVE = 1 diff --git a/ports/raspberrypi/boards/orpheus_pico/pico-sdk-configboard.h b/ports/raspberrypi/boards/orpheus_pico/pico-sdk-configboard.h new file mode 100644 index 0000000000000..110195b779498 --- /dev/null +++ b/ports/raspberrypi/boards/orpheus_pico/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/orpheus_pico/pins.c b/ports/raspberrypi/boards/orpheus_pico/pins.c new file mode 100644 index 0000000000000..24d656c18c9e0 --- /dev/null +++ b/ports/raspberrypi/boards/orpheus_pico/pins.c @@ -0,0 +1,57 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_GP23), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_GP24), MP_ROM_PTR(&pin_GPIO24) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) }, + + { MP_ROM_QSTR(MP_QSTR_GP26_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_GP27_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/board.c b/ports/raspberrypi/boards/pimoroni_badger2040/board.c index 457bff33b4433..5950d11da8a11 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2040/board.c +++ b/ports/raspberrypi/boards/pimoroni_badger2040/board.c @@ -303,6 +303,7 @@ void board_init(void) { false, // always_toggle_chip_select false, // grayscale false, // acep + false, // spectra6 false, // two_byte_sequence_length false); // address_little_endian } diff --git a/ports/raspberrypi/boards/pimoroni_badger2040w/board.c b/ports/raspberrypi/boards/pimoroni_badger2040w/board.c index 30c05273b9478..7dc11af01eca3 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2040w/board.c +++ b/ports/raspberrypi/boards/pimoroni_badger2040w/board.c @@ -303,6 +303,7 @@ void board_init(void) { false, // always_toggle_chip_select false, // grayscale false, // acep + false, // spectra6 false, // two_byte_sequence_length false); // address_little_endian } diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c index 650d307711e8e..7969143ec6621 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c @@ -97,6 +97,7 @@ void board_init(void) { false, // always_toggle_chip_select false, // grayscale true, // acep + false, // spectra6 false, // two_byte_sequence_length false); // address_little_endian } diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.h b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.h index d2547cc161568..a8c404c422501 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.h +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.h @@ -14,8 +14,8 @@ #define MICROPY_HW_LED_STATUS (&pin_GPIO6) -#define DEFAULT_I2C_BUS_SCL (&pin_GPIO4) -#define DEFAULT_I2C_BUS_SDA (&pin_GPIO5) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4) +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5) #define DEFAULT_UART_BUS_TX (&pin_GPIO0) #define DEFAULT_UART_BUS_RX (&pin_GPIO1) diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c b/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c index a24c91e546da9..7c71e03b4281d 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c @@ -156,6 +156,7 @@ void board_init(void) { false, // always_toggle_chip_select false, // grayscale true, // acep + false, // spectra6 false, // two_byte_sequence_length false); // address_little_endian } diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/mpconfigboard.h b/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/mpconfigboard.h index 42cb1196a5475..32477b12c299f 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/mpconfigboard.h +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/mpconfigboard.h @@ -14,8 +14,8 @@ #define MICROPY_HW_LED_STATUS (&pin_GPIO6) -#define DEFAULT_I2C_BUS_SCL (&pin_GPIO4) -#define DEFAULT_I2C_BUS_SDA (&pin_GPIO5) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4) +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5) #define DEFAULT_UART_BUS_TX (&pin_GPIO0) #define DEFAULT_UART_BUS_RX (&pin_GPIO1) diff --git a/ports/raspberrypi/common-hal/alarm/pin/PinAlarm.c b/ports/raspberrypi/common-hal/alarm/pin/PinAlarm.c index ecebb072775ed..350306390eefb 100644 --- a/ports/raspberrypi/common-hal/alarm/pin/PinAlarm.c +++ b/ports/raspberrypi/common-hal/alarm/pin/PinAlarm.c @@ -39,7 +39,7 @@ static void gpio_callback(uint gpio, uint32_t events) { } } -void alarm_pin_pinalarm_entering_deep_sleep() { +void alarm_pin_pinalarm_entering_deep_sleep(void) { _not_yet_deep_sleeping = false; } diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index f5bc67332af4b..4be42380491cb 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -584,7 +584,7 @@ __attribute__((used)) void __not_in_flash_func(isr_hardfault)(void) { } } -void port_yield() { +void port_yield(void) { #if CIRCUITPY_CYW43 cyw43_arch_poll(); #endif diff --git a/ports/renode/Makefile b/ports/renode/Makefile index 22e32f9d2fb6e..92541c03e77b9 100644 --- a/ports/renode/Makefile +++ b/ports/renode/Makefile @@ -21,7 +21,7 @@ INC += \ CFLAGS += -ggdb3 -Os DISABLE_WARNINGS = -Wno-cast-align -CFLAGS += $(INC) -Wall -Werror -std=gnu11 -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS) -Werror=missing-prototypes +CFLAGS += $(INC) -Wall -Werror -std=gnu11 -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS) -Werror=missing-prototypes -Werror=old-style-definition CFLAGS += \ -march=armv6-m \ diff --git a/ports/renode/supervisor/port.c b/ports/renode/supervisor/port.c index dae32b7bb8f2d..d12ebd2efddb9 100644 --- a/ports/renode/supervisor/port.c +++ b/ports/renode/supervisor/port.c @@ -210,7 +210,7 @@ __attribute__((used)) void HardFault_Handler(void) { } } -void port_yield() { +void port_yield(void) { } void port_boot_info(void) { diff --git a/ports/silabs/boards/devkit_xg24_brd2601b/sensor.c b/ports/silabs/boards/devkit_xg24_brd2601b/sensor.c index aaf698a6cb27f..1c991a4caafc7 100644 --- a/ports/silabs/boards/devkit_xg24_brd2601b/sensor.c +++ b/ports/silabs/boards/devkit_xg24_brd2601b/sensor.c @@ -75,7 +75,7 @@ static mp_obj_t sensor_init(mp_obj_t i2c_in) { return mp_const_true; } -static mp_obj_t sensor_deinit() { +static mp_obj_t sensor_deinit(void) { sl_sensor_hall_deinit(); sl_sensor_lux_deinit(); diff --git a/ports/silabs/common-hal/_bleio/CharacteristicBuffer.c b/ports/silabs/common-hal/_bleio/CharacteristicBuffer.c index d6a64db3a2e95..d08fa765c4f71 100644 --- a/ports/silabs/common-hal/_bleio/CharacteristicBuffer.c +++ b/ports/silabs/common-hal/_bleio/CharacteristicBuffer.c @@ -156,7 +156,7 @@ bool common_hal_bleio_characteristic_buffer_connected( common_hal_bleio_connection_get_connected(self->characteristic->service->connection))); } -void reset_characteristic_buffer_list() { +void reset_characteristic_buffer_list(void) { // Remove characteristic_buffer list memset(bleio_characteristic_buffer_list.data, 0, sizeof(bleio_characteristic_buffer_list.data)); diff --git a/ports/silabs/common-hal/_bleio/PacketBuffer.c b/ports/silabs/common-hal/_bleio/PacketBuffer.c index 1d2b140f7efef..dec833fe62f85 100644 --- a/ports/silabs/common-hal/_bleio/PacketBuffer.c +++ b/ports/silabs/common-hal/_bleio/PacketBuffer.c @@ -391,7 +391,7 @@ void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { } // Remove packet_buffer list when reload -void reset_packet_buffer_list() { +void reset_packet_buffer_list(void) { // Remove packet_buffer list memset(bleio_packet_buffer_list.data, 0, sizeof(bleio_packet_buffer_list.data)); diff --git a/ports/silabs/common-hal/_bleio/Service.c b/ports/silabs/common-hal/_bleio/Service.c index 694841e66284f..abc8ffe74edff 100644 --- a/ports/silabs/common-hal/_bleio/Service.c +++ b/ports/silabs/common-hal/_bleio/Service.c @@ -230,7 +230,7 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, } // Remove dynamic service when reload -void reset_dynamic_service() { +void reset_dynamic_service(void) { uint16_t gattdb_session; uint8_t svc_index; diff --git a/ports/silabs/common-hal/_bleio/__init__.c b/ports/silabs/common-hal/_bleio/__init__.c index a9ad7b32c36ba..c6ae8a0b606c8 100644 --- a/ports/silabs/common-hal/_bleio/__init__.c +++ b/ports/silabs/common-hal/_bleio/__init__.c @@ -54,7 +54,7 @@ const osMutexAttr_t bluetooth_connection_mutex_attr = { void common_hal_bleio_init(void) { } -void bleio_user_reset() { +void bleio_user_reset(void) { // Stop any user scanning or advertising. common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); @@ -63,7 +63,7 @@ void bleio_user_reset() { supervisor_bluetooth_background(); } -void bleio_reset() { +void bleio_reset(void) { reset_dynamic_service(); reset_packet_buffer_list(); reset_characteristic_buffer_list(); diff --git a/ports/stm/Makefile b/ports/stm/Makefile index baea6893a33d9..9db283767e0ec 100755 --- a/ports/stm/Makefile +++ b/ports/stm/Makefile @@ -51,7 +51,7 @@ CFLAGS += -ftree-vrp # STM32 MCU series must be defined. See supervisor/linker.h C_DEFS = -D$(MCU_PACKAGE) -DUSE_HAL_DRIVER -DUSE_FULL_LL_DRIVER -D$(MCU_VARIANT) -DSTM32$(MCU_SERIES) -CFLAGS += $(INC) -Werror -Wall -std=gnu11 -fshort-enums $(BASE_CFLAGS) $(C_DEFS) $(CFLAGS_MOD) $(COPT) -nostdlib -nostartfiles +CFLAGS += $(INC) -Werror -Wall -std=gnu11 -fshort-enums $(BASE_CFLAGS) $(C_DEFS) $(CFLAGS_MOD) $(COPT) -nostdlib -nostartfiles -Werror=old-style-definition # Undo some warnings. # STM32 HAL uses undefined preprocessor variables, shadowed variables, casts that change alignment reqs diff --git a/ports/stm/common-hal/sdioio/SDCard.c b/ports/stm/common-hal/sdioio/SDCard.c index a5c8b0404a0fb..92e552c2e8984 100644 --- a/ports/stm/common-hal/sdioio/SDCard.c +++ b/ports/stm/common-hal/sdioio/SDCard.c @@ -338,7 +338,7 @@ void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self) { } } -void sdioio_reset() { +void sdioio_reset(void) { for (size_t i = 0; i < MP_ARRAY_SIZE(reserved_sdio); i++) { if (!never_reset_sdio[i]) { reserved_sdio[i] = false; diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index 4aa8c044122ce..c5a1685a7fddc 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -285,7 +285,7 @@ void HAL_Delay(uint32_t delay_ms) { } } -uint32_t HAL_GetTick() { +uint32_t HAL_GetTick(void) { if (SysTick->CTRL != 0) { return systick_ms; } else { diff --git a/ports/unix/Makefile b/ports/unix/Makefile index cd0403a8f5df5..e7d63d514d968 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -169,7 +169,7 @@ ifeq ($(MICROPY_STANDALONE),1) # Build libffi from source. GIT_SUBMODULES += lib/libffi DEPLIBS += libffi -LIBFFI_CFLAGS := -I$(shell ls -1d $(BUILD)/lib/libffi/out/lib/libffi-*/include) +LIBFFI_CFLAGS := -I$(shell ls -1d $(BUILD)/lib/libffi/include) ifeq ($(MICROPY_FORCE_32BIT),1) LIBFFI_LDFLAGS = $(BUILD)/lib/libffi/out/lib32/libffi.a else diff --git a/ports/unix/README.md b/ports/unix/README.md index 61dfd7453e6ac..b7aa6e3fef76d 100644 --- a/ports/unix/README.md +++ b/ports/unix/README.md @@ -1,17 +1,59 @@ -The Unix version -================ +MicroPython Unix port +===================== + +The "unix" port runs in standard Unix-like environments including Linux, BSD, +macOS, and Windows Subsystem for Linux. -The "unix" port requires a standard Unix-like environment with gcc and GNU -make. This includes Linux, BSD, macOS, and Windows Subsystem for Linux. The -x86 and x64 architectures are supported (i.e. x86 32- and 64-bit), as well as -ARM and MIPS. Making a full-featured port to another architecture requires +The x86 and x64 architectures are supported (i.e. x86 32- and 64-bit), as well +as ARM and MIPS. Extending the unix port to another architecture requires writing some assembly code for the exception handling and garbage collection. Alternatively, a fallback implementation based on setjmp/longjmp can be used. -To build (see section below for required dependencies): +Building +-------- + +### Dependencies + +To build the unix port locally then you will need: + +* git command line executable, unless you downloaded a source .tar.xz file from + https://micropython.org/download/ +* gcc (or clang for macOS) toolchain +* GNU Make +* Python 3.x + +To build the default "standard" variant and configuration, then you will also +need: + +* `pkg-config` tool +* `libffi` library and headers + +On Debian/Ubuntu/Mint and related Linux distros, you can install all these +dependencies with a command like: + +``` +# apt install build-essential git python3 pkg-config libffi-dev +``` + +(See below for steps to build either a standalone or minimal MicroPython +executable that doesn't require system `libffi` or `pkg-config`.) + +### Default build steps + +To set up the environment for building (not needed every time), starting from +the top-level MicroPython directory: $ cd ports/unix + $ make -C ../../mpy-cross $ make submodules + +The `mpy-cross` step builds the [MicroPython +cross-compiler](https://github.com/micropython/micropython/?tab=readme-ov-file#the-micropython-cross-compiler-mpy-cross). +The `make submodules` step can be skipped if you didn't clone the MicroPython +source from git. + +Next, to build the actual executable (still in the `ports/unix` directory): + $ make Then to give it a try: @@ -45,44 +87,71 @@ Browse available modules at [Package management](https://docs.micropython.org/en/latest/reference/packages.html) for more information about `mip`. -External dependencies -===================== - -The `libffi` library and `pkg-config` tool are required. On Debian/Ubuntu/Mint -derivative Linux distros, install `build-essential`(includes toolchain and -make), `libffi-dev`, and `pkg-config` packages. +### Minimal Variant -Other dependencies can be built together with MicroPython. This may -be required to enable extra features or capabilities, and in recent -versions of MicroPython, these may be enabled by default. To build -these additional dependencies, in the unix port directory first execute: +The "standard" variant of MicroPython is the default. It enables most features, +including external modules interfaced using `libffi`. To instead build the +"minimal" variant, which disables almost all optional features and modules: + $ cd ports/unix $ make submodules + $ make VARIANT=minimal + +The executable will be built at `build-minimal/micropython`. + +Additional variants can be found in the `variants` sub-directory of the port, +although these are mostly of interest to MicroPython maintainers. + +### Standalone build + +By default, the "standard" variant uses `pkg-config` to link to the system's +shared `libffi` library. + +It is possible to instead build a standalone MicroPython where `libffi` is built +from source and linked statically into the `micropython` executable. This is +mostly useful for embedded or cross-compiled applications. -This will fetch all the relevant git submodules (sub repositories) that -the port needs. Use the same command to get the latest versions of -submodules as they are updated from time to time. After that execute: +Building standalone requires `autoconf` and `libtool` to also be installed. - $ make deplibs +To build standalone: -This will build all available dependencies (regardless whether they are used -or not). If you intend to build MicroPython with additional options -(like cross-compiling), the same set of options should be passed to `make -deplibs`. To actually enable/disable use of dependencies, edit the + $ export MICROPY_STANDALONE=1 + $ make submodules # fetches libffi submodule + $ make deplibs # build just the external libraries + $ make # build MicroPython itself + +`make deplibs` causes all supported external libraries (currently only `libffi`) +to be built inside the build directory, so it needs to run again only after +`make clean`. + +If you intend to build MicroPython with additional options (like +cross-compiling), the same set of options should be passed to both `make +deplibs` and `make`. + +### Other dependencies + +To actually enable/disable use of dependencies, edit the `ports/unix/mpconfigport.mk` file, which has inline descriptions of the options. For example, to build the SSL module, `MICROPY_PY_SSL` should be set to 1. -Debug Symbols -============= +### Debug Symbols By default, builds are stripped of symbols and debug information to save size. -To build a debuggable version of the Unix port, there are two options +To build a debuggable version of the Unix port, there are two options: 1. Run `make [other arguments] DEBUG=1`. Note setting `DEBUG` also reduces the - optimisation level, so it's not a good option for builds that also want the - best performance. + optimisation level and enables assertions, so it's not a good option for + builds that also want the best performance. 2. Run `make [other arguments] STRIP=`. Note that the value of `STRIP` is empty. This will skip the build step that strips symbols and debug information, but changes nothing else in the build configuration. + +### Optimisation Level + +The default compiler optimisation level is -Os, or -Og if `DEBUG=1` is set. + +Setting the variable `COPT` will explicitly set the optimisation level. For +example `make [other arguments] COPT=-O0 DEBUG=1` will build a binary with no +optimisations, assertions enabled, and debug symbols. diff --git a/ports/unix/alloc.c b/ports/unix/alloc.c index e9cf521583d99..9ab2ca04ebc97 100644 --- a/ports/unix/alloc.c +++ b/ports/unix/alloc.c @@ -31,9 +31,8 @@ #include #include "py/mpstate.h" -#include "py/gc.h" -#if MICROPY_EMIT_NATIVE || (MICROPY_PY_FFI && MICROPY_FORCE_PLAT_ALLOC_EXEC) +#if MICROPY_EMIT_NATIVE #if defined(__OpenBSD__) || defined(__MACH__) #define MAP_ANONYMOUS MAP_ANON @@ -79,31 +78,6 @@ void mp_unix_free_exec(void *ptr, size_t size) { } } -void mp_unix_mark_exec(void) { - for (mmap_region_t *rg = MP_STATE_VM(mmap_region_head); rg != NULL; rg = rg->next) { - gc_collect_root(rg->ptr, rg->len / sizeof(mp_uint_t)); - } -} - -#if MICROPY_FORCE_PLAT_ALLOC_EXEC -// Provide implementation of libffi ffi_closure_* functions in terms -// of the functions above. On a normal Linux system, this save a lot -// of code size. -void *ffi_closure_alloc(size_t size, void **code); -void ffi_closure_free(void *ptr); - -void *ffi_closure_alloc(size_t size, void **code) { - size_t dummy; - mp_unix_alloc_exec(size, code, &dummy); - return *code; -} - -void ffi_closure_free(void *ptr) { - (void)ptr; - // TODO -} -#endif - MP_REGISTER_ROOT_POINTER(void *mmap_region_head); -#endif // MICROPY_EMIT_NATIVE || (MICROPY_PY_FFI && MICROPY_FORCE_PLAT_ALLOC_EXEC) +#endif // MICROPY_EMIT_NATIVE diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 4308ca6a1d27a..7f13f9756f177 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -4,8 +4,10 @@ #include "py/obj.h" #include "py/objfun.h" +#include "py/objint.h" #include "py/objstr.h" #include "py/runtime.h" +#include "py/stackctrl.h" #include "py/gc.h" #include "py/repl.h" #include "py/mpz.h" @@ -388,7 +390,7 @@ static mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "# str\n"); // intern string - mp_printf(&mp_plat_print, "%d\n", mp_obj_is_qstr(mp_obj_str_intern(mp_obj_new_str("intern me", 9)))); + mp_printf(&mp_plat_print, "%d\n", mp_obj_is_qstr(mp_obj_str_intern(mp_obj_new_str_from_cstr("intern me")))); } // bytearray @@ -455,6 +457,13 @@ static mp_obj_t extra_coverage(void) { mpz_mul_inpl(&mpz, &mpz2, &mpz); mpz_as_uint_checked(&mpz, &value); mp_printf(&mp_plat_print, "%d\n", (int)value); + + // mpz_not_inpl with argument==0, testing ~0 + mpz_set_from_int(&mpz, 0); + mpz_not_inpl(&mpz, &mpz); + mp_int_t value_signed; + mpz_as_int_checked(&mpz, &value_signed); + mp_printf(&mp_plat_print, "%d\n", (int)value_signed); } // runtime utils @@ -464,12 +473,15 @@ static mp_obj_t extra_coverage(void) { // call mp_call_function_1_protected mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), MP_OBJ_NEW_SMALL_INT(1)); // call mp_call_function_1_protected with invalid args - mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), mp_obj_new_str("abc", 3)); + mp_call_function_1_protected(MP_OBJ_FROM_PTR(&mp_builtin_abs_obj), mp_obj_new_str_from_cstr("abc")); // call mp_call_function_2_protected mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), MP_OBJ_NEW_SMALL_INT(1), MP_OBJ_NEW_SMALL_INT(1)); // call mp_call_function_2_protected with invalid args - mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), mp_obj_new_str("abc", 3), mp_obj_new_str("abc", 3)); + mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), mp_obj_new_str_from_cstr("abc"), mp_obj_new_str_from_cstr("abc")); + + // mp_obj_int_get_checked with mp_obj_int_t that has a value that is a small integer + mp_printf(&mp_plat_print, "%d\n", mp_obj_int_get_checked(mp_obj_int_new_mpz())); // mp_obj_int_get_uint_checked with non-negative small-int mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_uint_checked(MP_OBJ_NEW_SMALL_INT(1))); @@ -723,12 +735,38 @@ static mp_obj_t extra_coverage(void) { // mp_obj_is_integer accepts ints and booleans mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_integer(mp_obj_new_int_from_ll(1))); mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(mp_const_true), mp_obj_is_integer(mp_const_false)); - mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(mp_obj_new_str("1", 1)), mp_obj_is_integer(mp_const_none)); + mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(mp_obj_new_str_from_cstr("1")), mp_obj_is_integer(mp_const_none)); // mp_obj_is_int accepts small int and object ints mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_int(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_int(mp_obj_new_int_from_ll(1))); } + // Legacy stackctrl.h API, this has been replaced by cstack.h + { + mp_printf(&mp_plat_print, "# stackctrl\n"); + char *old_stack_top = MP_STATE_THREAD(stack_top); + size_t old_stack_limit = 0; + size_t new_stack_limit = SIZE_MAX; + #if MICROPY_STACK_CHECK + old_stack_limit = MP_STATE_THREAD(stack_limit); + MP_STACK_CHECK(); + #endif + + mp_stack_ctrl_init(); // Will set stack top incorrectly + mp_stack_set_top(old_stack_top); // ... and restore it + + #if MICROPY_STACK_CHECK + mp_stack_set_limit(MP_STATE_THREAD(stack_limit)); + MP_STACK_CHECK(); + new_stack_limit = MP_STATE_THREAD(stack_limit); + #endif + + // Nothing should have changed + mp_printf(&mp_plat_print, "%d %d\n", + old_stack_top == MP_STATE_THREAD(stack_top), + MICROPY_STACK_CHECK == 0 || old_stack_limit == new_stack_limit); + } + mp_printf(&mp_plat_print, "# end coverage.c\n"); mp_obj_streamtest_t *s = mp_obj_malloc(mp_obj_streamtest_t, &mp_type_stest_fileio); diff --git a/ports/unix/coveragecpp.cpp b/ports/unix/coveragecpp.cpp index 93c1b387fe285..377b5acf763ce 100644 --- a/ports/unix/coveragecpp.cpp +++ b/ports/unix/coveragecpp.cpp @@ -1,4 +1,5 @@ extern "C" { +// CIRCUITPY-CHANGE: do not include everything: it causes compilation warnings #include "py/obj.h" } diff --git a/ports/unix/gccollect.c b/ports/unix/gccollect.c index 94c9c61ea4d6a..8f0f5a6769d3d 100644 --- a/ports/unix/gccollect.c +++ b/ports/unix/gccollect.c @@ -39,9 +39,6 @@ void gc_collect(void) { #if MICROPY_PY_THREAD mp_thread_gc_others(); #endif - #if MICROPY_EMIT_NATIVE - mp_unix_mark_exec(); - #endif gc_collect_end(); } diff --git a/ports/unix/main.c b/ports/unix/main.c index 28521c1251438..73e61597050f6 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -44,7 +44,7 @@ #include "py/repl.h" #include "py/gc.h" #include "py/objstr.h" -#include "py/stackctrl.h" +#include "py/cstack.h" #include "py/mphal.h" #include "py/mpthread.h" #include "extmod/misc.h" @@ -350,6 +350,7 @@ static void print_help(char **argv) { printf( "usage: %s [] [-X ] [-c | -m | ]\n" "Options:\n" + "--version : show version information\n" "-h : print this help message\n" "-i : enable inspection via REPL after running command/module/file\n" #if MICROPY_DEBUG_PRINTERS @@ -401,6 +402,10 @@ static void pre_process_options(int argc, char **argv) { print_help(argv); exit(0); } + if (strcmp(argv[a], "--version") == 0) { + printf(MICROPY_BANNER_NAME_AND_VERSION "; " MICROPY_BANNER_MACHINE "\n"); + exit(0); + } if (strcmp(argv[a], "-X") == 0) { if (a + 1 >= argc) { exit(invalid_args()); @@ -500,12 +505,20 @@ int main(int argc, char **argv) { #if MICROPY_PY_THREAD mp_thread_init(); #endif + + // Define a reasonable stack limit to detect stack overflow. + mp_uint_t stack_size = 40000 * (sizeof(void *) / 4); + #if defined(__arm__) && !defined(__thumb2__) + // ARM (non-Thumb) architectures require more stack. + stack_size *= 2; + #endif + // We should capture stack top ASAP after start, and it should be // captured guaranteedly before any other stack variables are allocated. // For this, actual main (renamed main_) should not be inlined into // this function. main_() itself may have other functions inlined (with // their own stack variables), that's why we need this main/main_ split. - mp_stack_ctrl_init(); + mp_cstack_init_with_sp_here(stack_size); return main_(argc, argv); } @@ -524,14 +537,6 @@ MP_NOINLINE int main_(int argc, char **argv) { signal(SIGPIPE, SIG_IGN); #endif - // Define a reasonable stack limit to detect stack overflow. - mp_uint_t stack_limit = 40000 * (sizeof(void *) / 4); - #if defined(__arm__) && !defined(__thumb2__) - // ARM (non-Thumb) architectures require more stack. - stack_limit *= 2; - #endif - mp_stack_set_limit(stack_limit); - pre_process_options(argc, argv); #if MICROPY_ENABLE_GC @@ -594,7 +599,12 @@ MP_NOINLINE int main_(int argc, char **argv) { // First entry is empty. We've already added an empty entry to sys.path, so skip it. ++path; } - bool path_remaining = *path; + // GCC targeting RISC-V 64 reports a warning about `path_remaining` being clobbered by + // either setjmp or vfork if that variable it is allocated on the stack. This may + // probably be a compiler error as it occurs on a few recent GCC releases (up to 14.1.0) + // but LLVM doesn't report any warnings. + static bool path_remaining; + path_remaining = *path; while (path_remaining) { char *path_entry_end = strchr(path, PATHLIST_SEP_CHAR); if (path_entry_end == NULL) { @@ -676,7 +686,7 @@ MP_NOINLINE int main_(int argc, char **argv) { return invalid_args(); } mp_obj_t import_args[4]; - import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1])); + import_args[0] = mp_obj_new_str_from_cstr(argv[a + 1]); import_args[1] = import_args[2] = mp_const_none; // Ask __import__ to handle imported module specially - set its __name__ // to __main__, and also return this leaf module, not top-level package diff --git a/ports/unix/modffi.c b/ports/unix/modffi.c index b7d03e84dde6f..b469e932e0d5a 100644 --- a/ports/unix/modffi.c +++ b/ports/unix/modffi.c @@ -174,7 +174,7 @@ static mp_obj_t return_ffi_value(ffi_union_t *val, char type) { if (!s) { return mp_const_none; } - return mp_obj_new_str(s, strlen(s)); + return mp_obj_new_str_from_cstr(s); } case 'v': return mp_const_none; @@ -190,10 +190,13 @@ static mp_obj_t return_ffi_value(ffi_union_t *val, char type) { case 'h': case 'i': case 'l': - return mp_obj_new_int((signed)val->ffi); + return mp_obj_new_int((ffi_sarg)val->ffi); + case 'I': + // On RV64, 32-bit values are stored as signed integers inside the + // holding register. + return mp_obj_new_int_from_uint(val->ffi & 0xFFFFFFFF); case 'B': case 'H': - case 'I': case 'L': return mp_obj_new_int_from_uint(val->ffi); case 'q': @@ -334,7 +337,8 @@ static mp_obj_t mod_ffi_callback(size_t n_args, const mp_obj_t *pos_args, mp_map const char *rettype = mp_obj_str_get_str(rettype_in); mp_int_t nparams = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(paramtypes_in)); - mp_obj_fficallback_t *o = mp_obj_malloc_var(mp_obj_fficallback_t, params, ffi_type *, nparams, &fficallback_type); + mp_obj_fficallback_t *o = (mp_obj_fficallback_t *)m_tracked_calloc(offsetof(mp_obj_fficallback_t, params) + sizeof(ffi_type *) * nparams, sizeof(uint8_t)); + o->base.type = &fficallback_type; o->clo = ffi_closure_alloc(sizeof(ffi_closure), &o->func); diff --git a/ports/unix/modjni.c b/ports/unix/modjni.c index d953e7e015237..dbce61aec1135 100644 --- a/ports/unix/modjni.c +++ b/ports/unix/modjni.c @@ -337,7 +337,7 @@ static mp_obj_t new_jobject(jobject jo) { return mp_const_none; } else if (JJ(IsInstanceOf, jo, String_class)) { const char *s = JJ(GetStringUTFChars, jo, NULL); - mp_obj_t ret = mp_obj_new_str(s, strlen(s)); + mp_obj_t ret = mp_obj_new_str_from_cstr(s); JJ(ReleaseStringUTFChars, jo, s); return ret; } else if (JJ(IsInstanceOf, jo, Class_class)) { diff --git a/ports/unix/modmachine.c b/ports/unix/modmachine.c index 6f3ab80944061..d1cdbe8619aba 100644 --- a/ports/unix/modmachine.c +++ b/ports/unix/modmachine.c @@ -36,9 +36,6 @@ #define MICROPY_PAGE_MASK (MICROPY_PAGE_SIZE - 1) #endif -// This variable is needed for machine.soft_reset(), but the variable is otherwise unused. -int pyexec_system_exit = 0; - uintptr_t mod_machine_mem_get_addr(mp_obj_t addr_o, uint align) { uintptr_t addr = mp_obj_get_int_truncated(addr_o); if ((addr & (align - 1)) != 0) { diff --git a/ports/unix/modos.c b/ports/unix/modos.c index 09d829843100a..896bf351b83f1 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -56,7 +56,7 @@ static mp_obj_t mp_os_getenv(size_t n_args, const mp_obj_t *args) { } return mp_const_none; } - return mp_obj_new_str(s, strlen(s)); + return mp_obj_new_str_from_cstr(s); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_os_getenv_obj, 1, 2, mp_os_getenv); diff --git a/ports/unix/modtermios.c b/ports/unix/modtermios.c index b1ad9a450e0c8..d7b94038aa138 100644 --- a/ports/unix/modtermios.c +++ b/ports/unix/modtermios.c @@ -141,6 +141,27 @@ static const mp_rom_map_elem_t mp_module_termios_globals_table[] = { #ifdef B115200 C(B115200), #endif + #ifdef B230400 + C(B230400), + #endif + #ifdef B460800 + C(B460800), + #endif + #ifdef B500000 + C(B500000), + #endif + #ifdef B576000 + C(B576000), + #endif + #ifdef B921600 + C(B921600), + #endif + #ifdef B1000000 + C(B1000000), + #endif + #ifdef B1152000 + C(B1152000) + #endif #undef C }; diff --git a/ports/unix/mpbthciport.c b/ports/unix/mpbthciport.c index 95c39f559910d..765146677e8c5 100644 --- a/ports/unix/mpbthciport.c +++ b/ports/unix/mpbthciport.c @@ -196,10 +196,7 @@ int mp_bluetooth_hci_uart_init(uint32_t port, uint32_t baudrate) { } // Create a thread to run the polling loop. - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&hci_poll_thread_id, &attr, &hci_poll_thread, NULL); + pthread_create(&hci_poll_thread_id, NULL, &hci_poll_thread, NULL); return 0; } diff --git a/ports/unix/mpbtstackport_usb.c b/ports/unix/mpbtstackport_usb.c index 8b1d1fff2189f..a924fc3ca912a 100644 --- a/ports/unix/mpbtstackport_usb.c +++ b/ports/unix/mpbtstackport_usb.c @@ -110,10 +110,7 @@ static void *btstack_thread(void *arg) { void mp_bluetooth_btstack_port_start(void) { // Create a thread to run the btstack loop. - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&bstack_thread_id, &attr, &btstack_thread, NULL); + pthread_create(&bstack_thread_id, NULL, &btstack_thread, NULL); } #endif // MICROPY_PY_BLUETOOTH && MICROPY_BLUETOOTH_BTSTACK && MICROPY_BLUETOOTH_BTSTACK_USB diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 185d4dcf3401c..4d9fe9f1dc4a2 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -115,7 +115,7 @@ typedef long mp_off_t; // CIRCUITPY-CHANGE #define MICROPY_ENABLE_SELECTIVE_COLLECT (1) -#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__)) +#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__) || (defined(__riscv) && (__riscv_xlen == 64))) // Fall back to setjmp() implementation for discovery of GC pointers in registers. #define MICROPY_GCREGS_SETJMP (1) #endif @@ -127,8 +127,9 @@ typedef long mp_off_t; #define MICROPY_HELPER_LEXER_UNIX (1) #define MICROPY_VFS_POSIX (1) #define MICROPY_READER_POSIX (1) +// CIRCUITPY-CHANGE: define no matter what #ifndef MICROPY_TRACKED_ALLOC -#define MICROPY_TRACKED_ALLOC (MICROPY_BLUETOOTH_BTSTACK) +#define MICROPY_TRACKED_ALLOC (MICROPY_PY_FFI || MICROPY_BLUETOOTH_BTSTACK) #endif // VFS stat functions should return time values relative to 1970/1/1 @@ -182,14 +183,8 @@ extern const struct _mp_print_t mp_stderr_print; // For the native emitter configure how to mark a region as executable. void mp_unix_alloc_exec(size_t min_size, void **ptr, size_t *size); void mp_unix_free_exec(void *ptr, size_t size); -void mp_unix_mark_exec(void); #define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) mp_unix_alloc_exec(min_size, ptr, size) #define MP_PLAT_FREE_EXEC(ptr, size) mp_unix_free_exec(ptr, size) -#ifndef MICROPY_FORCE_PLAT_ALLOC_EXEC -// Use MP_PLAT_ALLOC_EXEC for any executable memory allocation, including for FFI -// (overriding libffi own implementation) -#define MICROPY_FORCE_PLAT_ALLOC_EXEC (1) -#endif // If enabled, configure how to seed random on init. #ifdef MICROPY_PY_RANDOM_SEED_INIT_FUNC diff --git a/ports/unix/mpconfigport.mk b/ports/unix/mpconfigport.mk index d6b57ca88601a..26c04faf4c5ca 100644 --- a/ports/unix/mpconfigport.mk +++ b/ports/unix/mpconfigport.mk @@ -41,7 +41,7 @@ MICROPY_PY_JNI = 0 # Avoid using system libraries, use copies bundled with MicroPython # as submodules (currently affects only libffi). -MICROPY_STANDALONE = 0 +MICROPY_STANDALONE ?= 0 # CIRCUITPY-CHANGE: not used MICROPY_ROM_TEXT_COMPRESSION = 0 diff --git a/ports/unix/variants/coverage/mpconfigvariant.h b/ports/unix/variants/coverage/mpconfigvariant.h index 11f4b2eb4b1b5..12823f3c2b5fc 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.h +++ b/ports/unix/variants/coverage/mpconfigvariant.h @@ -45,5 +45,6 @@ // CIRCUITPY-CHANGE: Disable things never used in circuitpython #define MICROPY_PY_CRYPTOLIB (0) #define MICROPY_PY_CRYPTOLIB_CTR (0) +#define MICROPY_PY_MICROPYTHON_RINGIO (0) // CircuitPython uses shared-bindings struct #define MICROPY_PY_STRUCT (0) diff --git a/ports/unix/variants/mpconfigvariant_common.h b/ports/unix/variants/mpconfigvariant_common.h index 2e34055bf773f..cea0397414325 100644 --- a/ports/unix/variants/mpconfigvariant_common.h +++ b/ports/unix/variants/mpconfigvariant_common.h @@ -95,7 +95,6 @@ #define MICROPY_PY_OS_INCLUDEFILE "ports/unix/modos.c" #define MICROPY_PY_OS_ERRNO (1) #define MICROPY_PY_OS_GETENV_PUTENV_UNSETENV (1) -#define MICROPY_PY_OS_SEP (1) #define MICROPY_PY_OS_SYSTEM (1) #define MICROPY_PY_OS_URANDOM (1) diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index aecccebb9c850..222a325e346b6 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -78,6 +78,7 @@ pwmio = false qrio = false rainbowio = false random = true +rclcpy = false rgbmatrix = false rotaryio = false rtc = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 27e4f35f22366..41631c3d6c02c 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -78,6 +78,7 @@ pwmio = false qrio = false rainbowio = false random = true +rclcpy = false rgbmatrix = false rotaryio = false rtc = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 35e3791507023..ea009aa36e1ca 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -78,6 +78,7 @@ pwmio = false qrio = false rainbowio = false random = true +rclcpy = false rgbmatrix = false rotaryio = false rtc = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 4f4ee95bd0296..a96d1bad1d2a6 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -78,6 +78,7 @@ pwmio = false qrio = false rainbowio = false random = true +rclcpy = false rgbmatrix = false rotaryio = false rtc = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 90bb28c341ef6..e4946decb190b 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -78,6 +78,7 @@ pwmio = false qrio = false rainbowio = false random = true +rclcpy = false rgbmatrix = false rotaryio = false rtc = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index c6fa66037a9ac..7519d8817687b 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -78,6 +78,7 @@ pwmio = false qrio = false rainbowio = false random = true +rclcpy = false rgbmatrix = false rotaryio = false rtc = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 9e117262b3f91..e029020982d20 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -78,6 +78,7 @@ pwmio = false qrio = false rainbowio = false random = true +rclcpy = false rgbmatrix = false rotaryio = false rtc = false diff --git a/py/asmbase.c b/py/asmbase.c index cf64e3f3d054f..3fce543a7f485 100644 --- a/py/asmbase.c +++ b/py/asmbase.c @@ -30,6 +30,7 @@ #include "py/obj.h" #include "py/misc.h" #include "py/asmbase.h" +#include "py/persistentcode.h" #if MICROPY_EMIT_MACHINE_CODE @@ -91,6 +92,11 @@ void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label) { } else { // ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT assert(as->label_offsets[label] == as->code_offset); + #if MICROPY_DYNAMIC_COMPILER && MICROPY_EMIT_NATIVE_DEBUG + if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_DEBUG) { + mp_printf(MICROPY_EMIT_NATIVE_DEBUG_PRINTER, "label(label_%u)\n", (unsigned int)label); + } + #endif } } diff --git a/py/asmbase.h b/py/asmbase.h index 352d2f54cc810..461393fe77fb7 100644 --- a/py/asmbase.h +++ b/py/asmbase.h @@ -27,6 +27,7 @@ #define MICROPY_INCLUDED_PY_ASMBASE_H #include +#include #include #define MP_ASM_PASS_COMPUTE (1) diff --git a/py/asmrv32.c b/py/asmrv32.c new file mode 100644 index 0000000000000..3f3395842efb9 --- /dev/null +++ b/py/asmrv32.c @@ -0,0 +1,631 @@ +/* + * This file is part of the MicroPython project, https://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Alessandro Gatti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/emit.h" +#include "py/mpconfig.h" + +// wrapper around everything in this file +#if MICROPY_EMIT_RV32 + +#include "py/asmrv32.h" + +#if MICROPY_DEBUG_VERBOSE +#define DEBUG_PRINT (1) +#define DEBUG_printf DEBUG_printf +#else +#define DEBUG_printf(...) (void)0 +#endif + +#ifndef MP_POPCOUNT +#ifdef _MSC_VER +#include +#define MP_POPCOUNT __popcnt +#else +#if defined __has_builtin +#if __has_builtin(__builtin_popcount) +#define MP_POPCOUNT __builtin_popcount +#endif +#else +static uint32_t fallback_popcount(uint32_t value) { + value = value - ((value >> 1) & 0x55555555); + value = (value & 0x33333333) + ((value >> 2) & 0x33333333); + value = (value + (value >> 4)) & 0x0F0F0F0F; + return value * 0x01010101; +} +#define MP_POPCOUNT fallback_popcount +#endif +#endif +#endif + +#define INTERNAL_TEMPORARY ASM_RV32_REG_S0 +#define AVAILABLE_REGISTERS_COUNT 32 + +#define IS_IN_C_REGISTER_WINDOW(register_number) \ + (((register_number) >= ASM_RV32_REG_X8) && ((register_number) <= ASM_RV32_REG_X15)) +#define MAP_IN_C_REGISTER_WINDOW(register_number) \ + ((register_number) - ASM_RV32_REG_X8) + +#define FIT_UNSIGNED(value, bits) (((value) & ~((1U << (bits)) - 1)) == 0) +#define FIT_SIGNED(value, bits) \ + ((((value) & ~((1U << ((bits) - 1)) - 1)) == 0) || \ + (((value) & ~((1U << ((bits) - 1)) - 1)) == ~((1U << ((bits) - 1)) - 1))) + +/////////////////////////////////////////////////////////////////////////////// + +void asm_rv32_emit_word_opcode(asm_rv32_t *state, mp_uint_t word) { + uint8_t *cursor = mp_asm_base_get_cur_to_write_bytes(&state->base, sizeof(uint32_t)); + if (cursor == NULL) { + return; + } + + #if MP_ENDIANNESS_LITTLE + cursor[0] = word & 0xFF; + cursor[1] = (word >> 8) & 0xFF; + cursor[2] = (word >> 16) & 0xFF; + cursor[3] = (word >> 24) & 0xFF; + #else + cursor[0] = (word >> 24) & 0xFF; + cursor[1] = (word >> 16) & 0xFF; + cursor[2] = (word >> 8) & 0xFF; + cursor[3] = word & 0xFF; + #endif +} + +void asm_rv32_emit_halfword_opcode(asm_rv32_t *state, mp_uint_t word) { + uint8_t *cursor = mp_asm_base_get_cur_to_write_bytes(&state->base, sizeof(uint16_t)); + if (cursor == NULL) { + return; + } + + #if MP_ENDIANNESS_LITTLE + cursor[0] = word & 0xFF; + cursor[1] = (word >> 8) & 0xFF; + #else + cursor[0] = (word >> 8) & 0xFF; + cursor[1] = word & 0xFF; + #endif +} + +/////////////////////////////////////////////////////////////////////////////// + +static void split_immediate(mp_int_t immediate, mp_uint_t *upper, mp_uint_t *lower) { + assert(upper != NULL && "Upper pointer is NULL."); + assert(lower != NULL && "Lower pointer is NULL."); + + mp_uint_t unsigned_immediate = *((mp_uint_t *)&immediate); + *upper = unsigned_immediate & 0xFFFFF000; + *lower = unsigned_immediate & 0x00000FFF; + + // Turn the lower half from unsigned to signed. + if ((*lower & 0x800) != 0) { + *upper += 0x1000; + *lower -= 0x1000; + } +} + +static void load_upper_immediate(asm_rv32_t *state, mp_uint_t rd, mp_uint_t immediate) { + // if immediate fits in 17 bits and is ≠ 0: + // c.lui rd, HI(immediate) + // else: + // lui rd, HI(immediate) + if (FIT_SIGNED(immediate, 17) && ((immediate >> 12) != 0)) { + asm_rv32_opcode_clui(state, rd, immediate); + } else { + asm_rv32_opcode_lui(state, rd, immediate); + } +} + +static void load_lower_immediate(asm_rv32_t *state, mp_uint_t rd, mp_uint_t immediate) { + // WARNING: This must be executed on a register that has either been + // previously cleared or was the target of a LUI/C.LUI or + // AUIPC opcode. + + if (immediate == 0) { + return; + } + + // if LO(immediate) fits in 6 bits: + // c.addi rd, LO(immediate) + // else: + // addi rd, rd, LO(immediate) + if (FIT_SIGNED(immediate, 6)) { + asm_rv32_opcode_caddi(state, rd, immediate); + } else { + asm_rv32_opcode_addi(state, rd, rd, immediate); + } +} + +static void load_full_immediate(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate) { + mp_uint_t upper = 0; + mp_uint_t lower = 0; + split_immediate(immediate, &upper, &lower); + + // if immediate fits in 17 bits: + // c.lui rd, HI(immediate) + // else: + // lui rd, HI(immediate) + // if LO(immediate) fits in 6 bits && LO(immediate) != 0: + // c.addi rd, LO(immediate) + // else: + // addi rd, rd, LO(immediate) + load_upper_immediate(state, rd, upper); + load_lower_immediate(state, rd, lower); +} + +void asm_rv32_emit_optimised_load_immediate(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate) { + if (FIT_SIGNED(immediate, 6)) { + // c.li rd, immediate + asm_rv32_opcode_cli(state, rd, immediate); + return; + } + + if (FIT_SIGNED(immediate, 12)) { + // addi rd, zero, immediate + asm_rv32_opcode_addi(state, rd, ASM_RV32_REG_ZERO, immediate); + return; + } + + load_full_immediate(state, rd, immediate); +} + +// RV32 does not have dedicated push/pop opcodes, so series of loads and +// stores are generated in their place. + +static void emit_registers_store(asm_rv32_t *state, mp_uint_t registers_mask) { + mp_uint_t offset = 0; + for (mp_uint_t register_index = 0; register_index < AVAILABLE_REGISTERS_COUNT; register_index++) { + if (registers_mask & (1U << register_index)) { + assert(FIT_UNSIGNED(offset >> 2, 6) && "Registers save stack offset out of range."); + // c.swsp register, offset + asm_rv32_opcode_cswsp(state, register_index, offset); + offset += sizeof(uint32_t); + } + } +} + +static void emit_registers_load(asm_rv32_t *state, mp_uint_t registers_mask) { + mp_uint_t offset = 0; + for (mp_uint_t register_index = 0; register_index < AVAILABLE_REGISTERS_COUNT; register_index++) { + if (registers_mask & (1U << register_index)) { + assert(FIT_UNSIGNED(offset >> 2, 6) && "Registers load stack offset out of range."); + // c.lwsp register, offset + asm_rv32_opcode_clwsp(state, register_index, offset); + offset += sizeof(uint32_t); + } + } +} + +static void adjust_stack(asm_rv32_t *state, mp_int_t stack_size) { + if (stack_size == 0) { + return; + } + + if (FIT_SIGNED(stack_size, 6)) { + // c.addi sp, stack_size + asm_rv32_opcode_caddi(state, ASM_RV32_REG_SP, stack_size); + return; + } + + if (FIT_SIGNED(stack_size, 12)) { + // addi sp, sp, stack_size + asm_rv32_opcode_addi(state, ASM_RV32_REG_SP, ASM_RV32_REG_SP, stack_size); + return; + } + + // li temporary, stack_size + // c.add sp, temporary + load_full_immediate(state, REG_TEMP0, stack_size); + asm_rv32_opcode_cadd(state, ASM_RV32_REG_SP, REG_TEMP0); +} + +// Generate a generic function entry prologue code sequence, setting up the +// stack to hold all the tainted registers and an arbitrary amount of space +// for locals. +static void emit_function_prologue(asm_rv32_t *state, mp_uint_t registers) { + mp_uint_t registers_count = MP_POPCOUNT(registers); + state->stack_size = (registers_count + state->locals_count) * sizeof(uint32_t); + mp_uint_t old_saved_registers_mask = state->saved_registers_mask; + // Move stack pointer up. + adjust_stack(state, -state->stack_size); + // Store registers at the top of the saved stack area. + emit_registers_store(state, registers); + state->locals_stack_offset = registers_count * sizeof(uint32_t); + state->saved_registers_mask = old_saved_registers_mask; +} + +// Restore registers and reset the stack pointer to its initial value. +static void emit_function_epilogue(asm_rv32_t *state, mp_uint_t registers) { + mp_uint_t old_saved_registers_mask = state->saved_registers_mask; + // Restore registers from the top of the stack area. + emit_registers_load(state, registers); + // Move stack pointer down. + adjust_stack(state, state->stack_size); + state->saved_registers_mask = old_saved_registers_mask; +} + +static bool calculate_displacement_for_label(asm_rv32_t *state, mp_uint_t label, ptrdiff_t *displacement) { + assert(displacement != NULL && "Displacement pointer is NULL"); + + mp_uint_t label_offset = state->base.label_offsets[label]; + *displacement = (ptrdiff_t)(label_offset - state->base.code_offset); + return (label_offset != (mp_uint_t)-1) && (*displacement < 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +void asm_rv32_entry(asm_rv32_t *state, mp_uint_t locals) { + state->saved_registers_mask |= (1U << REG_FUN_TABLE) | (1U << REG_LOCAL_1) | \ + (1U << REG_LOCAL_2) | (1U << REG_LOCAL_3) | (1U << INTERNAL_TEMPORARY); + state->locals_count = locals; + emit_function_prologue(state, state->saved_registers_mask); +} + +void asm_rv32_exit(asm_rv32_t *state) { + emit_function_epilogue(state, state->saved_registers_mask); + // c.jr ra + asm_rv32_opcode_cjr(state, ASM_RV32_REG_RA); +} + +void asm_rv32_end_pass(asm_rv32_t *state) { + (void)state; +} + +void asm_rv32_emit_call_ind(asm_rv32_t *state, mp_uint_t index) { + mp_uint_t offset = index * ASM_WORD_SIZE; + state->saved_registers_mask |= (1U << ASM_RV32_REG_RA); + + if (IS_IN_C_REGISTER_WINDOW(REG_FUN_TABLE) && IS_IN_C_REGISTER_WINDOW(INTERNAL_TEMPORARY) && FIT_UNSIGNED(offset, 6)) { + // c.lw temporary, offset(fun_table) + // c.jalr temporary + asm_rv32_opcode_clw(state, MAP_IN_C_REGISTER_WINDOW(INTERNAL_TEMPORARY), MAP_IN_C_REGISTER_WINDOW(REG_FUN_TABLE), offset); + asm_rv32_opcode_cjalr(state, INTERNAL_TEMPORARY); + return; + } + + if (FIT_UNSIGNED(offset, 11)) { + // lw temporary, offset(fun_table) + // c.jalr temporary + asm_rv32_opcode_lw(state, REG_TEMP2, REG_FUN_TABLE, offset); + asm_rv32_opcode_cjalr(state, REG_TEMP2); + return; + } + + mp_uint_t upper = 0; + mp_uint_t lower = 0; + split_immediate(offset, &upper, &lower); + + // lui temporary, HI(index) ; Or c.lui if possible + // c.add temporary, fun_table + // lw temporary, LO(index)(temporary) + // c.jalr temporary + load_upper_immediate(state, REG_TEMP2, upper); + asm_rv32_opcode_cadd(state, REG_TEMP2, REG_FUN_TABLE); + asm_rv32_opcode_lw(state, REG_TEMP2, REG_TEMP2, lower); + asm_rv32_opcode_cjalr(state, REG_TEMP2); +} + +void asm_rv32_emit_jump_if_reg_eq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t label) { + ptrdiff_t displacement = 0; + bool can_emit_short_jump = calculate_displacement_for_label(state, label, &displacement); + + if (can_emit_short_jump && FIT_SIGNED(displacement, 13)) { + // beq rs1, rs2, displacement + asm_rv32_opcode_beq(state, rs1, rs2, displacement); + return; + } + + // Compensate for the initial BNE opcode. + displacement -= ASM_WORD_SIZE; + + mp_uint_t upper = 0; + mp_uint_t lower = 0; + split_immediate(displacement, &upper, &lower); + + // bne rs1, rs2, 12 ; PC + 0 + // auipc temporary, HI(displacement) ; PC + 4 + // jalr zero, temporary, LO(displacement) ; PC + 8 + // ... ; PC + 12 + asm_rv32_opcode_bne(state, rs1, rs2, 12); + asm_rv32_opcode_auipc(state, REG_TEMP2, upper); + asm_rv32_opcode_jalr(state, ASM_RV32_REG_ZERO, REG_TEMP2, lower); +} + +void asm_rv32_emit_jump_if_reg_nonzero(asm_rv32_t *state, mp_uint_t rs, mp_uint_t label) { + ptrdiff_t displacement = 0; + bool can_emit_short_jump = calculate_displacement_for_label(state, label, &displacement); + + if (can_emit_short_jump && FIT_SIGNED(displacement, 8) && IS_IN_C_REGISTER_WINDOW(rs)) { + // c.bnez rs', displacement + asm_rv32_opcode_cbnez(state, MAP_IN_C_REGISTER_WINDOW(rs), displacement); + return; + } + + if (can_emit_short_jump && FIT_SIGNED(displacement, 13)) { + // bne rs, zero, displacement + asm_rv32_opcode_bne(state, rs, ASM_RV32_REG_ZERO, displacement); + return; + } + + // if rs1 in C window and displacement is negative: + // c.beqz rs', 10 ; PC + 0 + // auipc temporary, HI(displacement) ; PC + 2 + // jalr zero, temporary, LO(displacement) ; PC + 6 + // ... ; PC + 10 + // else: + // beq rs, zero, 12 ; PC + 0 + // auipc temporary, HI(displacement) ; PC + 4 + // jalr zero, temporary, LO(displacement) ; PC + 8 + // ... ; PC + 12 + + if (can_emit_short_jump && IS_IN_C_REGISTER_WINDOW(rs)) { + asm_rv32_opcode_cbeqz(state, MAP_IN_C_REGISTER_WINDOW(rs), 10); + // Compensate for the C.BEQZ opcode. + displacement -= ASM_HALFWORD_SIZE; + } else { + asm_rv32_opcode_beq(state, rs, ASM_RV32_REG_ZERO, 12); + // Compensate for the BEQ opcode. + displacement -= ASM_WORD_SIZE; + } + + mp_uint_t upper = 0; + mp_uint_t lower = 0; + split_immediate(displacement, &upper, &lower); + asm_rv32_opcode_auipc(state, REG_TEMP2, upper); + asm_rv32_opcode_jalr(state, ASM_RV32_REG_ZERO, REG_TEMP2, lower); +} + +void asm_rv32_emit_mov_local_reg(asm_rv32_t *state, mp_uint_t local, mp_uint_t rs) { + mp_uint_t offset = state->locals_stack_offset + (local * ASM_WORD_SIZE); + + if (FIT_UNSIGNED(offset >> 2, 6)) { + // c.swsp rs, offset + asm_rv32_opcode_cswsp(state, rs, offset); + return; + } + + if (FIT_UNSIGNED(offset, 11)) { + // sw rs, offset(sp) + asm_rv32_opcode_sw(state, rs, ASM_RV32_REG_SP, offset); + return; + } + + mp_uint_t upper = 0; + mp_uint_t lower = 0; + split_immediate(offset, &upper, &lower); + + // lui temporary, HI(offset) ; Or c.lui if possible + // c.add temporary, sp + // sw rs, LO(offset)(temporary) + load_upper_immediate(state, REG_TEMP2, upper); + asm_rv32_opcode_cadd(state, REG_TEMP2, ASM_RV32_REG_SP); + asm_rv32_opcode_sw(state, rs, REG_TEMP2, lower); +} + +void asm_rv32_emit_mov_reg_local(asm_rv32_t *state, mp_uint_t rd, mp_uint_t local) { + mp_uint_t offset = state->locals_stack_offset + (local * ASM_WORD_SIZE); + + if (FIT_UNSIGNED(offset >> 2, 6)) { + // c.lwsp rd, offset + asm_rv32_opcode_clwsp(state, rd, offset); + return; + } + + if (FIT_UNSIGNED(offset, 11)) { + // lw rd, offset(sp) + asm_rv32_opcode_lw(state, rd, ASM_RV32_REG_SP, offset); + return; + } + + mp_uint_t upper = 0; + mp_uint_t lower = 0; + split_immediate(offset, &upper, &lower); + + // lui rd, HI(offset) ; Or c.lui if possible + // c.add rd, sp + // lw rd, LO(offset)(rd) + load_upper_immediate(state, rd, upper); + asm_rv32_opcode_cadd(state, rd, ASM_RV32_REG_SP); + asm_rv32_opcode_lw(state, rd, rd, lower); +} + +void asm_rv32_emit_mov_reg_local_addr(asm_rv32_t *state, mp_uint_t rd, mp_uint_t local) { + mp_uint_t offset = state->locals_stack_offset + (local * ASM_WORD_SIZE); + + if (FIT_UNSIGNED(offset, 10) && offset != 0 && IS_IN_C_REGISTER_WINDOW(rd)) { + // c.addi4spn rd', offset + asm_rv32_opcode_caddi4spn(state, MAP_IN_C_REGISTER_WINDOW(rd), offset); + return; + } + + if (FIT_UNSIGNED(offset, 11)) { + // addi rd, sp, offset + asm_rv32_opcode_addi(state, rd, ASM_RV32_REG_SP, offset); + return; + } + + // li rd, offset + // c.add rd, sp + load_full_immediate(state, rd, offset); + asm_rv32_opcode_cadd(state, rd, ASM_RV32_REG_SP); +} + +void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { + mp_int_t scaled_offset = offset * sizeof(ASM_WORD_SIZE); + + if (scaled_offset >= 0 && IS_IN_C_REGISTER_WINDOW(rd) && IS_IN_C_REGISTER_WINDOW(rs) && FIT_UNSIGNED(scaled_offset, 6)) { + // c.lw rd', offset(rs') + asm_rv32_opcode_clw(state, MAP_IN_C_REGISTER_WINDOW(rd), MAP_IN_C_REGISTER_WINDOW(rs), scaled_offset); + return; + } + + if (FIT_SIGNED(scaled_offset, 12)) { + // lw rd, offset(rs) + asm_rv32_opcode_lw(state, rd, rs, scaled_offset); + return; + } + + mp_uint_t upper = 0; + mp_uint_t lower = 0; + split_immediate(scaled_offset, &upper, &lower); + + // lui rd, HI(offset) ; Or c.lui if possible + // c.add rd, rs + // lw rd, LO(offset)(rd) + load_upper_immediate(state, rd, upper); + asm_rv32_opcode_cadd(state, rd, rs); + asm_rv32_opcode_lw(state, rd, rd, lower); +} + +void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label) { + ptrdiff_t displacement = 0; + bool can_emit_short_jump = calculate_displacement_for_label(state, label, &displacement); + + if (can_emit_short_jump && FIT_SIGNED(displacement, 12)) { + // c.j displacement + asm_rv32_opcode_cj(state, displacement); + return; + } + + mp_uint_t upper = 0; + mp_uint_t lower = 0; + split_immediate(displacement, &upper, &lower); + + // auipc temporary, HI(displacement) + // jalr zero, temporary, LO(displacement) + asm_rv32_opcode_auipc(state, REG_TEMP2, upper); + asm_rv32_opcode_jalr(state, ASM_RV32_REG_ZERO, REG_TEMP2, lower); +} + +void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { + mp_int_t scaled_offset = offset * ASM_WORD_SIZE; + + if (FIT_SIGNED(scaled_offset, 12)) { + // sw rd, offset(rs) + asm_rv32_opcode_sw(state, rd, rs, scaled_offset); + return; + } + + mp_uint_t upper = 0; + mp_uint_t lower = 0; + split_immediate(scaled_offset, &upper, &lower); + + // lui temporary, HI(offset) ; Or c.lui if possible + // c.add temporary, rs + // sw rd, LO(offset)(temporary) + load_upper_immediate(state, REG_TEMP2, upper); + asm_rv32_opcode_cadd(state, REG_TEMP2, rs); + asm_rv32_opcode_sw(state, rd, REG_TEMP2, lower); +} + +void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t label) { + ptrdiff_t displacement = (ptrdiff_t)(state->base.label_offsets[label] - state->base.code_offset); + mp_uint_t upper = 0; + mp_uint_t lower = 0; + split_immediate(displacement, &upper, &lower); + + // auipc rd, HI(relative) + // addi rd, rd, LO(relative) + asm_rv32_opcode_auipc(state, rd, upper); + asm_rv32_opcode_addi(state, rd, rd, lower); +} + +void asm_rv32_emit_load16_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { + mp_int_t scaled_offset = offset * sizeof(uint16_t); + + if (FIT_SIGNED(scaled_offset, 12)) { + // lhu rd, offset(rs) + asm_rv32_opcode_lhu(state, rd, rs, scaled_offset); + return; + } + + mp_uint_t upper = 0; + mp_uint_t lower = 0; + split_immediate(scaled_offset, &upper, &lower); + + // lui rd, HI(offset) ; Or c.lui if possible + // c.add rd, rs + // lhu rd, LO(offset)(rd) + load_upper_immediate(state, rd, upper); + asm_rv32_opcode_cadd(state, rd, rs); + asm_rv32_opcode_lhu(state, rd, rd, lower); +} + +void asm_rv32_emit_optimised_xor(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs) { + if (rs == rd) { + // c.li rd, 0 + asm_rv32_opcode_cli(state, rd, 0); + return; + } + + // xor rd, rd, rs + asm_rv32_opcode_xor(state, rd, rd, rs); +} + +void asm_rv32_meta_comparison_eq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd) { + // c.li rd, 1 ; + // beq rs1, rs2, 6 ; PC + 0 + // c.li rd, 0 ; PC + 4 + // ... ; PC + 6 + asm_rv32_opcode_cli(state, rd, 1); + asm_rv32_opcode_beq(state, rs1, rs2, 6); + asm_rv32_opcode_cli(state, rd, 0); +} + +void asm_rv32_meta_comparison_ne(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd) { + // sub rd, rs1, rs2 + // sltu rd, zero, rd + asm_rv32_opcode_sub(state, rd, rs1, rs2); + asm_rv32_opcode_sltu(state, rd, ASM_RV32_REG_ZERO, rd); +} + +void asm_rv32_meta_comparison_lt(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd, bool unsigned_comparison) { + // slt(u) rd, rs1, rs2 + if (unsigned_comparison) { + asm_rv32_opcode_sltu(state, rd, rs1, rs2); + } else { + asm_rv32_opcode_slt(state, rd, rs1, rs2); + } +} + +void asm_rv32_meta_comparison_le(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd, bool unsigned_comparison) { + // c.li rd, 1 ; + // beq rs1, rs2, 8 ; PC + 0 + // slt(u) rd, rs1, rs2 ; PC + 4 + // ... ; PC + 8 + asm_rv32_opcode_cli(state, rd, 1); + asm_rv32_opcode_beq(state, rs1, rs2, 8); + if (unsigned_comparison) { + asm_rv32_opcode_sltu(state, rd, rs1, rs2); + } else { + asm_rv32_opcode_slt(state, rd, rs1, rs2); + } +} + +#endif // MICROPY_EMIT_RV32 diff --git a/py/asmrv32.h b/py/asmrv32.h new file mode 100644 index 0000000000000..775cf1ffc9630 --- /dev/null +++ b/py/asmrv32.h @@ -0,0 +1,496 @@ +/* + * This file is part of the MicroPython project, https://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Alessandro Gatti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_PY_ASMRV32_H +#define MICROPY_INCLUDED_PY_ASMRV32_H + +#include + +#include "py/asmbase.h" +#include "py/emit.h" +#include "py/misc.h" +#include "py/persistentcode.h" + +#define ASM_RV32_REG_X0 (0) // Zero +#define ASM_RV32_REG_X1 (1) // RA +#define ASM_RV32_REG_X2 (2) // SP +#define ASM_RV32_REG_X3 (3) // GP +#define ASM_RV32_REG_X4 (4) // TP +#define ASM_RV32_REG_X5 (5) // T0 +#define ASM_RV32_REG_X6 (6) // T1 +#define ASM_RV32_REG_X7 (7) // T2 +#define ASM_RV32_REG_X8 (8) // S0 +#define ASM_RV32_REG_X9 (9) // S1 +#define ASM_RV32_REG_X10 (10) // A0 +#define ASM_RV32_REG_X11 (11) // A1 +#define ASM_RV32_REG_X12 (12) // A2 +#define ASM_RV32_REG_X13 (13) // A3 +#define ASM_RV32_REG_X14 (14) // A4 +#define ASM_RV32_REG_X15 (15) // A5 +#define ASM_RV32_REG_X16 (16) // A6 +#define ASM_RV32_REG_X17 (17) // A7 +#define ASM_RV32_REG_X18 (18) // S2 +#define ASM_RV32_REG_X19 (19) // S3 +#define ASM_RV32_REG_X20 (20) // S4 +#define ASM_RV32_REG_X21 (21) // S5 +#define ASM_RV32_REG_X22 (22) // S6 +#define ASM_RV32_REG_X23 (23) // S7 +#define ASM_RV32_REG_X24 (24) // S8 +#define ASM_RV32_REG_X25 (25) // S9 +#define ASM_RV32_REG_X26 (26) // S10 +#define ASM_RV32_REG_X27 (27) // S11 +#define ASM_RV32_REG_X28 (28) // T3 +#define ASM_RV32_REG_X29 (29) // T4 +#define ASM_RV32_REG_X30 (30) // T5 +#define ASM_RV32_REG_X31 (31) // T6 + +// Alternate register names. + +#define ASM_RV32_REG_ZERO (ASM_RV32_REG_X0) +#define ASM_RV32_REG_RA (ASM_RV32_REG_X1) +#define ASM_RV32_REG_SP (ASM_RV32_REG_X2) +#define ASM_RV32_REG_GP (ASM_RV32_REG_X3) +#define ASM_RV32_REG_TP (ASM_RV32_REG_X4) +#define ASM_RV32_REG_T0 (ASM_RV32_REG_X5) +#define ASM_RV32_REG_T1 (ASM_RV32_REG_X6) +#define ASM_RV32_REG_T2 (ASM_RV32_REG_X7) +#define ASM_RV32_REG_A0 (ASM_RV32_REG_X10) +#define ASM_RV32_REG_A1 (ASM_RV32_REG_X11) +#define ASM_RV32_REG_A2 (ASM_RV32_REG_X12) +#define ASM_RV32_REG_A3 (ASM_RV32_REG_X13) +#define ASM_RV32_REG_A4 (ASM_RV32_REG_X14) +#define ASM_RV32_REG_A5 (ASM_RV32_REG_X15) +#define ASM_RV32_REG_A6 (ASM_RV32_REG_X16) +#define ASM_RV32_REG_A7 (ASM_RV32_REG_X17) +#define ASM_RV32_REG_T3 (ASM_RV32_REG_X28) +#define ASM_RV32_REG_T4 (ASM_RV32_REG_X29) +#define ASM_RV32_REG_T5 (ASM_RV32_REG_X30) +#define ASM_RV32_REG_T6 (ASM_RV32_REG_X31) +#define ASM_RV32_REG_FP (ASM_RV32_REG_X8) +#define ASM_RV32_REG_S0 (ASM_RV32_REG_X8) +#define ASM_RV32_REG_S1 (ASM_RV32_REG_X9) +#define ASM_RV32_REG_S2 (ASM_RV32_REG_X18) +#define ASM_RV32_REG_S3 (ASM_RV32_REG_X19) +#define ASM_RV32_REG_S4 (ASM_RV32_REG_X20) +#define ASM_RV32_REG_S5 (ASM_RV32_REG_X21) +#define ASM_RV32_REG_S6 (ASM_RV32_REG_X22) +#define ASM_RV32_REG_S7 (ASM_RV32_REG_X23) +#define ASM_RV32_REG_S8 (ASM_RV32_REG_X24) +#define ASM_RV32_REG_S9 (ASM_RV32_REG_X25) +#define ASM_RV32_REG_S10 (ASM_RV32_REG_X26) +#define ASM_RV32_REG_S11 (ASM_RV32_REG_X27) + +typedef struct _asm_rv32_t { + // Opaque emitter state. + mp_asm_base_t base; + // Which registers are tainted and need saving/restoring. + mp_uint_t saved_registers_mask; + // How many locals must be stored on the stack. + mp_uint_t locals_count; + // The computed function stack size. + mp_uint_t stack_size; + // The stack offset where stack-based locals start to be stored. + mp_uint_t locals_stack_offset; +} asm_rv32_t; + +void asm_rv32_entry(asm_rv32_t *state, mp_uint_t locals); +void asm_rv32_exit(asm_rv32_t *state); +void asm_rv32_end_pass(asm_rv32_t *state); + +//////////////////////////////////////////////////////////////////////////////// + +#define RV32_ENCODE_TYPE_B(op, ft3, rs1, rs2, imm) \ + ((op & 0x7F) | ((ft3 & 0x07) << 12) | ((imm & 0x800) >> 4) | \ + ((imm & 0x1E) << 7) | ((rs1 & 0x1F) << 15) | ((rs2 & 0x1F) << 20) | \ + ((imm & 0x7E0) << 20) | ((imm & 0x1000) << 19)) + +#define RV32_ENCODE_TYPE_I(op, ft3, rd, rs, imm) \ + ((op & 0x7F) | ((rd & 0x1F) << 7) | ((ft3 & 0x07) << 12) | \ + ((rs & 0x1F) << 15) | ((imm & 0xFFF) << 20)) + +#define RV32_ENCODE_TYPE_J(op, rd, imm) \ + ((op & 0x7F) | ((rd & 0x1F) << 7) | (imm & 0xFF000) | \ + ((imm & 0x800) << 9) | ((imm & 0x7FE) << 20) | ((imm & 0x100000) << 11)) + +#define RV32_ENCODE_TYPE_R(op, ft3, ft7, rd, rs1, rs2) \ + ((op & 0x7F) | ((rd & 0x1F) << 7) | ((ft3 & 0x07) << 12) | \ + ((rs1 & 0x1F) << 15) | ((rs2 & 0x1F) << 20) | ((ft7 & 0x7F) << 25)) + +#define RV32_ENCODE_TYPE_S(op, ft3, rs1, rs2, imm) \ + ((op & 0x7F) | ((imm & 0x1F) << 7) | ((ft3 & 0x07) << 12) | \ + ((rs1 & 0x1F) << 15) | ((rs2 & 0x1F) << 20) | ((imm & 0xFE0) << 20)) + +#define RV32_ENCODE_TYPE_U(op, rd, imm) \ + ((op & 0x7F) | ((rd & 0x1F) << 7) | (imm & 0xFFFFF000)) + +#define RV32_ENCODE_TYPE_CB(op, ft3, rs, imm) \ + ((op & 0x03) | ((ft3 & 0x07) << 13) | ((rs & 0x07) << 7) | \ + (((imm) & 0x100) << 4) | (((imm) & 0xC0) >> 1) | (((imm) & 0x20) >> 3) | \ + (((imm) & 0x18) << 7) | (((imm) & 0x06) << 2)) + +#define RV32_ENCODE_TYPE_CI(op, ft3, rd, imm) \ + ((op & 0x03) | ((ft3 & 0x07) << 13) | ((rd & 0x1F) << 7) | \ + (((imm) & 0x20) << 7) | (((imm) & 0x1F) << 2)) + +#define RV32_ENCODE_TYPE_CIW(op, ft3, rd, imm) \ + ((op & 0x03) | ((ft3 & 0x07) << 13) | ((rd & 0x07) << 2) | \ + ((imm & 0x3C0) << 1) | ((imm & 0x30) << 7) | \ + ((imm & 0x08) << 2) | ((imm & 0x04) << 4)) + +#define RV32_ENCODE_TYPE_CJ(op, ft3, imm) \ + ((op & 0x03) | ((ft3 & 0x07) << 13) | ((imm & 0x0E) << 2) | \ + ((imm & 0x300) << 1) | ((imm & 0x800) << 1) | ((imm & 0x400) >> 2) | \ + ((imm & 0x80) >> 1) | ((imm & 0x40) << 1) | ((imm & 0x20) >> 3) | \ + ((imm & 0x10) << 7)) + +#define RV32_ENCODE_TYPE_CL(op, ft3, rd, rs, imm) \ + ((op & 0x03) | ((ft3 & 0x07) << 13) | ((rd & 0x07) << 2) | \ + ((rs & 0x07) << 7) | ((imm & 0x40) >> 1) | ((imm & 0x38) << 7) | \ + ((imm & 0x04) << 4)) + +#define RV32_ENCODE_TYPE_CR(op, ft4, rs1, rs2) \ + ((op & 0x03) | ((rs2 & 0x1F) << 2) | ((rs1 & 0x1F) << 7) | ((ft4 & 0x0F) << 12)) + +#define RV32_ENCODE_TYPE_CSS(op, ft3, rs, imm) \ + ((op & 0x03) | ((ft3 & 0x07) << 13) | ((rs & 0x1F) << 2) | ((imm) & 0x3F) << 7) + +void asm_rv32_emit_word_opcode(asm_rv32_t *state, mp_uint_t opcode); +void asm_rv32_emit_halfword_opcode(asm_rv32_t *state, mp_uint_t opcode); + +// ADD RD, RS1, RS2 +static inline void asm_rv32_opcode_add(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0000000 ..... ..... 000 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x00, 0x00, rd, rs1, rs2)); +} + +// ADDI RD, RS, IMMEDIATE +static inline void asm_rv32_opcode_addi(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t immediate) { + // I: ............ ..... 000 ..... 0010011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x13, 0x00, rd, rs, immediate)); +} + +// AND RD, RS1, RS2 +static inline void asm_rv32_opcode_and(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0000000 ..... ..... 111 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x07, 0x00, rd, rs1, rs2)); +} + +// AUIPC RD, offset +static inline void asm_rv32_opcode_auipc(asm_rv32_t *state, mp_uint_t rd, mp_int_t offset) { + // U: .................... ..... 0010111 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_U(0x17, rd, offset)); +} + +// BEQ RS1, RS2, OFFSET +static inline void asm_rv32_opcode_beq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_int_t offset) { + // B: . ...... ..... ..... 000 .... . 1100011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_B(0x63, 0x00, rs1, rs2, offset)); +} + +// BNE RS1, RS2, OFFSET +static inline void asm_rv32_opcode_bne(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_int_t offset) { + // B: . ...... ..... ..... 001 .... . 1100011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_B(0x63, 0x01, rs1, rs2, offset)); +} + +// C.ADD RD, RS +static inline void asm_rv32_opcode_cadd(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs) { + // CR: 1001 ..... ..... 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CR(0x02, 0x09, rd, rs)); +} + +// C.ADDI RD, IMMEDIATE +static inline void asm_rv32_opcode_caddi(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate) { + // CI: 000 . ..... ..... 01 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CI(0x01, 0x00, rd, immediate)); +} + +// C.ADDI4SPN RD', IMMEDIATE +static inline void asm_rv32_opcode_caddi4spn(asm_rv32_t *state, mp_uint_t rd, mp_uint_t immediate) { + // CIW: 000 ........ ... 00 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CIW(0x00, 0x00, rd, immediate)); +} + +// C.BEQZ RS', IMMEDIATE +static inline void asm_rv32_opcode_cbeqz(asm_rv32_t *state, mp_uint_t rs, mp_int_t offset) { + // CB: 110 ... ... ..... 01 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CB(0x01, 0x06, rs, offset)); +} + +// C.BNEZ RS', IMMEDIATE +static inline void asm_rv32_opcode_cbnez(asm_rv32_t *state, mp_uint_t rs, mp_int_t offset) { + // CB: 111 ... ... ..... 01 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CB(0x01, 0x07, rs, offset)); +} + +// C.J OFFSET +static inline void asm_rv32_opcode_cj(asm_rv32_t *state, mp_int_t offset) { + // CJ: 101 ........... 01 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CJ(0x01, 0x05, offset)); +} + +// C.JALR RS +static inline void asm_rv32_opcode_cjalr(asm_rv32_t *state, mp_uint_t rs) { + // CR: 1001 ..... 00000 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CR(0x02, 0x09, rs, 0)); +} + +// C.JR RS +static inline void asm_rv32_opcode_cjr(asm_rv32_t *state, mp_uint_t rs) { + // CR: 1000 ..... 00000 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CR(0x02, 0x08, rs, 0)); +} + +// C.LI RD, IMMEDIATE +static inline void asm_rv32_opcode_cli(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate) { + // CI: 010 . ..... ..... 01 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CI(0x01, 0x02, rd, immediate)); +} + +// C.LUI RD, IMMEDIATE +static inline void asm_rv32_opcode_clui(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate) { + // CI: 011 . ..... ..... 01 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CI(0x01, 0x03, rd, immediate >> 12)); +} + +// C.LW RD', OFFSET(RS') +static inline void asm_rv32_opcode_clw(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { + // CL: 010 ... ... .. ... 00 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CL(0x00, 0x02, rd, rs, offset)); +} + +// C.LWSP RD, OFFSET +static inline void asm_rv32_opcode_clwsp(asm_rv32_t *state, mp_uint_t rd, mp_uint_t offset) { + // CI: 010 . ..... ..... 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CI(0x02, 0x02, rd, ((offset & 0xC0) >> 6) | (offset & 0x3C))); +} + +// C.MV RD, RS +static inline void asm_rv32_opcode_cmv(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs) { + // CR: 1000 ..... ..... 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CR(0x02, 0x08, rd, rs)); +} + +// C.SWSP RS, OFFSET +static inline void asm_rv32_opcode_cswsp(asm_rv32_t *state, mp_uint_t rs, mp_uint_t offset) { + // CSS: 010 ...... ..... 10 + asm_rv32_emit_halfword_opcode(state, RV32_ENCODE_TYPE_CSS(0x02, 0x06, rs, ((offset & 0xC0) >> 6) | (offset & 0x3C))); +} + +// JALR RD, RS, offset +static inline void asm_rv32_opcode_jalr(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { + // I: ............ ..... 000 ..... 1100111 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x67, 0x00, rd, rs, offset)); +} + +// LBU RD, OFFSET(RS) +static inline void asm_rv32_opcode_lbu(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { + // I: ............ ..... 100 ..... 0000011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x03, 0x04, rd, rs, offset)); +} + +// LHU RD, OFFSET(RS) +static inline void asm_rv32_opcode_lhu(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { + // I: ............ ..... 101 ..... 0000011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x03, 0x05, rd, rs, offset)); +} + +// LUI RD, immediate +static inline void asm_rv32_opcode_lui(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate) { + // U: .................... ..... 0110111 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_U(0x37, rd, immediate)); +} + +// LW RD, OFFSET(RS) +static inline void asm_rv32_opcode_lw(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { + // I: ............ ..... 010 ..... 0000011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x03, 0x02, rd, rs, offset)); +} + +// MUL RD, RS1, RS2 +static inline void asm_rv32_opcode_mul(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0000001 ..... ..... 000 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x00, 0x01, rd, rs1, rs2)); +} + +// OR RD, RS1, RS2 +static inline void asm_rv32_opcode_or(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0000000 ..... ..... 110 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x06, 0x00, rd, rs1, rs2)); +} + +// SLL RD, RS1, RS2 +static inline void asm_rv32_opcode_sll(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0000000 ..... ..... 001 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x01, 0x00, rd, rs1, rs2)); +} + +// SLLI RD, RS, IMMEDIATE +static inline void asm_rv32_opcode_slli(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_uint_t immediate) { + // I: 0000000..... ..... 001 ..... 0010011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x13, 0x01, rd, rs, immediate & 0x1F)); +} + +// SRL RD, RS1, RS2 +static inline void asm_rv32_opcode_srl(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0000000 ..... ..... 101 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x05, 0x00, rd, rs1, rs2)); +} + +// SLT RD, RS1, RS2 +static inline void asm_rv32_opcode_slt(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0000000 ..... ..... 010 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x02, 0x00, rd, rs1, rs2)); +} + +// SLTU RD, RS1, RS2 +static inline void asm_rv32_opcode_sltu(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0000000 ..... ..... 011 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x03, 0x00, rd, rs1, rs2)); +} + +// SRA RD, RS1, RS2 +static inline void asm_rv32_opcode_sra(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0100000 ..... ..... 101 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x05, 0x20, rd, rs1, rs2)); +} + +// SUB RD, RS1, RS2 +static inline void asm_rv32_opcode_sub(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0100000 ..... ..... 000 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x00, 0x20, rd, rs1, rs2)); +} + +// SB RS2, OFFSET(RS1) +static inline void asm_rv32_opcode_sb(asm_rv32_t *state, mp_uint_t rs2, mp_uint_t rs1, mp_int_t offset) { + // S: ....... ..... ..... 000 ..... 0100011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_S(0x23, 0x00, rs1, rs2, offset)); +} + +// SH RS2, OFFSET(RS1) +static inline void asm_rv32_opcode_sh(asm_rv32_t *state, mp_uint_t rs2, mp_uint_t rs1, mp_int_t offset) { + // S: ....... ..... ..... 001 ..... 0100011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_S(0x23, 0x01, rs1, rs2, offset)); +} + +// SW RS2, OFFSET(RS1) +static inline void asm_rv32_opcode_sw(asm_rv32_t *state, mp_uint_t rs2, mp_uint_t rs1, mp_int_t offset) { + // S: ....... ..... ..... 010 ..... 0100011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_S(0x23, 0x02, rs1, rs2, offset)); +} + +// XOR RD, RS1, RS2 +static inline void asm_rv32_opcode_xor(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0000000 ..... ..... 100 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x04, 0x00, rd, rs1, rs2)); +} + +// XORI RD, RS, IMMEDIATE +static inline void asm_rv32_opcode_xori(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t immediate) { + // I: ............ ..... 100 ..... 0010011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x13, 0x04, rd, rs, immediate)); +} + +#define ASM_WORD_SIZE (4) +#define ASM_HALFWORD_SIZE (2) + +#define REG_RET ASM_RV32_REG_A0 +#define REG_ARG_1 ASM_RV32_REG_A0 +#define REG_ARG_2 ASM_RV32_REG_A1 +#define REG_ARG_3 ASM_RV32_REG_A2 +#define REG_ARG_4 ASM_RV32_REG_A3 +#define REG_TEMP0 ASM_RV32_REG_T1 +#define REG_TEMP1 ASM_RV32_REG_T2 +#define REG_TEMP2 ASM_RV32_REG_T3 +#define REG_FUN_TABLE ASM_RV32_REG_S1 +#define REG_LOCAL_1 ASM_RV32_REG_S3 +#define REG_LOCAL_2 ASM_RV32_REG_S4 +#define REG_LOCAL_3 ASM_RV32_REG_S5 + +void asm_rv32_meta_comparison_eq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd); +void asm_rv32_meta_comparison_ne(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd); +void asm_rv32_meta_comparison_lt(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd, bool unsigned_comparison); +void asm_rv32_meta_comparison_le(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd, bool unsigned_comparison); + +#ifdef GENERIC_ASM_API + +void asm_rv32_emit_call_ind(asm_rv32_t *state, mp_uint_t index); +void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label); +void asm_rv32_emit_jump_if_reg_eq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t label); +void asm_rv32_emit_jump_if_reg_nonzero(asm_rv32_t *state, mp_uint_t rs, mp_uint_t label); +void asm_rv32_emit_load16_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset); +void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset); +void asm_rv32_emit_mov_local_reg(asm_rv32_t *state, mp_uint_t local, mp_uint_t rs); +void asm_rv32_emit_mov_reg_local(asm_rv32_t *state, mp_uint_t rd, mp_uint_t local); +void asm_rv32_emit_mov_reg_local_addr(asm_rv32_t *state, mp_uint_t rd, mp_uint_t local); +void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t label); +void asm_rv32_emit_optimised_load_immediate(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate); +void asm_rv32_emit_optimised_xor(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs); +void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_uint_t base, mp_int_t offset); + +#define ASM_T asm_rv32_t +#define ASM_ENTRY(state, labels) asm_rv32_entry(state, labels) +#define ASM_EXIT(state) asm_rv32_exit(state) +#define ASM_END_PASS(state) asm_rv32_end_pass(state) + +#define ASM_ADD_REG_REG(state, rd, rs) asm_rv32_opcode_cadd(state, rd, rs) +#define ASM_AND_REG_REG(state, rd, rs) asm_rv32_opcode_and(state, rd, rs, rd) +#define ASM_ASR_REG_REG(state, rd, rs) asm_rv32_opcode_sra(state, rd, rd, rs) +#define ASM_CALL_IND(state, index) asm_rv32_emit_call_ind(state, index) +#define ASM_JUMP(state, label) asm_rv32_emit_jump(state, label) +#define ASM_JUMP_IF_REG_EQ(state, rs1, rs2, label) asm_rv32_emit_jump_if_reg_eq(state, rs1, rs2, label) +#define ASM_JUMP_IF_REG_NONZERO(state, rs, label, bool_test) asm_rv32_emit_jump_if_reg_nonzero(state, rs, label) +#define ASM_JUMP_IF_REG_ZERO(state, rs, label, bool_test) asm_rv32_emit_jump_if_reg_eq(state, rs, ASM_RV32_REG_ZERO, label) +#define ASM_JUMP_REG(state, rs) asm_rv32_opcode_cjr(state, rs) +#define ASM_LOAD16_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load16_reg_reg_offset(state, rd, rs, offset) +#define ASM_LOAD16_REG_REG(state, rd, rs) asm_rv32_opcode_lhu(state, rd, rs, 0) +#define ASM_LOAD32_REG_REG(state, rd, rs) ASM_LOAD_REG_REG_OFFSET(state, rd, rs, 0) +#define ASM_LOAD8_REG_REG(state, rd, rs) asm_rv32_opcode_lbu(state, rd, rs, 0) +#define ASM_LOAD_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset) +#define ASM_LOAD_REG_REG(state, rd, rs) ASM_LOAD32_REG_REG(state, rd, rs) +#define ASM_LSL_REG_REG(state, rd, rs) asm_rv32_opcode_sll(state, rd, rd, rs) +#define ASM_LSR_REG_REG(state, rd, rs) asm_rv32_opcode_srl(state, rd, rd, rs) +#define ASM_MOV_LOCAL_REG(state, local, rs) asm_rv32_emit_mov_local_reg(state, local, rs) +#define ASM_MOV_REG_IMM(state, rd, imm) asm_rv32_emit_optimised_load_immediate(state, rd, imm) +#define ASM_MOV_REG_LOCAL_ADDR(state, rd, local) asm_rv32_emit_mov_reg_local_addr(state, rd, local) +#define ASM_MOV_REG_LOCAL(state, rd, local) asm_rv32_emit_mov_reg_local(state, rd, local) +#define ASM_MOV_REG_PCREL(state, rd, label) asm_rv32_emit_mov_reg_pcrel(state, rd, label) +#define ASM_MOV_REG_REG(state, rd, rs) asm_rv32_opcode_cmv(state, rd, rs) +#define ASM_MUL_REG_REG(state, rd, rs) asm_rv32_opcode_mul(state, rd, rd, rs) +#define ASM_NEG_REG(state, rd) asm_rv32_opcode_sub(state, rd, ASM_RV32_REG_ZERO, rd) +#define ASM_NOT_REG(state, rd) asm_rv32_opcode_xori(state, rd, rd, -1) +#define ASM_OR_REG_REG(state, rd, rs) asm_rv32_opcode_or(state, rd, rd, rs) +#define ASM_STORE16_REG_REG(state, rs1, rs2) asm_rv32_opcode_sh(state, rs1, rs2, 0) +#define ASM_STORE32_REG_REG(state, rs1, rs2) ASM_STORE_REG_REG_OFFSET(state, rs1, rs2, 0) +#define ASM_STORE8_REG_REG(state, rs1, rs2) asm_rv32_opcode_sb(state, rs1, rs2, 0) +#define ASM_STORE_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset) +#define ASM_STORE_REG_REG(state, rs1, rs2) ASM_STORE32_REG_REG(state, rs1, rs2) +#define ASM_SUB_REG_REG(state, rd, rs) asm_rv32_opcode_sub(state, rd, rd, rs) +#define ASM_XOR_REG_REG(state, rd, rs) asm_rv32_emit_optimised_xor(state, rd, rs) + +#endif + +#endif // MICROPY_INCLUDED_PY_ASMRV32_H diff --git a/py/asmthumb.c b/py/asmthumb.c index 0df79e5fd6203..420815e80269a 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -35,23 +35,7 @@ #include "py/mpstate.h" #include "py/asmthumb.h" - -#ifdef _MSC_VER -#include - -static uint32_t mp_clz(uint32_t x) { - unsigned long lz = 0; - return _BitScanReverse(&lz, x) ? (sizeof(x) * 8 - 1) - lz : 0; -} - -static uint32_t mp_ctz(uint32_t x) { - unsigned long tz = 0; - return _BitScanForward(&tz, x) ? tz : 0; -} -#else -#define mp_clz(x) __builtin_clz(x) -#define mp_ctz(x) __builtin_ctz(x) -#endif +#include "py/misc.h" #define UNSIGNED_FIT5(x) ((uint32_t)(x) < 32) #define UNSIGNED_FIT7(x) ((uint32_t)(x) < 128) diff --git a/py/binary.c b/py/binary.c index 2167d38023eb6..728f29815cd78 100644 --- a/py/binary.c +++ b/py/binary.c @@ -358,7 +358,7 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte * #if MICROPY_NONSTANDARD_TYPECODES } else if (val_type == 'S') { const char *s_val = (const char *)(uintptr_t)(mp_uint_t)val; - return mp_obj_new_str(s_val, strlen(s_val)); + return mp_obj_new_str_from_cstr(s_val); #endif #if MICROPY_PY_BUILTINS_FLOAT } else if (val_type == 'e') { diff --git a/py/builtin.h b/py/builtin.h index 81d0789802b9c..6efe3e8facabd 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -126,6 +126,8 @@ MP_DECLARE_CONST_FUN_OBJ_2(mp_op_getitem_obj); MP_DECLARE_CONST_FUN_OBJ_3(mp_op_setitem_obj); MP_DECLARE_CONST_FUN_OBJ_2(mp_op_delitem_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_sys_exit_obj); + // Modules needed by the runtime. extern const mp_obj_dict_t mp_module_builtins_globals; extern const mp_obj_module_t mp_module___main__; diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index f73d52a6c4b12..d6569bc39bd8e 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -201,6 +201,9 @@ endif ifeq ($(CIRCUITPY_DISPLAYIO),1) SRC_PATTERNS += displayio/% endif +ifeq ($(CIRCUITPY_DUALBANK),1) +SRC_PATTERNS += dualbank/% +endif ifeq ($(CIRCUITPY__EVE),1) SRC_PATTERNS += _eve/% endif @@ -279,6 +282,9 @@ endif ifeq ($(CIRCUITPY_MAX3421E),1) SRC_PATTERNS += max3421e/% endif +ifeq ($(CIRCUITPY_MDNS),1) +SRC_PATTERNS += mdns/% +endif ifeq ($(CIRCUITPY_MEMORYMAP),1) SRC_PATTERNS += memorymap/% endif @@ -288,9 +294,6 @@ endif ifeq ($(CIRCUITPY_MICROCONTROLLER),1) SRC_PATTERNS += microcontroller/% endif -ifeq ($(CIRCUITPY_MDNS),1) -SRC_PATTERNS += mdns/% -endif ifeq ($(CIRCUITPY_MSGPACK),1) SRC_PATTERNS += msgpack/% endif @@ -306,9 +309,6 @@ endif ifeq ($(CIRCUITPY_OS),1) SRC_PATTERNS += os/% endif -ifeq ($(CIRCUITPY_DUALBANK),1) -SRC_PATTERNS += dualbank/% -endif ifeq ($(CIRCUITPY_PARALLELDISPLAYBUS),1) SRC_PATTERNS += paralleldisplaybus/% endif @@ -342,6 +342,9 @@ endif ifeq ($(CIRCUITPY_RANDOM),1) SRC_PATTERNS += random/% endif +ifeq ($(CIRCUITPY_RCLCPY),1) +SRC_PATTERNS += rclcpy/% +endif ifeq ($(CIRCUITPY_RGBMATRIX),1) SRC_PATTERNS += rgbmatrix/% endif @@ -540,6 +543,9 @@ SRC_COMMON_HAL_ALL = \ pulseio/__init__.c \ pwmio/PWMOut.c \ pwmio/__init__.c \ + rclcpy/__init__.c \ + rclcpy/Node.c \ + rclcpy/Publisher.c \ rgbmatrix/RGBMatrix.c \ rgbmatrix/__init__.c \ rotaryio/IncrementalEncoder.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index d6658867b7d1d..bc894e98606eb 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -639,7 +639,7 @@ void background_callback_run_all(void); #define MICROPY_PY_BUILTINS_COMPILE (1) #ifndef CIRCUITPY_MIN_GCC_VERSION -#define CIRCUITPY_MIN_GCC_VERSION 13 +#define CIRCUITPY_MIN_GCC_VERSION 14 #endif #ifndef CIRCUITPY_SAVES_PARTITION_SIZE diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index b081e0f52dbde..2009c4e177da6 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -379,6 +379,9 @@ CFLAGS += -DCIRCUITPY_MATH=$(CIRCUITPY_MATH) CIRCUITPY_MAX3421E ?= 0 CFLAGS += -DCIRCUITPY_MAX3421E=$(CIRCUITPY_MAX3421E) +CIRCUITPY_MDNS ?= $(CIRCUITPY_WIFI) +CFLAGS += -DCIRCUITPY_MDNS=$(CIRCUITPY_MDNS) + CIRCUITPY_MEMORYMAP ?= 0 CFLAGS += -DCIRCUITPY_MEMORYMAP=$(CIRCUITPY_MEMORYMAP) @@ -388,9 +391,6 @@ CFLAGS += -DCIRCUITPY_MEMORYMONITOR=$(CIRCUITPY_MEMORYMONITOR) CIRCUITPY_MICROCONTROLLER ?= 1 CFLAGS += -DCIRCUITPY_MICROCONTROLLER=$(CIRCUITPY_MICROCONTROLLER) -CIRCUITPY_MDNS ?= $(CIRCUITPY_WIFI) -CFLAGS += -DCIRCUITPY_MDNS=$(CIRCUITPY_MDNS) - CIRCUITPY_MSGPACK ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_MSGPACK=$(CIRCUITPY_MSGPACK) @@ -454,6 +454,9 @@ CFLAGS += -DCIRCUITPY_RAINBOWIO=$(CIRCUITPY_RAINBOWIO) CIRCUITPY_RANDOM ?= 1 CFLAGS += -DCIRCUITPY_RANDOM=$(CIRCUITPY_RANDOM) +CIRCUITPY_RCLCPY ?= 0 +CFLAGS += -DCIRCUITPY_RCLCPY=$(CIRCUITPY_RCLCPY) + CIRCUITPY_RE ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_RE=$(CIRCUITPY_RE) @@ -719,7 +722,7 @@ CIRCUITPY_SWO_TRACE ?= 0 CFLAGS += -DCIRCUITPY_SWO_TRACE=$(CIRCUITPY_SWO_TRACE) # Check for a minimum GCC version during build (set to 0 to disable) -CIRCUITPY_MIN_GCC_VERSION ?= 13 +CIRCUITPY_MIN_GCC_VERSION ?= 14 CFLAGS += -DCIRCUITPY_MIN_GCC_VERSION=$(CIRCUITPY_MIN_GCC_VERSION) # Define an equivalent for MICROPY_LONGINT_IMPL, to pass to $(MPY-TOOL) in py/mkrules.mk diff --git a/py/compile.c b/py/compile.c index 085c342605d46..01904155d67c0 100644 --- a/py/compile.c +++ b/py/compile.c @@ -102,6 +102,8 @@ static const emit_method_table_t *emit_native_table[] = { &emit_native_thumb_method_table, &emit_native_xtensa_method_table, &emit_native_xtensawin_method_table, + &emit_native_rv32_method_table, + &emit_native_debug_method_table, }; #elif MICROPY_EMIT_NATIVE @@ -118,6 +120,10 @@ static const emit_method_table_t *emit_native_table[] = { #define NATIVE_EMITTER(f) emit_native_xtensa_##f #elif MICROPY_EMIT_XTENSAWIN #define NATIVE_EMITTER(f) emit_native_xtensawin_##f +#elif MICROPY_EMIT_RV32 +#define NATIVE_EMITTER(f) emit_native_rv32_##f +#elif MICROPY_EMIT_NATIVE_DEBUG +#define NATIVE_EMITTER(f) emit_native_debug_##f #else #error "unknown native emitter" #endif @@ -1894,19 +1900,7 @@ static void compile_async_with_stmt_helper(compiler_t *comp, size_t n, mp_parse_ // Handle case 1: call __aexit__ // Stack: (..., ctx_mgr) - EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // to tell end_finally there's no exception - EMIT(rot_two); - EMIT_ARG(jump, l_aexit_no_exc); // jump to code below to call __aexit__ - - // Start of "finally" block - // At this point we have case 2 or 3, we detect which one by the TOS being an exception or not - EMIT_ARG(label_assign, l_finally_block); - - // Detect if TOS an exception or not - EMIT(dup_top); - EMIT_LOAD_GLOBAL(MP_QSTR_BaseException); - EMIT_ARG(binary_op, MP_BINARY_OP_EXCEPTION_MATCH); - EMIT_ARG(pop_jump_if, false, l_ret_unwind_jump); // if not an exception then we have case 3 + EMIT_ARG(async_with_setup_finally, l_aexit_no_exc, l_finally_block, l_ret_unwind_jump); // Handle case 2: call __aexit__ and either swallow or re-raise the exception // Stack: (..., ctx_mgr, exc) @@ -1932,6 +1926,7 @@ static void compile_async_with_stmt_helper(compiler_t *comp, size_t n, mp_parse_ EMIT_ARG(pop_jump_if, false, l_end); EMIT(pop_top); // pop exception EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); // replace with None to swallow exception + // Stack: (..., None) EMIT_ARG(jump, l_end); EMIT_ARG(adjust_stack_size, 2); @@ -1941,6 +1936,8 @@ static void compile_async_with_stmt_helper(compiler_t *comp, size_t n, mp_parse_ EMIT(rot_three); EMIT(rot_three); EMIT_ARG(label_assign, l_aexit_no_exc); + // We arrive here from either case 1 (a jump) or case 3 (fall through) + // Stack: case 1: (..., None, ctx_mgr) or case 3: (..., X, INT, ctx_mgr) EMIT_ARG(load_method, MP_QSTR___aexit__, false); EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE); EMIT(dup_top); @@ -1948,6 +1945,7 @@ static void compile_async_with_stmt_helper(compiler_t *comp, size_t n, mp_parse_ EMIT_ARG(call_method, 3, 0, 0); compile_yield_from(comp); EMIT(pop_top); + // Stack: case 1: (..., None) or case 3: (..., X, INT) EMIT_ARG(adjust_stack_size, -1); // End of "finally" block diff --git a/py/cstack.c b/py/cstack.c new file mode 100644 index 0000000000000..fe4b16d652a50 --- /dev/null +++ b/py/cstack.c @@ -0,0 +1,57 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * Copryight (c) 2024 Angus Gratton + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/cstack.h" + +void mp_cstack_init_with_sp_here(size_t stack_size) { + #if __GNUC__ >= 13 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdangling-pointer" + #endif + volatile int stack_dummy; + mp_cstack_init_with_top((void *)&stack_dummy, stack_size); + #if __GNUC__ >= 13 + #pragma GCC diagnostic pop + #endif +} + +mp_uint_t mp_cstack_usage(void) { + // Assumes descending stack + volatile int stack_dummy; + return MP_STATE_THREAD(stack_top) - (char *)&stack_dummy; +} + +#if MICROPY_STACK_CHECK + +void mp_cstack_check(void) { + if (mp_cstack_usage() >= MP_STATE_THREAD(stack_limit)) { + mp_raise_recursion_depth(); + } +} + +#endif // MICROPY_STACK_CHECK diff --git a/py/cstack.h b/py/cstack.h new file mode 100644 index 0000000000000..b12a18e13fcad --- /dev/null +++ b/py/cstack.h @@ -0,0 +1,63 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Paul Sokolovsky + * Copyright (c) 2024 Angus Gratton + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_CSTACK_H +#define MICROPY_INCLUDED_PY_CSTACK_H + +#include "py/mpstate.h" + +// Both init functions below accept the full stack size. Set the +// MICROPY_STACK_CHECK_MARGIN to the number of bytes subtracted to account +// for stack usage between checks. + +void mp_cstack_init_with_sp_here(size_t stack_size); + +inline static void mp_cstack_init_with_top(void *top, size_t stack_size) { + MP_STATE_THREAD(stack_top) = (char *)top; + + #if MICROPY_STACK_CHECK + assert(stack_size > MICROPY_STACK_CHECK_MARGIN); // Should be enforced by port + MP_STATE_THREAD(stack_limit) = stack_size - MICROPY_STACK_CHECK_MARGIN; + #else + (void)stack_size; + #endif +} + +mp_uint_t mp_cstack_usage(void); + +#if MICROPY_STACK_CHECK + +void mp_cstack_check(void); + +#else + +inline static void mp_cstack_check(void) { + // No-op when stack checking is disabled +} + +#endif + +#endif // MICROPY_INCLUDED_PY_CSTACK_H diff --git a/py/emit.h b/py/emit.h index 26f978ba598ab..623b163490164 100644 --- a/py/emit.h +++ b/py/emit.h @@ -144,6 +144,9 @@ typedef struct _emit_method_table_t { void (*unwind_jump)(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); void (*setup_block)(emit_t *emit, mp_uint_t label, int kind); void (*with_cleanup)(emit_t *emit, mp_uint_t label); + #if MICROPY_PY_ASYNC_AWAIT + void (*async_with_setup_finally)(emit_t *emit, mp_uint_t label_aexit_no_exc, mp_uint_t label_finally_block, mp_uint_t label_ret_unwind_jump); + #endif void (*end_finally)(emit_t *emit); void (*get_iter)(emit_t *emit, bool use_stack); void (*for_iter)(emit_t *emit, mp_uint_t label); @@ -201,6 +204,8 @@ extern const emit_method_table_t emit_native_thumb_method_table; extern const emit_method_table_t emit_native_arm_method_table; extern const emit_method_table_t emit_native_xtensa_method_table; extern const emit_method_table_t emit_native_xtensawin_method_table; +extern const emit_method_table_t emit_native_rv32_method_table; +extern const emit_method_table_t emit_native_debug_method_table; extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops; extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops; @@ -213,6 +218,8 @@ emit_t *emit_native_thumb_new(mp_emit_common_t *emit_common, mp_obj_t *error_slo emit_t *emit_native_arm_new(mp_emit_common_t *emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); emit_t *emit_native_xtensa_new(mp_emit_common_t *emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); emit_t *emit_native_xtensawin_new(mp_emit_common_t *emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); +emit_t *emit_native_rv32_new(mp_emit_common_t *emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); +emit_t *emit_native_debug_new(mp_emit_common_t *emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels); void emit_bc_set_max_num_labels(emit_t *emit, mp_uint_t max_num_labels); @@ -223,6 +230,8 @@ void emit_native_thumb_free(emit_t *emit); void emit_native_arm_free(emit_t *emit); void emit_native_xtensa_free(emit_t *emit); void emit_native_xtensawin_free(emit_t *emit); +void emit_native_rv32_free(emit_t *emit); +void emit_native_debug_free(emit_t *emit); void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope); bool mp_emit_bc_end_pass(emit_t *emit); @@ -258,6 +267,9 @@ void mp_emit_bc_jump_if_or_pop(emit_t *emit, bool cond, mp_uint_t label); void mp_emit_bc_unwind_jump(emit_t *emit, mp_uint_t label, mp_uint_t except_depth); void mp_emit_bc_setup_block(emit_t *emit, mp_uint_t label, int kind); void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label); +#if MICROPY_PY_ASYNC_AWAIT +void mp_emit_bc_async_with_setup_finally(emit_t *emit, mp_uint_t label_aexit_no_exc, mp_uint_t label_finally_block, mp_uint_t label_ret_unwind_jump); +#endif void mp_emit_bc_end_finally(emit_t *emit); void mp_emit_bc_get_iter(emit_t *emit, bool use_stack); void mp_emit_bc_for_iter(emit_t *emit, mp_uint_t label); diff --git a/py/emitbc.c b/py/emitbc.c index f23f9e07d8410..0bcac8a167627 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -668,6 +668,27 @@ void mp_emit_bc_with_cleanup(emit_t *emit, mp_uint_t label) { mp_emit_bc_adjust_stack_size(emit, -4); } +#if MICROPY_PY_ASYNC_AWAIT +void mp_emit_bc_async_with_setup_finally(emit_t *emit, mp_uint_t label_aexit_no_exc, mp_uint_t label_finally_block, mp_uint_t label_ret_unwind_jump) { + // The async-with body has executed and no exception was raised, the execution fell through to this point. + // Stack: (..., ctx_mgr) + + // Finish async-with body and prepare to enter "finally" block. + mp_emit_bc_load_const_tok(emit, MP_TOKEN_KW_NONE); // to tell end_finally there's no exception + mp_emit_bc_rot_two(emit); + mp_emit_bc_jump(emit, label_aexit_no_exc); // jump to code to call __aexit__ + + // Start of "finally" block which is entered via one of: an exception propagating out, a return, an unwind jump. + mp_emit_bc_label_assign(emit, label_finally_block); + + // Detect which case we have by the TOS being an exception or not. + mp_emit_bc_dup_top(emit); + mp_emit_bc_load_global(emit, MP_QSTR_BaseException, MP_EMIT_IDOP_GLOBAL_GLOBAL); + mp_emit_bc_binary_op(emit, MP_BINARY_OP_EXCEPTION_MATCH); + mp_emit_bc_pop_jump_if(emit, false, label_ret_unwind_jump); // if not an exception then we have return or unwind jump. +} +#endif + void mp_emit_bc_end_finally(emit_t *emit) { emit_write_bytecode_byte(emit, -1, MP_BC_END_FINALLY); } @@ -775,10 +796,10 @@ static void emit_bc_call_function_method_helper(emit_t *emit, int stack_adj, mp_ // each positional arg is one object, each kwarg is two objects, the key // and the value and one extra object for the star args bitmap. stack_adj -= (int)n_positional + 2 * (int)n_keyword + 1; - emit_write_bytecode_byte_uint(emit, stack_adj, bytecode_base + 1, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? + emit_write_bytecode_byte_uint(emit, stack_adj, bytecode_base + 1, (n_keyword << 8) | n_positional); } else { stack_adj -= (int)n_positional + 2 * (int)n_keyword; - emit_write_bytecode_byte_uint(emit, stack_adj, bytecode_base, (n_keyword << 8) | n_positional); // TODO make it 2 separate uints? + emit_write_bytecode_byte_uint(emit, stack_adj, bytecode_base, (n_keyword << 8) | n_positional); } } @@ -864,6 +885,9 @@ const emit_method_table_t emit_bc_method_table = { mp_emit_bc_unwind_jump, mp_emit_bc_setup_block, mp_emit_bc_with_cleanup, + #if MICROPY_PY_ASYNC_AWAIT + mp_emit_bc_async_with_setup_finally, + #endif mp_emit_bc_end_finally, mp_emit_bc_get_iter, mp_emit_bc_for_iter, diff --git a/py/emitglue.c b/py/emitglue.c index 8ab624ee7cf38..e5d9465ed7c11 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -168,7 +168,7 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, cons } DEBUG_printf("\n"); - #ifdef WRITE_CODE + #if WRITE_CODE FILE *fp_write_code = fopen("out-code", "wb"); fwrite(fun_data, fun_len, 1, fp_write_code); fclose(fp_write_code); diff --git a/py/emitnative.c b/py/emitnative.c index 4789d3f5781f6..6b589b54731aa 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -60,28 +60,40 @@ #endif // CIRCUITPY-CHANGE: force definitions -#ifndef N_X64 -#define N_X64 (0) +#ifndef N_ARM +#define N_ARM (0) #endif -#ifndef N_X86 -#define N_X86 (0) +#ifndef N_DEBUG +#define N_DEBUG (0) +#endif + +#ifndef N_NLR_SETJMP +#define N_NLR_SETJMP (0) +#endif + +#ifndef N_RV32 +#define N_RV32 (0) #endif #ifndef N_THUMB #define N_THUMB (0) #endif -#ifndef N_ARM -#define N_ARM (0) +#ifndef N_X64 +#define N_X64 (0) +#endif + +#ifndef N_X86 +#define N_X86 (0) #endif #ifndef N_XTENSA #define N_XTENSA (0) #endif -#ifndef N_NLR_SETJMP -#define N_NLR_SETJMP (0) +#ifndef N_XTENSAWIN +#define N_XTENSWIN (0) #endif #ifndef N_PRELUDE_AS_BYTES_OBJ @@ -89,7 +101,7 @@ #endif // wrapper around everything in this file -#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA || N_XTENSAWIN +#if N_X64 || N_X86 || N_THUMB || N_ARM || N_XTENSA || N_XTENSAWIN || N_RV32 || N_DEBUG // C stack layout for native functions: // 0: nlr_buf_t [optional] @@ -159,6 +171,7 @@ // Whether a slot is needed to store LOCAL_IDX_EXC_HANDLER_UNWIND #define NEED_EXC_HANDLER_UNWIND(emit) ((emit)->scope->exc_stack_size > 0) +#define NEED_THROW_VAL(emit) ((emit)->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) // Whether registers can be used to store locals (only true if there are no // exception handlers, because otherwise an nlr_jump will restore registers to @@ -169,6 +182,7 @@ #define LOCAL_IDX_EXC_VAL(emit) (NLR_BUF_IDX_RET_VAL) #define LOCAL_IDX_EXC_HANDLER_PC(emit) (NLR_BUF_IDX_LOCAL_1) #define LOCAL_IDX_EXC_HANDLER_UNWIND(emit) (SIZEOF_NLR_BUF + 1) // this needs a dedicated variable outside nlr_buf_t +#define LOCAL_IDX_THROW_VAL(emit) (SIZEOF_NLR_BUF + 2) // needs a dedicated variable outside nlr_buf_t, following inject_exc in py/vm.c #define LOCAL_IDX_RET_VAL(emit) (SIZEOF_NLR_BUF) // needed when NEED_GLOBAL_EXC_HANDLER is true #define LOCAL_IDX_FUN_OBJ(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_FUN_BC) #define LOCAL_IDX_OLD_GLOBALS(emit) ((emit)->code_state_start + OFFSETOF_CODE_STATE_IP) @@ -208,6 +222,12 @@ static const uint8_t reg_local_table[MAX_REGS_FOR_LOCAL_VARS] = {REG_LOCAL_1, RE *emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \ } while (0) +#if N_RV32 +#define FIT_SIGNED(value, bits) \ + ((((value) & ~((1U << ((bits) - 1)) - 1)) == 0) || \ + (((value) & ~((1U << ((bits) - 1)) - 1)) == ~((1U << ((bits) - 1)) - 1))) +#endif + typedef enum { STACK_VALUE, STACK_REG, @@ -372,11 +392,14 @@ static void emit_native_mov_reg_state_addr(emit_t *emit, int reg_dest, int local static void emit_native_mov_reg_qstr(emit_t *emit, int arg_reg, qstr qst) { #if MICROPY_PERSISTENT_CODE_SAVE ASM_LOAD16_REG_REG_OFFSET(emit->as, arg_reg, REG_QSTR_TABLE, mp_emit_common_use_qstr(emit->emit_common, qst)); + #elif defined(ASM_MOV_REG_QSTR) + ASM_MOV_REG_QSTR(emit->as, arg_reg, qst); #else ASM_MOV_REG_IMM(emit->as, arg_reg, qst); #endif } +// This function may clobber REG_TEMP0 (and `reg_dest` can be REG_TEMP0). static void emit_native_mov_reg_qstr_obj(emit_t *emit, int reg_dest, qstr qst) { #if MICROPY_PERSISTENT_CODE_SAVE emit_load_reg_with_object(emit, reg_dest, MP_OBJ_NEW_QSTR(qst)); @@ -448,7 +471,9 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop if (NEED_GLOBAL_EXC_HANDLER(emit)) { emit->code_state_start = SIZEOF_NLR_BUF; // for nlr_buf_t emit->code_state_start += 1; // for return_value - if (NEED_EXC_HANDLER_UNWIND(emit)) { + if (NEED_THROW_VAL(emit)) { + emit->code_state_start += 2; + } else if (NEED_EXC_HANDLER_UNWIND(emit)) { emit->code_state_start += 1; } } @@ -567,11 +592,11 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop ASM_MOV_REG_REG(emit->as, REG_GENERATOR_STATE, REG_PARENT_ARG_1); #endif - // Put throw value into LOCAL_IDX_EXC_VAL slot, for yield/yield-from + // Put throw value into LOCAL_IDX_THROW_VAL slot, for yield/yield-from #if N_X86 asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2); #endif - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_PARENT_ARG_2); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_PARENT_ARG_2); // Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, LOCAL_IDX_FUN_OBJ(emit)); @@ -1135,6 +1160,7 @@ static exc_stack_entry_t *emit_native_pop_exc_stack(emit_t *emit) { return e; } +// This function will clobber REG_TEMP0 (and `reg` can be REG_TEMP0). static void emit_load_reg_with_object(emit_t *emit, int reg, mp_obj_t obj) { emit->scope->scope_flags |= MP_SCOPE_FLAG_HASCONSTS; size_t table_off = mp_emit_common_use_const_obj(emit->emit_common, obj); @@ -1163,7 +1189,7 @@ static void emit_native_label_assign(emit_t *emit, mp_uint_t l) { if (is_finally) { // Label is at start of finally handler: store TOS into exception slot vtype_kind_t vtype; - emit_pre_pop_reg(emit, &vtype, REG_TEMP0); + emit_access_stack(emit, 1, &vtype, REG_TEMP0); ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); } @@ -1219,6 +1245,10 @@ static void emit_native_global_exc_entry(emit_t *emit) { ASM_XOR_REG_REG(emit->as, REG_TEMP0, REG_TEMP0); ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_HANDLER_UNWIND(emit), REG_TEMP0); + // clear nlr.ret_val, because it's passed to mp_native_raise regardless + // of whether there was an exception or not + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); + // Put PC of start code block into REG_LOCAL_1 ASM_MOV_REG_PCREL(emit->as, REG_LOCAL_1, start_label); @@ -1274,8 +1304,10 @@ static void emit_native_global_exc_entry(emit_t *emit) { // This is the first entry of the generator - // Check LOCAL_IDX_EXC_VAL for any injected value - ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); + // Check LOCAL_IDX_THROW_VAL for any injected value + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_THROW_VAL(emit)); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2); emit_call(emit, MP_F_NATIVE_RAISE); } } @@ -1403,9 +1435,9 @@ static void emit_native_load_const_str(emit_t *emit, qstr qst) { static void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj) { emit_native_pre(emit); - need_reg_single(emit, REG_RET, 0); - emit_load_reg_with_object(emit, REG_RET, obj); - emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET); + need_reg_single(emit, REG_TEMP0, 0); + emit_load_reg_with_object(emit, REG_TEMP0, obj); + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_TEMP0); } static void emit_native_load_null(emit_t *emit) { @@ -1483,6 +1515,7 @@ static void emit_native_load_attr(emit_t *emit, qstr qst) { } static void emit_native_load_method(emit_t *emit, qstr qst, bool is_super) { + DEBUG_printf("load_method(%s, %d)\n", qstr_str(qst), is_super); if (is_super) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_2, 3); // arg2 = dest ptr emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_2, 2); // arg2 = dest ptr @@ -1549,6 +1582,11 @@ static void emit_native_load_subscr(emit_t *emit) { asm_thumb_ldrb_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); break; } + #elif N_RV32 + if (FIT_SIGNED(index_value, 12)) { + asm_rv32_opcode_lbu(emit->as, REG_RET, reg_base, index_value); + break; + } #endif need_reg_single(emit, reg_index, 0); ASM_MOV_REG_IMM(emit->as, reg_index, index_value); @@ -1567,6 +1605,11 @@ static void emit_native_load_subscr(emit_t *emit) { asm_thumb_ldrh_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); break; } + #elif N_RV32 + if (FIT_SIGNED(index_value, 11)) { + asm_rv32_opcode_lhu(emit->as, REG_RET, reg_base, index_value << 1); + break; + } #endif need_reg_single(emit, reg_index, 0); ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); @@ -1585,6 +1628,11 @@ static void emit_native_load_subscr(emit_t *emit) { asm_thumb_ldr_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); break; } + #elif N_RV32 + if (FIT_SIGNED(index_value, 10)) { + asm_rv32_opcode_lw(emit->as, REG_RET, reg_base, index_value << 2); + break; + } #endif need_reg_single(emit, reg_index, 0); ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2); @@ -1626,6 +1674,12 @@ static void emit_native_load_subscr(emit_t *emit) { } case VTYPE_PTR32: { // pointer to word-size memory + #if N_RV32 + asm_rv32_opcode_slli(emit->as, REG_TEMP2, reg_index, 2); + asm_rv32_opcode_cadd(emit->as, REG_ARG_1, REG_TEMP2); + asm_rv32_opcode_lw(emit->as, REG_RET, REG_ARG_1, 0); + break; + #endif ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base @@ -1781,6 +1835,11 @@ static void emit_native_store_subscr(emit_t *emit) { asm_thumb_strb_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); break; } + #elif N_RV32 + if (FIT_SIGNED(index_value, 12)) { + asm_rv32_opcode_sb(emit->as, reg_value, reg_base, index_value); + break; + } #endif ASM_MOV_REG_IMM(emit->as, reg_index, index_value); #if N_ARM @@ -1802,6 +1861,11 @@ static void emit_native_store_subscr(emit_t *emit) { asm_thumb_strh_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); break; } + #elif N_RV32 + if (FIT_SIGNED(index_value, 11)) { + asm_rv32_opcode_sh(emit->as, reg_value, reg_base, index_value << 1); + break; + } #endif ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base @@ -1819,8 +1883,12 @@ static void emit_native_store_subscr(emit_t *emit) { asm_thumb_str_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); break; } - #endif - #if N_ARM + #elif N_RV32 + if (FIT_SIGNED(index_value, 10)) { + asm_rv32_opcode_sw(emit->as, reg_value, reg_base, index_value << 2); + break; + } + #elif N_ARM ASM_MOV_REG_IMM(emit->as, reg_index, index_value); asm_arm_str_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); return; @@ -1885,6 +1953,11 @@ static void emit_native_store_subscr(emit_t *emit) { #if N_ARM asm_arm_str_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index); break; + #elif N_RV32 + asm_rv32_opcode_slli(emit->as, REG_TEMP2, reg_index, 2); + asm_rv32_opcode_cadd(emit->as, REG_ARG_1, REG_TEMP2); + asm_rv32_opcode_sw(emit->as, reg_value, REG_ARG_1, 0); + break; #endif ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base @@ -2133,6 +2206,7 @@ static void emit_native_setup_with(emit_t *emit, mp_uint_t label) { } static void emit_native_setup_block(emit_t *emit, mp_uint_t label, int kind) { + DEBUG_printf("setup_block(%d, %d)\n", (int)label, kind); if (kind == MP_EMIT_SETUP_BLOCK_WITH) { emit_native_setup_with(emit, label); } else { @@ -2209,15 +2283,43 @@ static void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { emit_native_label_assign(emit, *emit->label_slot + 1); // Exception is in nlr_buf.ret_val slot + adjust_stack(emit, 1); } +#if MICROPY_PY_ASYNC_AWAIT +static void emit_native_async_with_setup_finally(emit_t *emit, mp_uint_t label_aexit_no_exc, mp_uint_t label_finally_block, mp_uint_t label_ret_unwind_jump) { + // The async-with body has executed and no exception was raised, the execution fell through to this point. + // Stack: (..., ctx_mgr) + + // Insert a dummy value into the stack so the stack has the same layout to execute the code starting at label_aexit_no_exc + emit_native_adjust_stack_size(emit, 1); // push dummy value, it won't ever be used + emit_native_rot_two(emit); + emit_native_load_const_tok(emit, MP_TOKEN_KW_NONE); // to tell end_finally there's no exception + emit_native_rot_two(emit); + // Stack: (..., , None, ctx_mgr) + emit_native_jump(emit, label_aexit_no_exc); // jump to code to call __aexit__ + emit_native_adjust_stack_size(emit, -1); + + // Start of "finally" block which is entered via one of: an exception propagating out, a return, an unwind jump. + emit_native_label_assign(emit, label_finally_block); + + // Detect which case we have by the local exception slot holding an exception or not. + emit_pre_pop_discard(emit); + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); // get exception + emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_1); + ASM_JUMP_IF_REG_ZERO(emit->as, REG_ARG_1, label_ret_unwind_jump, false); // if not an exception then we have return or unwind jump. +} +#endif + static void emit_native_end_finally(emit_t *emit) { // logic: // exc = pop_stack // if exc == None: pass // else: raise exc // the check if exc is None is done in the MP_F_NATIVE_RAISE stub - emit_native_pre(emit); + DEBUG_printf("end_finally\n"); + + emit_pre_pop_discard(emit); ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); emit_call(emit, MP_F_NATIVE_RAISE); @@ -2241,6 +2343,8 @@ static void emit_native_get_iter(emit_t *emit, bool use_stack) { // perhaps the difficult one, as we want to rewrite for loops using native code // in cases where we iterate over a Python object, can we use normal runtime calls? + DEBUG_printf("get_iter(%d)\n", use_stack); + vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_ARG_1); assert(vtype == VTYPE_PYOBJ); @@ -2552,6 +2656,38 @@ static void emit_native_binary_op(emit_t *emit, mp_binary_op_t op) { } else { asm_xtensa_setcc_reg_reg_reg(emit->as, cc & ~0x80, REG_RET, reg_rhs, REG_ARG_2); } + #elif N_RV32 + (void)op_idx; + switch (op) { + case MP_BINARY_OP_LESS: + asm_rv32_meta_comparison_lt(emit->as, REG_ARG_2, reg_rhs, REG_RET, vtype_lhs == VTYPE_UINT); + break; + + case MP_BINARY_OP_MORE: + asm_rv32_meta_comparison_lt(emit->as, reg_rhs, REG_ARG_2, REG_RET, vtype_lhs == VTYPE_UINT); + break; + + case MP_BINARY_OP_EQUAL: + asm_rv32_meta_comparison_eq(emit->as, REG_ARG_2, reg_rhs, REG_RET); + break; + + case MP_BINARY_OP_LESS_EQUAL: + asm_rv32_meta_comparison_le(emit->as, REG_ARG_2, reg_rhs, REG_RET, vtype_lhs == VTYPE_UINT); + break; + + case MP_BINARY_OP_MORE_EQUAL: + asm_rv32_meta_comparison_le(emit->as, reg_rhs, REG_ARG_2, REG_RET, vtype_lhs == VTYPE_UINT); + break; + + case MP_BINARY_OP_NOT_EQUAL: + asm_rv32_meta_comparison_ne(emit->as, reg_rhs, REG_ARG_2, REG_RET); + break; + + default: + break; + } + #elif N_DEBUG + asm_debug_setcc_reg_reg_reg(emit->as, op_idx, REG_RET, REG_ARG_2, reg_rhs); #else #error not implemented #endif @@ -2792,6 +2928,7 @@ static void emit_native_call_function(emit_t *emit, mp_uint_t n_positional, mp_u } static void emit_native_call_method(emit_t *emit, mp_uint_t n_positional, mp_uint_t n_keyword, mp_uint_t star_flags) { + DEBUG_printf("call_method(%d, %d, %d)\n", n_positional, n_keyword, star_flags); if (star_flags) { emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword + 3); // pointer to args emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW_VAR, 1, REG_ARG_1, n_positional | (n_keyword << 8), REG_ARG_2); @@ -2858,6 +2995,7 @@ static void emit_native_return_value(emit_t *emit) { } static void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) { + DEBUG_printf("raise_varargs(%d)\n", n_args); (void)n_args; assert(n_args == 1); vtype_kind_t vtype_exc; @@ -2873,6 +3011,8 @@ static void emit_native_raise_varargs(emit_t *emit, mp_uint_t n_args) { static void emit_native_yield(emit_t *emit, int kind) { // Note: 1 (yield) or 3 (yield from) labels are reserved for this function, starting at *emit->label_slot + DEBUG_printf("yield(%d)\n", kind); + if (emit->do_viper_types) { mp_raise_NotImplementedError(MP_ERROR_TEXT("native yield")); } @@ -2928,18 +3068,22 @@ static void emit_native_yield(emit_t *emit, int kind) { emit_native_adjust_stack_size(emit, 1); // send_value if (kind == MP_EMIT_YIELD_VALUE) { - // Check LOCAL_IDX_EXC_VAL for any injected value - ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_EXC_VAL(emit)); + // Check LOCAL_IDX_THROW_VAL for any injected value + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_THROW_VAL(emit)); + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2); emit_call(emit, MP_F_NATIVE_RAISE); } else { // Label loop entry emit_native_label_assign(emit, *emit->label_slot + 2); // Get the next item from the delegate generator + ASM_MOV_REG_LOCAL(emit->as, REG_ARG_3, LOCAL_IDX_THROW_VAL(emit)); // throw_value + ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2); vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_ARG_2); // send_value emit_access_stack(emit, 1, &vtype, REG_ARG_1); // generator - ASM_MOV_REG_LOCAL(emit->as, REG_ARG_3, LOCAL_IDX_EXC_VAL(emit)); // throw_value emit_post_push_reg(emit, VTYPE_PYOBJ, REG_ARG_3); emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 1); // ret_value emit_call(emit, MP_F_NATIVE_YIELD_FROM); @@ -2963,7 +3107,6 @@ static void emit_native_start_except_handler(emit_t *emit) { } static void emit_native_end_except_handler(emit_t *emit) { - adjust_stack(emit, -1); // pop the exception (end_finally didn't use it) } const emit_method_table_t EXPORT_FUN(method_table) = { @@ -3012,6 +3155,9 @@ const emit_method_table_t EXPORT_FUN(method_table) = { emit_native_unwind_jump, emit_native_setup_block, emit_native_with_cleanup, + #if MICROPY_PY_ASYNC_AWAIT + emit_native_async_with_setup_finally, + #endif emit_native_end_finally, emit_native_get_iter, emit_native_for_iter, diff --git a/py/emitndebug.c b/py/emitndebug.c new file mode 100644 index 0000000000000..bd896a75c8ddf --- /dev/null +++ b/py/emitndebug.c @@ -0,0 +1,285 @@ +// native-debug specific stuff + +#include "py/mpconfig.h" + +#if MICROPY_EMIT_NATIVE_DEBUG + +#include "py/asmbase.h" +#include "py/nativeglue.h" + +#define asm_debug_printf(as, fmt, ...) \ + do { \ + if (as->base.pass == MP_ASM_PASS_EMIT) { \ + if (fmt[0] != 'E') { \ + mp_printf(MICROPY_EMIT_NATIVE_DEBUG_PRINTER, " "); \ + } \ + if (as->base.suppress) { \ + mp_printf(MICROPY_EMIT_NATIVE_DEBUG_PRINTER, "dead_code "); \ + } \ + mp_printf(MICROPY_EMIT_NATIVE_DEBUG_PRINTER, fmt, __VA_ARGS__); \ + } \ + } while (0) + +enum { + ASM_DEBUG_REG_R00, + ASM_DEBUG_REG_R01, + ASM_DEBUG_REG_R02, + ASM_DEBUG_REG_R03, + ASM_DEBUG_REG_R04, + ASM_DEBUG_REG_R05, + ASM_DEBUG_REG_R06, + ASM_DEBUG_REG_R07, + ASM_DEBUG_REG_R08, + ASM_DEBUG_REG_R09, + ASM_DEBUG_REG_R10, + ASM_DEBUG_REG_R11, +}; + +typedef struct _asm_debug_t { + mp_asm_base_t base; +} asm_debug_t; + +static const char *const reg_name_table[] = { + "r_ret", + "r_arg1", + "r_arg2", + "r_arg3", + "r_arg4", + "r_temp0", + "r_temp1", + "r_temp2", + "r_local1", + "r_local2", + "r_local3", + "r_fun_table", +}; + +static const char *const fun_name_table[MP_F_NUMBER_OF] = { + [MP_F_CONVERT_OBJ_TO_NATIVE] = "convert_obj_to_native", + [MP_F_CONVERT_NATIVE_TO_OBJ] = "convert_native_to_obj", + [MP_F_NATIVE_SWAP_GLOBALS] = "native_swap_globals", + [MP_F_LOAD_NAME] = "load_name", + [MP_F_LOAD_GLOBAL] = "load_global", + [MP_F_LOAD_BUILD_CLASS] = "load_build_class", + [MP_F_LOAD_ATTR] = "load_attr", + [MP_F_LOAD_METHOD] = "load_method", + [MP_F_LOAD_SUPER_METHOD] = "load_super_method", + [MP_F_STORE_NAME] = "store_name", + [MP_F_STORE_GLOBAL] = "store_global", + [MP_F_STORE_ATTR] = "store_attr", + [MP_F_OBJ_SUBSCR] = "obj_subscr", + [MP_F_OBJ_IS_TRUE] = "obj_is_true", + [MP_F_UNARY_OP] = "unary_op", + [MP_F_BINARY_OP] = "binary_op", + [MP_F_BUILD_TUPLE] = "build_tuple", + [MP_F_BUILD_LIST] = "build_list", + [MP_F_BUILD_MAP] = "build_map", + [MP_F_BUILD_SET] = "build_set", + [MP_F_STORE_SET] = "store_set", + [MP_F_LIST_APPEND] = "list_append", + [MP_F_STORE_MAP] = "store_map", + [MP_F_MAKE_FUNCTION_FROM_PROTO_FUN] = "make_function_from_proto_fun", + [MP_F_NATIVE_CALL_FUNCTION_N_KW] = "native_call_function_n_kw", + [MP_F_CALL_METHOD_N_KW] = "call_method_n_kw", + [MP_F_CALL_METHOD_N_KW_VAR] = "call_method_n_kw_var", + [MP_F_NATIVE_GETITER] = "native_getiter", + [MP_F_NATIVE_ITERNEXT] = "native_iternext", + [MP_F_NLR_PUSH] = "nlr_push", + [MP_F_NLR_POP] = "nlr_pop", + [MP_F_NATIVE_RAISE] = "native_raise", + [MP_F_IMPORT_NAME] = "import_name", + [MP_F_IMPORT_FROM] = "import_from", + [MP_F_IMPORT_ALL] = "import_all", + [MP_F_NEW_SLICE] = "new_slice", + [MP_F_UNPACK_SEQUENCE] = "unpack_sequence", + [MP_F_UNPACK_EX] = "unpack_ex", + [MP_F_DELETE_NAME] = "delete_name", + [MP_F_DELETE_GLOBAL] = "delete_global", + [MP_F_NEW_CLOSURE] = "new_closure", + [MP_F_ARG_CHECK_NUM_SIG] = "arg_check_num_sig", + [MP_F_SETUP_CODE_STATE] = "setup_code_state", + [MP_F_SMALL_INT_FLOOR_DIVIDE] = "small_int_floor_divide", + [MP_F_SMALL_INT_MODULO] = "small_int_modulo", + [MP_F_NATIVE_YIELD_FROM] = "native_yield_from", + [MP_F_SETJMP] = "setjmp", +}; + +static void asm_debug_end_pass(asm_debug_t *as) { + (void)as; +} + +static void asm_debug_entry(asm_debug_t *as, int num_locals) { + asm_debug_printf(as, "ENTRY(num_locals=%d)\n", num_locals); +} + +static void asm_debug_exit(asm_debug_t *as) { + asm_debug_printf(as, "EXIT(%u)\n", 0); +} + +static void asm_debug_fun(asm_debug_t *as, const char *op, int fun_idx) { + asm_debug_printf(as, "%s(%s)\n", op, fun_name_table[fun_idx]); +} + +static void asm_debug_reg(asm_debug_t *as, const char *op, int reg) { + asm_debug_printf(as, "%s(%s)\n", op, reg_name_table[reg]); +} + +static void asm_debug_label(asm_debug_t *as, const char *op, unsigned int label) { + asm_debug_printf(as, "%s(label_%u)\n", op, label); +} + +static void asm_debug_reg_imm(asm_debug_t *as, const char *op, int reg, int imm) { + asm_debug_printf(as, "%s(%s, %d=0x%x)\n", op, reg_name_table[reg], imm, imm); +} + +#if !MICROPY_PERSISTENT_CODE_SAVE +static void asm_debug_reg_qstr(asm_debug_t *as, const char *op, int reg, int qst) { + asm_debug_printf(as, "%s(%s, %s)\n", op, reg_name_table[reg], qstr_str(qst)); +} +#endif + +static void asm_debug_reg_reg(asm_debug_t *as, const char *op, int reg1, int reg2) { + asm_debug_printf(as, "%s(%s, %s)\n", op, reg_name_table[reg1], reg_name_table[reg2]); +} + +static void asm_debug_reg_local(asm_debug_t *as, const char *op, int reg, unsigned int local) { + asm_debug_printf(as, "%s(%s, local_%u)\n", op, reg_name_table[reg], local); +} + +static void asm_debug_reg_label(asm_debug_t *as, const char *op, int reg, unsigned int label) { + asm_debug_printf(as, "%s(%s, label_%u)\n", op, reg_name_table[reg], label); +} + +static void asm_debug_local_reg(asm_debug_t *as, const char *op, int local, int reg) { + asm_debug_printf(as, "%s(local_%d, %s)\n", op, local, reg_name_table[reg]); +} + +static void asm_debug_reg_label_bool(asm_debug_t *as, const char *op, int reg, unsigned int label, bool b) { + asm_debug_printf(as, "%s(%s, label_%u, %s)\n", op, reg_name_table[reg], label, b ? "true" : "false"); +} + +static void asm_debug_reg_reg_offset(asm_debug_t *as, const char *op, int reg1, int reg2, int offset) { + asm_debug_printf(as, "%s(%s, %s, %d)\n", op, reg_name_table[reg1], reg_name_table[reg2], offset); +} + +static void asm_debug_reg_reg_label(asm_debug_t *as, const char *op, int reg1, int reg2, unsigned int label) { + asm_debug_printf(as, "%s(%s, %s, label_%u)\n", op, reg_name_table[reg1], reg_name_table[reg2], label); +} + +static void asm_debug_setcc_reg_reg_reg(asm_debug_t *as, int op, int reg1, int reg2, int reg3) { + asm_debug_printf(as, "setcc(%d, %s, %s, %s)\n", op, reg_name_table[reg1], reg_name_table[reg2], reg_name_table[reg3]); +} + +// The following macros provide a (mostly) arch-independent API to +// generate native code, and are used by the native emitter. + +#define ASM_WORD_SIZE (8) + +#define REG_RET ASM_DEBUG_REG_R00 +#define REG_ARG_1 ASM_DEBUG_REG_R01 +#define REG_ARG_2 ASM_DEBUG_REG_R02 +#define REG_ARG_3 ASM_DEBUG_REG_R03 +#define REG_ARG_4 ASM_DEBUG_REG_R04 + +#define REG_TEMP0 ASM_DEBUG_REG_R05 +#define REG_TEMP1 ASM_DEBUG_REG_R06 +#define REG_TEMP2 ASM_DEBUG_REG_R07 + +#define REG_LOCAL_1 ASM_DEBUG_REG_R08 +#define REG_LOCAL_2 ASM_DEBUG_REG_R09 +#define REG_LOCAL_3 ASM_DEBUG_REG_R10 +#define REG_LOCAL_NUM (3) + +// Holds a pointer to mp_fun_table +#define REG_FUN_TABLE ASM_DEBUG_REG_R11 + +#define ASM_T asm_debug_t +#define ASM_END_PASS asm_debug_end_pass +#define ASM_ENTRY(as, num_locals) \ + asm_debug_entry(as, num_locals) +#define ASM_EXIT(as) \ + asm_debug_exit(as) + +#define ASM_JUMP(as, label) \ + asm_debug_label(as, "jump", label) +#define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ + asm_debug_reg_label_bool(as, "jump_if_reg_zero", reg, label, bool_test) +#define ASM_JUMP_IF_REG_NONZERO(as, reg, label, bool_test) \ + asm_debug_reg_label_bool(as, "jump_if_reg_nonzero", reg, label, bool_test) +#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \ + asm_debug_reg_reg_label(as, "jump_if_reg_eq", reg1, reg2, label) +#define ASM_JUMP_REG(as, reg) \ + asm_debug_reg(as, "jump_reg", reg) +#define ASM_CALL_IND(as, idx) \ + asm_debug_fun(as, "call_ind", idx) + +#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) \ + asm_debug_local_reg(as, "mov_local_reg", local_num, reg_src) +#define ASM_MOV_REG_IMM(as, reg_dest, imm) \ + asm_debug_reg_imm(as, "mov_reg_imm", reg_dest, imm) +#define ASM_MOV_REG_QSTR(as, reg_dest, qst) \ + asm_debug_reg_qstr(as, "mov_reg_qstr", reg_dest, qst) +#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) \ + asm_debug_reg_local(as, "mov_reg_local", reg_dest, local_num) +#define ASM_MOV_REG_REG(as, reg_dest, reg_src) \ + asm_debug_reg_reg(as, "mov_reg_reg", reg_dest, reg_src) +#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) \ + asm_debug_reg_local(as, "mov_reg_local_addr", reg_dest, local_num) +#define ASM_MOV_REG_PCREL(as, reg_dest, label) \ + asm_debug_reg_label(as, "mov_reg_pcrel", reg_dest, label) + +#define ASM_NOT_REG(as, reg_dest) \ + asm_debug_reg(as, "not", reg_dest) +#define ASM_NEG_REG(as, reg_dest) \ + asm_debug_reg(as, "neg", reg_dest) +#define ASM_LSL_REG_REG(as, reg_dest, reg_src) \ + asm_debug_reg_reg(as, "lsl", reg_dest, reg_src) +#define ASM_LSR_REG_REG(as, reg_dest, reg_src) \ + asm_debug_reg_reg(as, "lsr", reg_dest, reg_src) +#define ASM_ASR_REG_REG(as, reg_dest, reg_src) \ + asm_debug_reg_reg(as, "asr", reg_dest, reg_src) +#define ASM_OR_REG_REG(as, reg_dest, reg_src) \ + asm_debug_reg_reg(as, "or", reg_dest, reg_src) +#define ASM_XOR_REG_REG(as, reg_dest, reg_src) \ + asm_debug_reg_reg(as, "xor", reg_dest, reg_src) +#define ASM_AND_REG_REG(as, reg_dest, reg_src) \ + asm_debug_reg_reg(as, "and", reg_dest, reg_src) +#define ASM_ADD_REG_REG(as, reg_dest, reg_src) \ + asm_debug_reg_reg(as, "add", reg_dest, reg_src) +#define ASM_SUB_REG_REG(as, reg_dest, reg_src) \ + asm_debug_reg_reg(as, "sub", reg_dest, reg_src) +#define ASM_MUL_REG_REG(as, reg_dest, reg_src) \ + asm_debug_reg_reg(as, "mul", reg_dest, reg_src) + +#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) \ + asm_debug_reg_reg(as, "load", reg_dest, reg_base) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) \ + asm_debug_reg_reg_offset(as, "load", reg_dest, reg_base, word_offset) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) \ + asm_debug_reg_reg(as, "load8", reg_dest, reg_base) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) \ + asm_debug_reg_reg(as, "load16", reg_dest, reg_base) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) \ + asm_debug_reg_reg_offset(as, "load16", reg_dest, reg_base, uint16_offset) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) \ + asm_debug_reg_reg(as, "load32", reg_dest, reg_base) + +#define ASM_STORE_REG_REG(as, reg_src, reg_base) \ + asm_debug_reg_reg(as, "store", reg_src, reg_base) +#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) \ + asm_debug_reg_reg_offset(as, "store", reg_src, reg_base, word_offset) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) \ + asm_debug_reg_reg(as, "store8", reg_src, reg_base) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) \ + asm_debug_reg_reg(as, "store16", reg_src, reg_base) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) \ + asm_debug_reg_reg(as, "store32", reg_src, reg_base) + +// Word indices of REG_LOCAL_x in nlr_buf_t +#define NLR_BUF_IDX_LOCAL_1 (5) // rbx + +#define N_DEBUG (1) +#define EXPORT_FUN(name) emit_native_debug_##name +#include "py/emitnative.c" + +#endif diff --git a/shared/upytesthelper/upytesthelper.h b/py/emitnrv32.c similarity index 70% rename from shared/upytesthelper/upytesthelper.h rename to py/emitnrv32.c index 3a292befd7757..4a44100093141 100644 --- a/shared/upytesthelper/upytesthelper.h +++ b/py/emitnrv32.c @@ -1,9 +1,9 @@ /* - * This file is part of the MicroPython project, http://micropython.org/ + * This file is part of the MicroPython project, https://micropython.org/ * * The MIT License (MIT) * - * Copyright (c) 2017 Linaro Limited + * Copyright (c) 2024 Alessandro Gatti * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,14 +24,21 @@ * THE SOFTWARE. */ -#include -#include +// RISC-V RV32 specific stuff + #include "py/mpconfig.h" -#include "lib/tinytest/tinytest.h" -#include "lib/tinytest/tinytest_macros.h" -void upytest_set_heap(void *start, void *end); -void upytest_set_expected_output(const char *output, unsigned len); -void upytest_execute_test(const char *src); -void upytest_output(const char *str, mp_uint_t len); -bool upytest_is_failed(void); +#if MICROPY_EMIT_RV32 + +// this is defined so that the assembler exports generic assembler API macros +#define GENERIC_ASM_API (1) +#include "py/asmrv32.h" + +// Word indices of REG_LOCAL_x in nlr_buf_t +#define NLR_BUF_IDX_LOCAL_1 (6) // S3 + +#define N_RV32 (1) +#define EXPORT_FUN(name) emit_native_rv32_##name +#include "py/emitnative.c" + +#endif diff --git a/py/gc.c b/py/gc.c index c4febe7569fa8..c74aba9e8b5c6 100644 --- a/py/gc.c +++ b/py/gc.c @@ -1035,16 +1035,6 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) { return ret_ptr; } -/* -void *gc_alloc(mp_uint_t n_bytes) { - return _gc_alloc(n_bytes, false); -} - -void *gc_alloc_with_finaliser(mp_uint_t n_bytes) { - return _gc_alloc(n_bytes, true); -} -*/ - // force the freeing of a piece of memory // TODO: freeing here does not call finaliser void gc_free(void *ptr) { @@ -1157,35 +1147,6 @@ size_t gc_nbytes(const void *ptr) { return 0; } -#if 0 -// old, simple realloc that didn't expand memory in place -void *gc_realloc(void *ptr, mp_uint_t n_bytes) { - mp_uint_t n_existing = gc_nbytes(ptr); - if (n_bytes <= n_existing) { - return ptr; - } else { - bool has_finaliser; - if (ptr == NULL) { - has_finaliser = false; - } else { - #if MICROPY_ENABLE_FINALISER - has_finaliser = FTB_GET(BLOCK_FROM_PTR((mp_uint_t)ptr)); - #else - has_finaliser = false; - #endif - } - void *ptr2 = gc_alloc(n_bytes, has_finaliser); - if (ptr2 == NULL) { - return ptr2; - } - memcpy(ptr2, ptr, n_existing); - gc_free(ptr); - return ptr2; - } -} - -#else // Alternative gc_realloc impl - void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { // check for pure allocation if (ptr_in == NULL) { @@ -1363,7 +1324,6 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { gc_free(ptr_in); return ptr_out; } -#endif // Alternative gc_realloc impl void gc_dump_info(const mp_print_t *print) { gc_info_t info; @@ -1511,41 +1471,4 @@ void gc_dump_alloc_table(const mp_print_t *print) { GC_EXIT(); } -#if 0 -// For testing the GC functions -void gc_test(void) { - mp_uint_t len = 500; - mp_uint_t *heap = malloc(len); - gc_init(heap, heap + len / sizeof(mp_uint_t)); - void *ptrs[100]; - { - mp_uint_t **p = gc_alloc(16, false); - p[0] = gc_alloc(64, false); - p[1] = gc_alloc(1, false); - p[2] = gc_alloc(1, false); - p[3] = gc_alloc(1, false); - mp_uint_t ***p2 = gc_alloc(16, false); - p2[0] = p; - p2[1] = p; - ptrs[0] = p2; - } - for (int i = 0; i < 25; i += 2) { - mp_uint_t *p = gc_alloc(i, false); - printf("p=%p\n", p); - if (i & 3) { - // ptrs[i] = p; - } - } - - printf("Before GC:\n"); - gc_dump_alloc_table(&mp_plat_print); - printf("Starting GC...\n"); - gc_collect_start(); - gc_collect_root(ptrs, sizeof(ptrs) / sizeof(void *)); - gc_collect_end(); - printf("After GC:\n"); - gc_dump_alloc_table(&mp_plat_print); -} -#endif - #endif // MICROPY_ENABLE_GC diff --git a/py/lexer.c b/py/lexer.c index bff8e637656d6..98a10c87b2e5a 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -228,7 +228,6 @@ static const char *const tok_enc = "=e=" // = == "!."; // start of special cases: != . ... -// TODO static assert that number of tokens is less than 256 so we can safely make this table with byte sized entries static const uint8_t tok_enc_kind[] = { MP_TOKEN_DEL_PAREN_OPEN, MP_TOKEN_DEL_PAREN_CLOSE, MP_TOKEN_DEL_BRACKET_OPEN, MP_TOKEN_DEL_BRACKET_CLOSE, @@ -336,8 +335,12 @@ static void parse_string_literal(mp_lexer_t *lex, bool is_raw, bool is_fstring) // assume there's going to be interpolation, so prep the injection data // fstring_args_idx==0 && len(fstring_args)>0 means we're extracting the args. // only when fstring_args_idx>0 will we consume the arg data - // note: lex->fstring_args will be empty already (it's reset when finished) - vstr_add_str(&lex->fstring_args, ".format("); + // lex->fstring_args is reset when finished, so at this point there are two cases: + // - lex->fstring_args is empty: start of a new f-string + // - lex->fstring_args is non-empty: concatenation of adjacent f-strings + if (vstr_len(&lex->fstring_args) == 0) { + vstr_add_str(&lex->fstring_args, ".format("); + } } #endif @@ -657,21 +660,19 @@ void mp_lexer_to_next(mp_lexer_t *lex) { } #if MICROPY_PY_FSTRINGS if (is_char_following(lex, 'f')) { - // raw-f-strings unsupported, immediately return (invalid) token. - lex->tok_kind = MP_TOKEN_FSTRING_RAW; - break; + is_fstring = true; + n_char = 2; } #endif } #if MICROPY_PY_FSTRINGS else if (is_char(lex, 'f')) { + is_fstring = true; + n_char = 1; if (is_char_following(lex, 'r')) { - // raw-f-strings unsupported, immediately return (invalid) token. - lex->tok_kind = MP_TOKEN_FSTRING_RAW; - break; + is_raw = true; + n_char = 2; } - n_char = 1; - is_fstring = true; } #endif @@ -772,6 +773,9 @@ void mp_lexer_to_next(mp_lexer_t *lex) { } else { // search for encoded delimiter or operator + // assert that the token enum value fits in a byte, so they all fit in tok_enc_kind + MP_STATIC_ASSERT(MP_TOKEN_NUMBER_OF <= 256); + const char *t = tok_enc; size_t tok_enc_index = 0; for (; *t != 0 && !is_char(lex, *t); t += 1) { diff --git a/py/lexer.h b/py/lexer.h index 2d9d0447b8ba3..6e6c3e8f23e06 100644 --- a/py/lexer.h +++ b/py/lexer.h @@ -46,7 +46,6 @@ typedef enum _mp_token_kind_t { MP_TOKEN_LONELY_STRING_OPEN, #if MICROPY_PY_FSTRINGS MP_TOKEN_MALFORMED_FSTRING, - MP_TOKEN_FSTRING_RAW, #endif MP_TOKEN_NEWLINE, @@ -153,6 +152,8 @@ typedef enum _mp_token_kind_t { MP_TOKEN_DEL_SEMICOLON, MP_TOKEN_DEL_EQUAL, MP_TOKEN_DEL_MINUS_MORE, + + MP_TOKEN_NUMBER_OF, } mp_token_kind_t; // this data structure is exposed for efficiency diff --git a/py/misc.h b/py/misc.h index 868faa412b4de..3624efaa52220 100644 --- a/py/misc.h +++ b/py/misc.h @@ -363,4 +363,74 @@ typedef const char *mp_rom_error_text_t; // For now, forward directly to MP_COMPRESSED_ROM_TEXT. #define MP_ERROR_TEXT(x) (mp_rom_error_text_t)MP_COMPRESSED_ROM_TEXT(x) +// Portable implementations of CLZ and CTZ intrinsics +#ifdef _MSC_VER +#include + +static inline uint32_t mp_clz(uint32_t x) { + unsigned long lz = 0; + return _BitScanReverse(&lz, x) ? (sizeof(x) * 8 - 1) - lz : 0; +} + +static inline uint32_t mp_clzl(unsigned long x) { + unsigned long lz = 0; + return _BitScanReverse(&lz, x) ? (sizeof(x) * 8 - 1) - lz : 0; +} + +#ifdef _WIN64 +static inline uint32_t mp_clzll(unsigned long long x) { + unsigned long lz = 0; + return _BitScanReverse64(&lz, x) ? (sizeof(x) * 8 - 1) - lz : 0; +} +#else +// Microsoft don't ship _BitScanReverse64 on Win32, so emulate it +static inline uint32_t mp_clzll(unsigned long long x) { + unsigned long h = x >> 32; + return h ? mp_clzl(h) : (mp_clzl(x) + 32); +} +#endif + +static inline uint32_t mp_ctz(uint32_t x) { + unsigned long tz = 0; + return _BitScanForward(&tz, x) ? tz : 0; +} + +// Workaround for 'warning C4127: conditional expression is constant'. +static inline bool mp_check(bool value) { + return value; +} +#else +#define mp_clz(x) __builtin_clz(x) +#define mp_clzl(x) __builtin_clzl(x) +#define mp_clzll(x) __builtin_clzll(x) +#define mp_ctz(x) __builtin_ctz(x) +#define mp_check(x) (x) +#endif + +// mp_int_t can be larger than long, i.e. Windows 64-bit, nan-box variants +static inline uint32_t mp_clz_mpi(mp_int_t x) { + #ifdef __XC16__ + mp_uint_t mask = MP_OBJ_WORD_MSBIT_HIGH; + mp_uint_t zeroes = 0; + while (mask != 0) { + if (mask & (mp_uint_t)x) { + break; + } + zeroes++; + mask >>= 1; + } + return zeroes; + #else + MP_STATIC_ASSERT(sizeof(mp_int_t) == sizeof(long long) + || sizeof(mp_int_t) == sizeof(long)); + + // ugly, but should compile to single intrinsic unless O0 is set + if (mp_check(sizeof(mp_int_t) == sizeof(long))) { + return mp_clzl((unsigned long)x); + } else { + return mp_clzll((unsigned long long)x); + } + #endif +} + #endif // MICROPY_INCLUDED_PY_MISC_H diff --git a/py/mkrules.mk b/py/mkrules.mk index 93a6ab6fba5c8..e0c2cfd979425 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -243,8 +243,8 @@ endif submodules: $(ECHO) "Updating submodules: $(GIT_SUBMODULES)" ifneq ($(GIT_SUBMODULES),) - $(Q)git submodule sync $(addprefix $(TOP)/,$(GIT_SUBMODULES)) - $(Q)git submodule update --init $(addprefix $(TOP)/,$(GIT_SUBMODULES)) + $(Q)cd $(TOP) && git submodule sync $(GIT_SUBMODULES) + $(Q)cd $(TOP) && git submodule update --init $(GIT_SUBMODULES) endif .PHONY: submodules diff --git a/py/modmath.c b/py/modmath.c index 701da796bce36..2b41bbcd7d15e 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -196,7 +196,17 @@ MATH_FUN_1(erf, erf) // erfc(x): return the complementary error function of x MATH_FUN_1(erfc, erfc) // gamma(x): return the gamma function of x +#if MICROPY_PY_MATH_GAMMA_FIX_NEGINF +static mp_float_t MICROPY_FLOAT_C_FUN(tgamma_func)(mp_float_t x) { + if (isinf(x) && x < 0) { + math_error(); + } + return MICROPY_FLOAT_C_FUN(tgamma)(x); +} +MATH_FUN_1(gamma, tgamma_func) +#else MATH_FUN_1(gamma, tgamma) +#endif // lgamma(x): return the natural logarithm of the gamma function of x MATH_FUN_1(lgamma, lgamma) #endif diff --git a/py/modmicropython.c b/py/modmicropython.c index 4a0e2cf44ffff..e48b033648d0f 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -27,7 +27,7 @@ #include #include "py/builtin.h" -#include "py/stackctrl.h" +#include "py/cstack.h" #include "py/runtime.h" #include "py/gc.h" #include "py/mphal.h" @@ -78,9 +78,9 @@ mp_obj_t mp_micropython_mem_info(size_t n_args, const mp_obj_t *args) { #endif #if MICROPY_STACK_CHECK mp_printf(&mp_plat_print, "stack: " UINT_FMT " out of " UINT_FMT "\n", - mp_stack_usage(), (mp_uint_t)MP_STATE_THREAD(stack_limit)); + mp_cstack_usage(), (mp_uint_t)MP_STATE_THREAD(stack_limit)); #else - mp_printf(&mp_plat_print, "stack: " UINT_FMT "\n", mp_stack_usage()); + mp_printf(&mp_plat_print, "stack: " UINT_FMT "\n", mp_cstack_usage()); #endif #if MICROPY_ENABLE_GC gc_dump_info(&mp_plat_print); @@ -113,7 +113,7 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_micropython_qstr_info_obj, 0, 1, m #if MICROPY_PY_MICROPYTHON_STACK_USE static mp_obj_t mp_micropython_stack_use(void) { - return MP_OBJ_NEW_SMALL_INT(mp_stack_usage()); + return MP_OBJ_NEW_SMALL_INT(mp_cstack_usage()); } static MP_DEFINE_CONST_FUN_OBJ_0(mp_micropython_stack_use_obj, mp_micropython_stack_use); #endif @@ -213,6 +213,9 @@ static const mp_rom_map_elem_t mp_module_micropython_globals_table[] = { #if CIRCUITPY_MICROPYTHON_ADVANCED && MICROPY_KBD_EXCEPTION { MP_ROM_QSTR(MP_QSTR_kbd_intr), MP_ROM_PTR(&mp_micropython_kbd_intr_obj) }, #endif + #if MICROPY_PY_MICROPYTHON_RINGIO + { MP_ROM_QSTR(MP_QSTR_RingIO), MP_ROM_PTR(&mp_type_ringio) }, + #endif #if MICROPY_ENABLE_SCHEDULER { MP_ROM_QSTR(MP_QSTR_schedule), MP_ROM_PTR(&mp_micropython_schedule_obj) }, #endif diff --git a/py/modthread.c b/py/modthread.c index 188449802fdd2..1b792eaeb774b 100644 --- a/py/modthread.c +++ b/py/modthread.c @@ -28,7 +28,6 @@ #include #include "py/runtime.h" -#include "py/stackctrl.h" #if MICROPY_PY_THREAD diff --git a/py/mpconfig.h b/py/mpconfig.h index 1570265c1999c..20e237cc1cca5 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -40,8 +40,8 @@ // as well as a fallback to generate MICROPY_GIT_TAG if the git repo or tags // are unavailable. #define MICROPY_VERSION_MAJOR 1 -#define MICROPY_VERSION_MINOR 23 -#define MICROPY_VERSION_MICRO 0 +#define MICROPY_VERSION_MINOR 24 +#define MICROPY_VERSION_MICRO 1 #define MICROPY_VERSION_PRERELEASE 0 // Combined version as a 32-bit number for convenience to allow version @@ -418,8 +418,18 @@ #define MICROPY_EMIT_XTENSAWIN (0) #endif +// Whether to emit RISC-V RV32 native code +#ifndef MICROPY_EMIT_RV32 +#define MICROPY_EMIT_RV32 (0) +#endif + +// CIRCUITPY-CHANGE: make sure MICROPY_EMIT_NATIVE_DEBUG is defined +#ifndef MICROPY_EMIT_NATIVE_DEBUG +#define MICROPY_EMIT_NATIVE_DEBUG (0) +#endif + // Convenience definition for whether any native emitter is enabled -#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA || MICROPY_EMIT_XTENSAWIN) +#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA || MICROPY_EMIT_XTENSAWIN || MICROPY_EMIT_RV32 || MICROPY_EMIT_NATIVE_DEBUG) // Some architectures cannot read byte-wise from executable memory. In this case // the prelude for a native function (which usually sits after the machine code) @@ -432,18 +442,6 @@ // Convenience definition for whether any native or inline assembler emitter is enabled #define MICROPY_EMIT_MACHINE_CODE (MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_ASM) -// Whether native relocatable code loaded from .mpy files is explicitly tracked -// so that the GC cannot reclaim it. Needed on architectures that allocate -// executable memory on the MicroPython heap and don't explicitly track this -// data some other way. -#ifndef MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE -#if !MICROPY_EMIT_MACHINE_CODE || defined(MP_PLAT_ALLOC_EXEC) || defined(MP_PLAT_COMMIT_EXEC) -#define MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE (0) -#else -#define MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE (1) -#endif -#endif - /*****************************************************************************/ /* Compiler configuration */ @@ -712,6 +710,13 @@ #define MICROPY_STACK_CHECK (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif +// Additional margin between the places in the runtime where Python stack is +// checked and the actual end of the C stack. Needs to be large enough to avoid +// overflows from function calls made between checks. +#ifndef MICROPY_STACK_CHECK_MARGIN +#define MICROPY_STACK_CHECK_MARGIN (0) +#endif + // Whether to have an emergency exception buffer #ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0) @@ -1338,6 +1343,11 @@ typedef double mp_float_t; #define MICROPY_PY_MICROPYTHON_HEAP_LOCKED (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EVERYTHING) #endif +// Support for micropython.RingIO() +#ifndef MICROPY_PY_MICROPYTHON_RINGIO +#define MICROPY_PY_MICROPYTHON_RINGIO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#endif + // Whether to provide "array" module. Note that large chunk of the // underlying code is shared with "bytearray" builtin type, so to // get real savings, it should be disabled too. @@ -1432,6 +1442,11 @@ typedef double mp_float_t; #define MICROPY_PY_MATH_POW_FIX_NAN (0) #endif +// Whether to provide fix for gamma(-inf) to raise ValueError +#ifndef MICROPY_PY_MATH_GAMMA_FIX_NEGINF +#define MICROPY_PY_MATH_GAMMA_FIX_NEGINF (0) +#endif + // Whether to provide "cmath" module #ifndef MICROPY_PY_CMATH #define MICROPY_PY_CMATH (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) @@ -1660,6 +1675,10 @@ typedef double mp_float_t; #define MICROPY_PY_ASYNCIO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif +#ifndef MICROPY_PY_ASYNCIO_TASK_QUEUE_PUSH_CALLBACK +#define MICROPY_PY_ASYNCIO_TASK_QUEUE_PUSH_CALLBACK (0) +#endif + #ifndef MICROPY_PY_UCTYPES #define MICROPY_PY_UCTYPES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif @@ -1783,6 +1802,11 @@ typedef double mp_float_t; #define MICROPY_PY_MACHINE_RESET (0) #endif +// Maximum number of arguments for machine.freq() +#ifndef MICROPY_PY_MACHINE_FREQ_NUM_ARGS_MAX +#define MICROPY_PY_MACHINE_FREQ_NUM_ARGS_MAX (1) +#endif + // Whether to include: bitstream #ifndef MICROPY_PY_MACHINE_BITSTREAM #define MICROPY_PY_MACHINE_BITSTREAM (0) @@ -1826,6 +1850,12 @@ typedef double mp_float_t; #define MICROPY_PY_MACHINE_SOFTSPI (0) #endif +// Values of SPI.MSB and SPI.LSB constants +#ifndef MICROPY_PY_MACHINE_SPI_MSB +#define MICROPY_PY_MACHINE_SPI_MSB (0) +#define MICROPY_PY_MACHINE_SPI_LSB (1) +#endif + // Whether to provide the "machine.Timer" class #ifndef MICROPY_PY_MACHINE_TIMER #define MICROPY_PY_MACHINE_TIMER (0) @@ -1840,11 +1870,21 @@ typedef double mp_float_t; #define MICROPY_PY_SSL (0) #endif +// CIRCUITPY-CHANGE: avoid undefined warnings +#ifndef MICROPY_PY_SSL_ECDSA_SIGN_ALT +#define MICROPY_PY_SSL_ECDSA_SIGN_ALT (0) +#endif + // Whether to add finaliser code to ssl objects #ifndef MICROPY_PY_SSL_FINALISER #define MICROPY_PY_SSL_FINALISER (MICROPY_ENABLE_FINALISER) #endif +// Whether to add a root pointer for the current ssl object +#ifndef MICROPY_PY_SSL_MBEDTLS_NEED_ACTIVE_CONTEXT +#define MICROPY_PY_SSL_MBEDTLS_NEED_ACTIVE_CONTEXT (MICROPY_PY_SSL_ECDSA_SIGN_ALT) +#endif + // Whether to provide the "vfs" module #ifndef MICROPY_PY_VFS #define MICROPY_PY_VFS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES && MICROPY_VFS) @@ -2012,14 +2052,48 @@ typedef double mp_float_t; #define MICROPY_MAKE_POINTER_CALLABLE(p) (p) #endif -// If these MP_PLAT_*_EXEC macros are overridden then the memory allocated by them -// must be somehow reachable for marking by the GC, since the native code -// generators store pointers to GC managed memory in the code. +// Whether native text/BSS/rodata memory loaded from .mpy files is explicitly tracked +// so that the GC cannot reclaim it. +// +// In general a port should let these options have their defaults, but the defaults here +// can be overridden if needed by defining both MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA +// and MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA. +#ifndef MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA +#if MICROPY_EMIT_MACHINE_CODE && MICROPY_PERSISTENT_CODE_LOAD +// Pointer tracking is required when loading native code is enabled. +#if defined(MP_PLAT_ALLOC_EXEC) || defined(MP_PLAT_COMMIT_EXEC) +// If a port defined a custom allocator or commit function for native text, then the +// text does not need to be tracked (its allocation is managed by the port). But the +// BSS/rodata must be tracked (if there is any) because if there are any pointers to it +// in the function data, they aren't traced by the GC. +#define MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA (0) +#define MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA (1) +#else +// If a port uses the default allocator (the GC heap) then all native text is allocated +// on the GC heap. But it's not guaranteed that a pointer to the head of the block of +// native text (which may contain multiple native functions) will be retained for the GC +// to trace. This is because native functions can start inside the big block of text +// and so it's possible that the only GC-reachable pointers are pointers inside. +// Therefore the big block is explicitly tracked. If there is any BSS/rodata memory, +// then it does not need to be explicitly tracked because a pointer to it is stored into +// the function text via `mp_native_relocate()`. +#define MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA (1) +#define MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA (0) +#endif +#else // MICROPY_EMIT_MACHINE_CODE && MICROPY_PERSISTENT_CODE_LOAD +// Pointer tracking not needed when loading native code is disabled. +#define MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA (0) +#define MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA (0) +#endif +#endif + +// If these macros are defined then the memory allocated by them does not need to be +// traced by the GC. But if they are left undefined then the GC heap will be used as +// the allocator and the memory must be traced by the GC. See also above logic for +// enabling MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA and +// MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA. #ifndef MP_PLAT_ALLOC_EXEC #define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) do { *ptr = m_new(byte, min_size); *size = min_size; } while (0) -#endif - -#ifndef MP_PLAT_FREE_EXEC #define MP_PLAT_FREE_EXEC(ptr, size) m_del(byte, ptr, size) #endif diff --git a/py/mpstate.h b/py/mpstate.h index 1fcc759da79bc..aa85bd450cd55 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -322,6 +322,10 @@ typedef struct _mp_state_thread_t { struct _mp_code_state_t *current_code_state; #endif + #if MICROPY_PY_SSL_MBEDTLS_NEED_ACTIVE_CONTEXT + struct _mp_obj_ssl_context_t *tls_ssl_context; + #endif + // CIRCUITPY-CHANGE #if CIRCUITPY_WARNINGS warnings_action_t warnings_action; diff --git a/py/mpz.c b/py/mpz.c index 746c9fe5b69bc..7d8bc03ca8610 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -1593,7 +1593,7 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) { return true; } -void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf) { +bool mpz_as_bytes(const mpz_t *z, bool big_endian, bool as_signed, size_t len, byte *buf) { byte *b = buf; if (big_endian) { b += len; @@ -1602,6 +1602,8 @@ void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf) { int bits = 0; mpz_dbl_dig_t d = 0; mpz_dbl_dig_t carry = 1; + size_t olen = len; // bytes in output buffer + bool ok = true; for (size_t zlen = z->len; zlen > 0; --zlen) { bits += DIG_SIZE; d = (d << DIG_SIZE) | *zdig++; @@ -1611,28 +1613,32 @@ void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf) { val = (~val & 0xff) + carry; carry = val >> 8; } + + if (!olen) { + // Buffer is full, only OK if all remaining bytes are zeroes + ok = ok && ((byte)val == 0); + continue; + } + if (big_endian) { *--b = val; - if (b == buf) { - return; - } } else { *b++ = val; - if (b == buf + len) { - return; - } } + olen--; } } - // fill remainder of buf with zero/sign extension of the integer - if (big_endian) { - len = b - buf; + if (as_signed && olen == 0 && len > 0) { + // If output exhausted then ensure there was enough space for the sign bit + byte most_sig = big_endian ? buf[0] : buf[len - 1]; + ok = ok && (bool)(most_sig & 0x80) == (bool)z->neg; } else { - len = buf + len - b; - buf = b; + // fill remainder of buf with zero/sign extension of the integer + memset(big_endian ? buf : b, z->neg ? 0xff : 0x00, olen); } - memset(buf, z->neg ? 0xff : 0x00, len); + + return ok; } #if MICROPY_PY_BUILTINS_FLOAT @@ -1715,7 +1721,7 @@ size_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, ch break; } } - if (comma && (s - last_comma) == 3) { + if (!done && comma && (s - last_comma) == 3) { *s++ = comma; last_comma = s; } diff --git a/py/mpz.h b/py/mpz.h index f205e3cd158a1..0422b014a3350 100644 --- a/py/mpz.h +++ b/py/mpz.h @@ -93,9 +93,9 @@ typedef int8_t mpz_dbl_dig_signed_t; typedef struct _mpz_t { // Zero has neg=0, len=0. Negative zero is not allowed. size_t neg : 1; - size_t fixed_dig : 1; - size_t alloc : (8 * sizeof(size_t) - 2); - size_t len; + size_t fixed_dig : 1; // flag, 'dig' buffer cannot be reallocated + size_t alloc : (8 * sizeof(size_t) - 2); // number of entries allocated in 'dig' + size_t len; // number of entries used in 'dig' mpz_dig_t *dig; } mpz_t; @@ -153,7 +153,8 @@ static inline size_t mpz_num_bits(const mpz_t *z) { mp_int_t mpz_hash(const mpz_t *z); bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value); bool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value); -void mpz_as_bytes(const mpz_t *z, bool big_endian, size_t len, byte *buf); +// Returns true if 'z' fit into 'len' bytes of 'buf' without overflowing, 'buf' is truncated otherwise. +bool mpz_as_bytes(const mpz_t *z, bool big_endian, bool as_signed, size_t len, byte *buf); #if MICROPY_PY_BUILTINS_FLOAT mp_float_t mpz_as_float(const mpz_t *z); #endif diff --git a/py/nlr.c b/py/nlr.c index 516b8b86276b2..7ab0c0955a294 100644 --- a/py/nlr.c +++ b/py/nlr.c @@ -28,8 +28,7 @@ #if !MICROPY_NLR_SETJMP // When not using setjmp, nlr_push_tail is called from inline asm so needs special care -// CIRCUITPY-CHANGE: avoid warning -#if defined(MICROPY_NLR_X86) && MICROPY_NLR_X86 && defined(MICROPY_NLR_OS_WINDOWS) && MICROPY_NLR_OS_WINDOWS +#if MICROPY_NLR_X86 && MICROPY_NLR_OS_WINDOWS // On these 32-bit platforms make sure nlr_push_tail doesn't have a leading underscore unsigned int nlr_push_tail(nlr_buf_t *nlr) asm ("nlr_push_tail"); #else diff --git a/py/nlr.h b/py/nlr.h index 15f883422f5fc..340627b7aa1f0 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -44,6 +44,8 @@ #define MICROPY_NLR_NUM_REGS_MIPS (13) #define MICROPY_NLR_NUM_REGS_XTENSA (10) #define MICROPY_NLR_NUM_REGS_XTENSAWIN (17) +#define MICROPY_NLR_NUM_REGS_RV32I (14) +#define MICROPY_NLR_NUM_REGS_RV64I (14) // *FORMAT-OFF* @@ -99,16 +101,65 @@ #elif defined(__mips__) #define MICROPY_NLR_MIPS (1) #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_MIPS) +#elif defined(__riscv) + #if __riscv_xlen == 32 + #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_RV32I) + #define MICROPY_NLR_RV32I (1) + #elif __riscv_xlen == 64 + #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_RV64I) + #define MICROPY_NLR_RV64I (1) + #else + #error Unsupported RISC-V variant. + #endif #else #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" #endif #endif -// CIRCUITPY-CHANGE -// If MICROPY_NLR_SETJMP is not defined above - define/disable it here -#if !defined(MICROPY_NLR_SETJMP) - #define MICROPY_NLR_SETJMP (0) +// CIRCUITPY-CHANGE: Avoid warnings by defining all these MICROPY_PY_NLR_* macros +#ifndef MICROPY_NLR_AARCH64 +#define MICROPY_NLR_AARCH64 (0) +#endif + +#ifndef MICROPY_NLR_MIPS +#define MICROPY_NLR_MIPS (0) +#endif + +#ifndef MICROPY_NLR_OS_WINDOWS +#define MICROPY_NLR_OS_WINDOWS (0) +#endif + +#ifndef MICROPY_NLR_POWERPC +#define MICROPY_NLR_POWERPC (0) +#endif + +#ifndef MICROPY_NLR_RV32I +#define MICROPY_NLR_RV32I (0) +#endif + +#ifndef MICROPY_NLR_RV64I +#define MICROPY_NLR_RV64I (0) +#endif + +#ifndef MICROPY_NLR_SETJMP +#define MICROPY_NLR_SETJMP (0) +#endif + +#ifndef MICROPY_NLR_THUMB +#define MICROPY_NLR_THUMB (0) +#endif + +#ifndef MICROPY_NLR_X64 +#define MICROPY_NLR_X64 (0) +#endif + +#ifndef MICROPY_NLR_X86 +#define MICROPY_NLR_X86 (0) +#endif + +#ifndef MICROPY_NLR_XTENSA +#define MICROPY_NLR_XTENSA (0) #endif // *FORMAT-ON* diff --git a/py/nlraarch64.c b/py/nlraarch64.c index 898d9e2a76506..d6d87ebc50db8 100644 --- a/py/nlraarch64.c +++ b/py/nlraarch64.c @@ -26,8 +26,7 @@ #include "py/mpstate.h" // needed for NLR defs -// CIRCUITPY-CHANGE: avoid warnings -#if defined(MICROPY_NLR_AARCH64) && MICROPY_NLR_AARCH64 +#if MICROPY_NLR_AARCH64 // AArch64 callee-saved registers are x19-x29. // https://en.wikipedia.org/wiki/Calling_convention#ARM_(A64) diff --git a/py/nlrmips.c b/py/nlrmips.c index a60c3abd71487..cba52b16a266a 100644 --- a/py/nlrmips.c +++ b/py/nlrmips.c @@ -26,8 +26,7 @@ #include "py/mpstate.h" -// CIRCUITPY-CHANGE: avoid warning -#if defined(MICROPY_NLR_MIPS) && MICROPY_NLR_MIPS +#if MICROPY_NLR_MIPS __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); diff --git a/py/nlrpowerpc.c b/py/nlrpowerpc.c index ae2f92a078012..8a69fe1eeca6b 100644 --- a/py/nlrpowerpc.c +++ b/py/nlrpowerpc.c @@ -26,8 +26,7 @@ #include "py/mpstate.h" -// CIRCUITPY-CHANGE: avoid warning -#if defined(MICROPY_NLR_POWERPC) && MICROPY_NLR_POWERPC +#if MICROPY_NLR_POWERPC #undef nlr_push diff --git a/py/nlrrv32.c b/py/nlrrv32.c new file mode 100644 index 0000000000000..9a12ede400daa --- /dev/null +++ b/py/nlrrv32.c @@ -0,0 +1,81 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Alessandro Gatti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if MICROPY_NLR_RV32I + +#undef nlr_push + +__attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { + __asm volatile ( + "sw x1, 8(x10) \n" // Store RA. + "sw x8, 12(x10) \n" // Store S0. + "sw x9, 16(x10) \n" // Store S1. + "sw x18, 20(x10) \n" // Store S2. + "sw x19, 24(x10) \n" // Store S3. + "sw x20, 28(x10) \n" // Store S4. + "sw x21, 32(x10) \n" // Store S5. + "sw x22, 36(x10) \n" // Store S6. + "sw x23, 40(x10) \n" // Store S7. + "sw x24, 44(x10) \n" // Store S8. + "sw x25, 48(x10) \n" // Store S9. + "sw x26, 52(x10) \n" // Store S10. + "sw x27, 56(x10) \n" // Store S11. + "sw x2, 60(x10) \n" // Store SP. + "jal x0, nlr_push_tail \n" // Jump to the C part. + ); +} + +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + __asm volatile ( + "add x10, x0, %0 \n" // Load nlr_buf address. + "lw x1, 8(x10) \n" // Retrieve RA. + "lw x8, 12(x10) \n" // Retrieve S0. + "lw x9, 16(x10) \n" // Retrieve S1. + "lw x18, 20(x10) \n" // Retrieve S2. + "lw x19, 24(x10) \n" // Retrieve S3. + "lw x20, 28(x10) \n" // Retrieve S4. + "lw x21, 32(x10) \n" // Retrieve S5. + "lw x22, 36(x10) \n" // Retrieve S6. + "lw x23, 40(x10) \n" // Retrieve S7. + "lw x24, 44(x10) \n" // Retrieve S8. + "lw x25, 48(x10) \n" // Retrieve S9. + "lw x26, 52(x10) \n" // Retrieve S10. + "lw x27, 56(x10) \n" // Retrieve S11. + "lw x2, 60(x10) \n" // Retrieve SP. + "addi x10, x0, 1 \n" // Return 1 for a non-local return. + "jalr x0, x1, 0 \n" // Return. + : // Outputs. + : "r" (top) // Inputs. + : "memory" // Clobbered. + ); + + MP_UNREACHABLE +} + +#endif // MICROPY_NLR_RV32I diff --git a/py/nlrrv64.c b/py/nlrrv64.c new file mode 100644 index 0000000000000..e7ba79797b857 --- /dev/null +++ b/py/nlrrv64.c @@ -0,0 +1,81 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Alessandro Gatti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if MICROPY_NLR_RV64I + +#undef nlr_push + +__attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { + __asm volatile ( + "sd x1, 16(x10) \n" // Store RA. + "sd x8, 24(x10) \n" // Store S0. + "sd x9, 32(x10) \n" // Store S1. + "sd x18, 40(x10) \n" // Store S2. + "sd x19, 48(x10) \n" // Store S3. + "sd x20, 56(x10) \n" // Store S4. + "sd x21, 64(x10) \n" // Store S5. + "sd x22, 72(x10) \n" // Store S6. + "sd x23, 80(x10) \n" // Store S7. + "sd x24, 88(x10) \n" // Store S8. + "sd x25, 96(x10) \n" // Store S9. + "sd x26, 104(x10) \n" // Store S10. + "sd x27, 112(x10) \n" // Store S11. + "sd x2, 120(x10) \n" // Store SP. + "jal x0, nlr_push_tail \n" // Jump to the C part. + ); +} + +NORETURN void nlr_jump(void *val) { + MP_NLR_JUMP_HEAD(val, top) + __asm volatile ( + "add x10, x0, %0 \n" // Load nlr_buf address. + "ld x1, 16(x10) \n" // Retrieve RA. + "ld x8, 24(x10) \n" // Retrieve S0. + "ld x9, 32(x10) \n" // Retrieve S1. + "ld x18, 40(x10) \n" // Retrieve S2. + "ld x19, 48(x10) \n" // Retrieve S3. + "ld x20, 56(x10) \n" // Retrieve S4. + "ld x21, 64(x10) \n" // Retrieve S5. + "ld x22, 72(x10) \n" // Retrieve S6. + "ld x23, 80(x10) \n" // Retrieve S7. + "ld x24, 88(x10) \n" // Retrieve S8. + "ld x25, 96(x10) \n" // Retrieve S9. + "ld x26, 104(x10) \n" // Retrieve S10. + "ld x27, 112(x10) \n" // Retrieve S11. + "ld x2, 120(x10) \n" // Retrieve SP. + "addi x10, x0, 1 \n" // Return 1 for a non-local return. + "jalr x0, x1, 0 \n" // Return. + : // Outputs. + : "r" (top) // Inputs. + : "memory" // Clobbered. + ); + + MP_UNREACHABLE +} + +#endif // MICROPY_NLR_RV64I diff --git a/py/nlrthumb.c b/py/nlrthumb.c index de4d69eabd10f..0aa1f053a2397 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -26,8 +26,7 @@ #include "py/mpstate.h" -// CIRCUITPY-CHANGE: avoid warning -#if defined(MICROPY_NLR_THUMB) && MICROPY_NLR_THUMB +#if MICROPY_NLR_THUMB #undef nlr_push diff --git a/py/nlrx64.c b/py/nlrx64.c index 63586a2199fbd..d1ad91ff7d718 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -26,8 +26,7 @@ #include "py/mpstate.h" -// CIRCUITPY-CHANGE: avoid warning -#if defined(MICROPY_NLR_X64) && MICROPY_NLR_X64 +#if MICROPY_NLR_X64 #undef nlr_push diff --git a/py/nlrx86.c b/py/nlrx86.c index a2ce8424f9c56..085e30d2034a1 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -26,16 +26,14 @@ #include "py/mpstate.h" -// CIRCUITPY-CHANGE: avoid warning -#if defined(MICROPY_NLR_X86) && MICROPY_NLR_X86 +#if MICROPY_NLR_X86 #undef nlr_push // For reference, x86 callee save regs are: // ebx, esi, edi, ebp, esp, eip -// CIRCUITPY-CHANGE: avoid warning -#if defined(MICROPY_NLR_OS_WINDOWS) && MICROPY_NLR_OS_WINDOWS +#if MICROPY_NLR_OS_WINDOWS unsigned int nlr_push_tail(nlr_buf_t *nlr) asm ("nlr_push_tail"); #else __attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c index 62e799dbdca22..ff7af6edeef98 100644 --- a/py/nlrxtensa.c +++ b/py/nlrxtensa.c @@ -26,8 +26,7 @@ #include "py/mpstate.h" -// CIRCUITPY-CHANGE: avoid warning -#if defined(MICROPY_NLR_XTENSA) && MICROPY_NLR_XTENSA +#if MICROPY_NLR_XTENSA #undef nlr_push diff --git a/py/obj.c b/py/obj.c index 20554aaccefdf..29ae76557f8b5 100644 --- a/py/obj.c +++ b/py/obj.c @@ -39,7 +39,7 @@ // CIRCUITPY-CHANGE #include "py/qstr.h" #include "py/runtime.h" -#include "py/stackctrl.h" +#include "py/cstack.h" #include "py/stream.h" // for mp_obj_print // CIRCUITPY-CHANGE @@ -128,7 +128,7 @@ const char *mp_obj_get_type_str(mp_const_obj_t o_in) { void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { // There can be data structures nested too deep, or just recursive - MP_STACK_CHECK(); + mp_cstack_check(); // CIRCUITPY-CHANGE #ifdef RUN_BACKGROUND_TASKS RUN_BACKGROUND_TASKS; diff --git a/py/obj.h b/py/obj.h index 255a00b314f5e..1a7c3f60fb5ba 100644 --- a/py/obj.h +++ b/py/obj.h @@ -548,6 +548,9 @@ typedef mp_obj_t (*mp_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t); typedef mp_obj_t (*mp_fun_var_t)(size_t n, const mp_obj_t *); // mp_fun_kw_t takes mp_map_t* (and not const mp_map_t*) to ease passing // this arg to mp_map_lookup(). +// Note that the mp_obj_t* array will contain all arguments, positional and keyword, with the keyword +// ones starting at offset n, like: arg0 arg1 ... arg key0 value0 key1 value1 ..., and the mp_map_t* +// gets those same keyword arguments but as a map for convenience; see fun_builtin_var_call. typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *); // Flags for type behaviour (mp_obj_type_t.flags) @@ -885,6 +888,7 @@ extern const mp_obj_type_t mp_type_bound_meth; extern const mp_obj_type_t mp_type_property; extern const mp_obj_type_t mp_type_stringio; extern const mp_obj_type_t mp_type_bytesio; +extern const mp_obj_type_t mp_type_ringio; extern const mp_obj_type_t mp_type_reversed; extern const mp_obj_type_t mp_type_polymorph_iter; #if MICROPY_ENABLE_FINALISER @@ -1037,6 +1041,7 @@ mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, uns mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_str(const char *data, size_t len); // will check utf-8 (raises UnicodeError) +mp_obj_t mp_obj_new_str_from_cstr(const char *str); // // accepts null-terminated string, will check utf-8 (raises UnicodeError) mp_obj_t mp_obj_new_str_via_qstr(const char *data, size_t len); // input data must be valid utf-8 mp_obj_t mp_obj_new_str_from_vstr(vstr_t *vstr); // will check utf-8 (raises UnicodeError) #if MICROPY_PY_BUILTINS_STR_UNICODE && MICROPY_PY_BUILTINS_STR_UNICODE_CHECK @@ -1347,7 +1352,7 @@ bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte * bool mp_seq_cmp_objs(mp_uint_t op, const mp_obj_t *items1, size_t len1, const mp_obj_t *items2, size_t len2); mp_obj_t mp_seq_index_obj(const mp_obj_t *items, size_t len, size_t n_args, const mp_obj_t *args); mp_obj_t mp_seq_count_obj(const mp_obj_t *items, size_t len, mp_obj_t value); -mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes); +mp_obj_t mp_seq_extract_slice(const mp_obj_t *seq, mp_bound_slice_t *indexes); // Helper to clear stale pointers from allocated, but unused memory, to preclude GC problems #define mp_seq_clear(start, len, alloc_len, item_sz) memset((byte *)(start) + (len) * (item_sz), 0, ((alloc_len) - (len)) * (item_sz)) @@ -1362,6 +1367,8 @@ mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t memmove(((char *)dest) + (beg + slice_len) * (item_sz), ((char *)dest) + (end) * (item_sz), ((dest_len) + (len_adj) - ((beg) + (slice_len))) * (item_sz)); \ memmove(((char *)dest) + (beg) * (item_sz), slice, slice_len * (item_sz)); +#if !MICROPY_PREVIEW_VERSION_2 + // Provide translation for legacy API #define MP_OBJ_IS_SMALL_INT mp_obj_is_small_int #define MP_OBJ_IS_QSTR mp_obj_is_qstr @@ -1374,4 +1381,6 @@ mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t #define MP_MAP_SLOT_IS_FILLED mp_map_slot_is_filled #define MP_SET_SLOT_IS_FILLED mp_set_slot_is_filled +#endif + #endif // MICROPY_INCLUDED_PY_OBJ_H diff --git a/py/objarray.c b/py/objarray.c index f43a69cfb4d2c..0be1947167d6e 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -472,8 +472,9 @@ static mp_obj_t array_append(mp_obj_t self_in, mp_obj_t arg) { if (self->free == 0) { size_t item_sz = mp_binary_get_size('@', self->typecode, NULL); // TODO: alloc policy - self->free = 8; - self->items = m_renew(byte, self->items, item_sz * self->len, item_sz * (self->len + self->free)); + size_t add_cnt = 8; + self->items = m_renew(byte, self->items, item_sz * self->len, item_sz * (self->len + add_cnt)); + self->free = add_cnt; mp_seq_clear(self->items, self->len + 1, self->len + self->free, item_sz); } mp_binary_set_val_array(self->typecode, self->items, self->len, arg); diff --git a/py/objdeque.c b/py/objdeque.c index 2edb6908f0b4c..264c795801ba4 100644 --- a/py/objdeque.c +++ b/py/objdeque.c @@ -209,7 +209,7 @@ static mp_obj_t deque_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { size_t offset = mp_get_index(self->base.type, deque_len(self), index, false); size_t index_val = self->i_get + offset; - if (index_val > self->alloc) { + if (index_val >= self->alloc) { index_val -= self->alloc; } @@ -264,7 +264,7 @@ static MP_DEFINE_CONST_DICT(deque_locals_dict, deque_locals_dict_table); MP_DEFINE_CONST_OBJ_TYPE( mp_type_deque, MP_QSTR_deque, - MP_TYPE_FLAG_ITER_IS_GETITER, + DEQUE_TYPE_FLAGS, make_new, deque_make_new, unary_op, deque_unary_op, DEQUE_TYPE_SUBSCR diff --git a/py/objfloat.c b/py/objfloat.c index fa5a26b438b45..3610c2b85862d 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -51,6 +51,13 @@ #define M_PI (3.14159265358979323846) #endif +// Workaround a bug in recent MSVC where NAN is no longer constant. +// (By redefining back to the previous MSVC definition of NAN) +#if defined(_MSC_VER) && _MSC_VER >= 1942 +#undef NAN +#define NAN (-(float)(((float)(1e+300 * 1e+300)) * 0.0F)) +#endif + typedef struct _mp_obj_float_t { mp_obj_base_t base; mp_float_t value; diff --git a/py/objfun.c b/py/objfun.c index a552c5531b0e5..6e635a43418b3 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -32,7 +32,7 @@ #include "py/objfun.h" #include "py/runtime.h" #include "py/bc.h" -#include "py/stackctrl.h" +#include "py/cstack.h" #if MICROPY_DEBUG_VERBOSE // print debugging info #define DEBUG_PRINT (1) @@ -110,7 +110,9 @@ static mp_obj_t fun_builtin_var_call(mp_obj_t self_in, size_t n_args, size_t n_k if (self->sig & 1) { // function allows keywords - // we create a map directly from the given args array + // we create a map directly from the given args array; self->fun.kw does still + // expect args to have both positional and keyword arguments, ordered as: + // arg0 arg1 ... arg key0 value0 key1 value1 ... key value mp_map_t kw_args; mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); @@ -197,7 +199,7 @@ static void dump_args(const mp_obj_t *a, size_t sz) { #if MICROPY_STACKLESS mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - MP_STACK_CHECK(); + mp_cstack_check(); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); size_t n_state, state_size; @@ -229,7 +231,7 @@ mp_code_state_t *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, size_t n_args // CIRCUITPY-CHANGE: PLACE_IN_ITCM static mp_obj_t PLACE_IN_ITCM(fun_bc_call)(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - MP_STACK_CHECK(); + mp_cstack_check(); DEBUG_printf("Input n_args: " UINT_FMT ", n_kw: " UINT_FMT "\n", n_args, n_kw); DEBUG_printf("Input pos args: "); @@ -402,7 +404,7 @@ mp_obj_t mp_obj_new_fun_bc(const mp_obj_t *def_args, const byte *code, const mp_ // CIRCUITPY-CHANGE: PLACE_IN_ITCM static mp_obj_t PLACE_IN_ITCM(fun_native_call)(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - MP_STACK_CHECK(); + mp_cstack_check(); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); mp_call_fun_t fun = mp_obj_fun_native_get_function_start(self); return fun(self_in, n_args, n_kw, args); @@ -436,7 +438,7 @@ MP_DEFINE_CONST_OBJ_TYPE( #if MICROPY_EMIT_NATIVE static mp_obj_t fun_viper_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - MP_STACK_CHECK(); + mp_cstack_check(); mp_obj_fun_bc_t *self = MP_OBJ_TO_PTR(self_in); mp_call_fun_t fun = MICROPY_MAKE_POINTER_CALLABLE((void *)self->bytecode); return fun(self_in, n_args, n_kw, args); diff --git a/py/objgenerator.c b/py/objgenerator.c index fa59313998f4d..de063d384587d 100644 --- a/py/objgenerator.c +++ b/py/objgenerator.c @@ -33,7 +33,7 @@ #include "py/objstr.h" #include "py/objgenerator.h" #include "py/objfun.h" -#include "py/stackctrl.h" +#include "py/cstack.h" // Instance of GeneratorExit exception - needed by generator.close() // CIRCUITPY-CHANGE: https://github.com/adafruit/circuitpython/pull/7069 fix @@ -205,7 +205,7 @@ static void coro_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_pr #endif mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) { - MP_STACK_CHECK(); + mp_cstack_check(); // CIRCUITPY-CHANGE // note that self may have as its type either gen or coro, // both of which are stored as an mp_obj_gen_instance_t . diff --git a/py/objint.c b/py/objint.c index cc7a77451764b..bf5b677df3be8 100644 --- a/py/objint.c +++ b/py/objint.c @@ -308,7 +308,7 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_signed) { if (is_signed) { // self must be < 2**(bits - 1) - mp_obj_t edge = mp_binary_op(MP_BINARY_OP_INPLACE_LSHIFT, + mp_obj_t edge = mp_binary_op(MP_BINARY_OP_LSHIFT, mp_obj_new_int(1), mp_obj_new_int(nbytes * 8 - 1)); @@ -323,7 +323,7 @@ void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_s // self must be >= 0 if (mp_obj_int_sign(self_in) >= 0) { // and < 2**(bits) - mp_obj_t edge = mp_binary_op(MP_BINARY_OP_INPLACE_LSHIFT, + mp_obj_t edge = mp_binary_op(MP_BINARY_OP_LSHIFT, mp_obj_new_int(1), mp_obj_new_int(nbytes * 8)); @@ -536,7 +536,7 @@ static MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, MP_ROM_PTR(&int_from_ static mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_length, ARG_byteorder, ARG_signed }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_length, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_length, MP_ARG_INT, {.u_int = 1} }, // CIRCUITPY-CHANGE: not required and given a default value. { MP_QSTR_byteorder, MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_QSTR(MP_QSTR_big)} }, { MP_QSTR_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, @@ -578,8 +578,7 @@ static mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t * return mp_obj_new_bytes_from_vstr(&vstr); } -// CIRCUITPY-CHANGE: only two required args. -static MP_DEFINE_CONST_FUN_OBJ_KW(int_to_bytes_obj, 2, int_to_bytes); +static MP_DEFINE_CONST_FUN_OBJ_KW(int_to_bytes_obj, 1, int_to_bytes); static const mp_rom_map_elem_t int_locals_dict_table[] = { // CIRCUITPY-CHANGE diff --git a/py/objint.h b/py/objint.h index b081d6590517a..92466bae4e26e 100644 --- a/py/objint.h +++ b/py/objint.h @@ -64,7 +64,8 @@ mp_int_t mp_obj_int_hash(mp_obj_t self_in); // CIRCUITPY-CHANGE mp_obj_t mp_obj_int_bit_length_impl(mp_obj_t self_in); mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf); -void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf); +// Returns true if 'self_in' fit into 'len' bytes of 'buf' without overflowing, 'buf' is truncated otherwise. +bool mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf); int mp_obj_int_sign(mp_obj_t self_in); mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in); mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in); diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 70d7e2873c55f..0fad693c7adcd 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -69,10 +69,27 @@ mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf return mp_obj_new_int_from_ll(value); } -void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { +bool mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { assert(mp_obj_is_exact_type(self_in, &mp_type_int)); mp_obj_int_t *self = self_in; long long val = self->val; + size_t slen; // Number of bytes to represent val + + // This logic has a twin in objint.c + if (val > 0) { + slen = (sizeof(long long) * 8 - mp_clzll(val) + 7) / 8; + } else if (val < -1) { + slen = (sizeof(long long) * 8 - mp_clzll(~val) + 8) / 8; + } else { + // clz of 0 is defined, so 0 and -1 map to 0 and 1 + slen = -val; + } + + if (slen > len) { + return false; // Would overflow + // TODO: Determine whether to copy and truncate, as some callers probably expect this...? + } + if (big_endian) { byte *b = buf + len; while (b > buf) { @@ -85,6 +102,7 @@ void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byt val >>= 8; } } + return true; } int mp_obj_int_sign(mp_obj_t self_in) { @@ -241,25 +259,21 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i } mp_obj_t mp_obj_new_int(mp_int_t value) { - if (MP_SMALL_INT_FITS(value)) { - return MP_OBJ_NEW_SMALL_INT(value); - } return mp_obj_new_int_from_ll(value); } mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { - // SMALL_INT accepts only signed numbers, so make sure the input - // value fits completely in the small-int positive range. - if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { - return MP_OBJ_NEW_SMALL_INT(value); - } return mp_obj_new_int_from_ll(value); } mp_obj_t mp_obj_new_int_from_ll(long long val) { + if ((long long)(mp_int_t)val == val && MP_SMALL_INT_FITS(val)) { + return MP_OBJ_NEW_SMALL_INT(val); + } + mp_obj_int_t *o = mp_obj_malloc(mp_obj_int_t, &mp_type_int); o->val = val; - return o; + return MP_OBJ_FROM_PTR(o); } mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { @@ -267,19 +281,16 @@ mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { if (val >> (sizeof(unsigned long long) * 8 - 1) != 0) { mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("ulonglong too large")); } - mp_obj_int_t *o = mp_obj_malloc(mp_obj_int_t, &mp_type_int); - o->val = val; - return o; + return mp_obj_new_int_from_ll(val); } mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated // TODO check overflow - mp_obj_int_t *o = mp_obj_malloc(mp_obj_int_t, &mp_type_int); char *endptr; - o->val = strtoll(*str, &endptr, base); + mp_obj_t result = mp_obj_new_int_from_ll(strtoll(*str, &endptr, base)); *str = endptr; - return o; + return result; } mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 7bdeb364d8714..111f53009fb1f 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -119,10 +119,10 @@ mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf return MP_OBJ_FROM_PTR(o); } -void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { +bool mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { assert(mp_obj_is_exact_type(self_in, &mp_type_int)); mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); - mpz_as_bytes(&self->mpz, big_endian, len, buf); + return mpz_as_bytes(&self->mpz, big_endian, self->mpz.neg, len, buf); } int mp_obj_int_sign(mp_obj_t self_in) { @@ -320,6 +320,14 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return MP_OBJ_NULL; // op not supported } + // Check if the result fits in a small-int, and if so just return that. + mp_int_t res_small; + if (mpz_as_int_checked(&res->mpz, &res_small)) { + if (MP_SMALL_INT_FITS(res_small)) { + return MP_OBJ_NEW_SMALL_INT(res_small); + } + } + return MP_OBJ_FROM_PTR(res); } else { @@ -438,6 +446,10 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { const mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t value; if (mpz_as_int_checked(&self->mpz, &value)) { + // mp_obj_int_t objects should always contain a value that is a large + // integer (if the value fits in a small-int then it should have been + // converted to a small-int object), and so this code-path should never + // be taken in normal circumstances. return value; } else { // overflow diff --git a/py/objlist.c b/py/objlist.c index d0b6fd4b3e47e..3137e9fa53483 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -29,7 +29,7 @@ #include "py/objlist.h" #include "py/runtime.h" -#include "py/stackctrl.h" +#include "py/cstack.h" static mp_obj_t mp_obj_new_list_iterator(mp_obj_t list, size_t cur, mp_obj_iter_buf_t *iter_buf); static mp_obj_list_t *list_new(size_t n); @@ -201,7 +201,7 @@ static mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { - return mp_seq_extract_slice(self->len, self->items, &slice); + return mp_seq_extract_slice(self->items, &slice); } mp_obj_list_t *res = list_new(slice.stop - slice.start); mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); @@ -312,7 +312,7 @@ static mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { } static void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj_t binop_less_result) { - MP_STACK_CHECK(); + mp_cstack_check(); while (head < tail) { mp_obj_t *h = head - 1; mp_obj_t *t = tail; diff --git a/py/objrange.c b/py/objrange.c index 8793040eab095..bde2ebaabb4ed 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -33,7 +33,6 @@ typedef struct _mp_obj_range_it_t { mp_obj_base_t base; - // TODO make these values generic objects or something mp_int_t cur; mp_int_t stop; mp_int_t step; @@ -72,7 +71,6 @@ static mp_obj_t mp_obj_new_range_iterator(mp_int_t cur, mp_int_t stop, mp_int_t typedef struct _mp_obj_range_t { mp_obj_base_t base; - // TODO make these values generic objects or something mp_int_t start; mp_int_t stop; mp_int_t step; diff --git a/py/objringio.c b/py/objringio.c new file mode 100644 index 0000000000000..ba1ec25307ea4 --- /dev/null +++ b/py/objringio.c @@ -0,0 +1,130 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Andrew Leech + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "ringbuf.h" +#include "py/mpconfig.h" + +#if MICROPY_PY_MICROPYTHON_RINGIO + +#include "py/runtime.h" +#include "py/stream.h" + +typedef struct _micropython_ringio_obj_t { + mp_obj_base_t base; + ringbuf_t ringbuffer; +} micropython_ringio_obj_t; + +static mp_obj_t micropython_ringio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + mp_int_t buff_size = -1; + mp_buffer_info_t bufinfo = {NULL, 0, 0}; + + if (!mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) { + buff_size = mp_obj_get_int(args[0]); + } + micropython_ringio_obj_t *self = mp_obj_malloc(micropython_ringio_obj_t, type); + if (bufinfo.buf != NULL) { + // buffer passed in, use it directly for ringbuffer. + self->ringbuffer.buf = bufinfo.buf; + self->ringbuffer.size = bufinfo.len; + self->ringbuffer.iget = self->ringbuffer.iput = 0; + } else { + // Allocate new buffer, add one extra to buff_size as ringbuf consumes one byte for tracking. + ringbuf_alloc(&(self->ringbuffer), buff_size + 1); + } + return MP_OBJ_FROM_PTR(self); +} + +static mp_uint_t micropython_ringio_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { + micropython_ringio_obj_t *self = MP_OBJ_TO_PTR(self_in); + size = MIN(size, ringbuf_avail(&self->ringbuffer)); + ringbuf_memcpy_get_internal(&(self->ringbuffer), buf_in, size); + *errcode = 0; + return size; +} + +static mp_uint_t micropython_ringio_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { + micropython_ringio_obj_t *self = MP_OBJ_TO_PTR(self_in); + size = MIN(size, ringbuf_free(&self->ringbuffer)); + ringbuf_memcpy_put_internal(&(self->ringbuffer), buf_in, size); + *errcode = 0; + return size; +} + +static mp_uint_t micropython_ringio_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + micropython_ringio_obj_t *self = MP_OBJ_TO_PTR(self_in); + switch (request) { + case MP_STREAM_POLL: { + mp_uint_t ret = 0; + if ((arg & MP_STREAM_POLL_RD) && ringbuf_avail(&self->ringbuffer) > 0) { + ret |= MP_STREAM_POLL_RD; + } + if ((arg & MP_STREAM_POLL_WR) && ringbuf_free(&self->ringbuffer) > 0) { + ret |= MP_STREAM_POLL_WR; + } + return ret; + } + case MP_STREAM_CLOSE: + return 0; + } + *errcode = MP_EINVAL; + return MP_STREAM_ERROR; +} + +static mp_obj_t micropython_ringio_any(mp_obj_t self_in) { + micropython_ringio_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(ringbuf_avail(&self->ringbuffer)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(micropython_ringio_any_obj, micropython_ringio_any); + +static const mp_rom_map_elem_t micropython_ringio_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(µpython_ringio_any_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + +}; +static MP_DEFINE_CONST_DICT(micropython_ringio_locals_dict, micropython_ringio_locals_dict_table); + +static const mp_stream_p_t ringio_stream_p = { + .read = micropython_ringio_read, + .write = micropython_ringio_write, + .ioctl = micropython_ringio_ioctl, + .is_text = false, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + mp_type_ringio, + MP_QSTR_RingIO, + MP_TYPE_FLAG_NONE, + make_new, micropython_ringio_make_new, + protocol, &ringio_stream_p, + locals_dict, µpython_ringio_locals_dict + ); + +#endif // MICROPY_PY_MICROPYTHON_RINGIO diff --git a/py/objstr.c b/py/objstr.c index 342affb514dd4..d1e0d58b6ef10 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -32,7 +32,7 @@ #include "py/objstr.h" #include "py/objlist.h" #include "py/runtime.h" -#include "py/stackctrl.h" +#include "py/cstack.h" // CIRCUITPY-CHANGE const char nibble_to_hex_upper[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', @@ -1202,7 +1202,7 @@ static vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar // type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%" // recursively call the formatter to format any nested specifiers - MP_STACK_CHECK(); + mp_cstack_check(); vstr_t format_spec_vstr = mp_obj_str_format_helper(format_spec, str, arg_i, n_args, args, kwargs); const char *s = vstr_null_terminated_str(&format_spec_vstr); const char *stop = s + format_spec_vstr.len; @@ -1503,8 +1503,7 @@ static mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ // Dictionary value lookup if (*str == '(') { if (dict == MP_OBJ_NULL) { - // CIRCUITPY-CHANGE: clearer message - mp_raise_TypeError(MP_ERROR_TEXT("format requires a dict")); + mp_raise_TypeError(MP_ERROR_TEXT("format needs a dict")); } arg_i = 1; // we used up the single dict argument const byte *key = ++str; @@ -1585,8 +1584,7 @@ static mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ if (arg == MP_OBJ_NULL) { if (arg_i >= n_args) { not_enough_args: - // CIRCUITPY-CHANGE: clearer message - mp_raise_TypeError(MP_ERROR_TEXT("not enough arguments for format string")); + mp_raise_TypeError(MP_ERROR_TEXT("format string needs more arguments")); } arg = args[arg_i++]; } @@ -1596,16 +1594,14 @@ static mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ size_t slen; const char *s = mp_obj_str_get_data(arg, &slen); if (slen != 1) { - // CIRCUITPY-CHANGE: clearer message - mp_raise_TypeError(MP_ERROR_TEXT("%%c requires int or char")); + mp_raise_TypeError(MP_ERROR_TEXT("%%c needs int or char")); } mp_print_strn(&print, s, 1, flags, ' ', width); } else if (arg_looks_integer(arg)) { char ch = mp_obj_get_int(arg); mp_print_strn(&print, &ch, 1, flags, ' ', width); } else { - // CIRCUITPY-CHANGE: clearer message - mp_raise_TypeError(MP_ERROR_TEXT("%%c requires int or char")); + mp_raise_TypeError(MP_ERROR_TEXT("%%c needs int or char")); } break; @@ -1677,8 +1673,7 @@ static mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ if (dict == MP_OBJ_NULL && arg_i != n_args) { // NOTE: if `dict` exists, then `n_args` is 1 and the dict is always consumed; either // positionally, or as a map of named args, even if none were actually referenced. - // CIRCUITPY-CHANGE: clearer message - mp_raise_TypeError(MP_ERROR_TEXT("not all arguments converted during string formatting")); + mp_raise_TypeError(MP_ERROR_TEXT("format string didn't convert all arguments")); } return mp_obj_new_str_type_from_vstr(is_bytes ? &mp_type_bytes : &mp_type_str, &vstr); @@ -2044,27 +2039,21 @@ mp_obj_t mp_obj_bytes_fromhex(mp_obj_t type_in, mp_obj_t data) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(data, &bufinfo, MP_BUFFER_READ); - if ((bufinfo.len & 1) != 0) { - mp_raise_ValueError(MP_ERROR_TEXT("odd-length string")); - } vstr_t vstr; vstr_init_len(&vstr, bufinfo.len / 2); byte *in = bufinfo.buf, *out = (byte *)vstr.buf; - byte hex_byte = 0; - for (mp_uint_t i = bufinfo.len; i--;) { - byte hex_ch = *in++; - if (unichar_isxdigit(hex_ch)) { - hex_byte += unichar_xdigit_value(hex_ch); - } else { - mp_raise_ValueError(MP_ERROR_TEXT("non-hex digit found")); + byte *in_end = in + bufinfo.len; + mp_uint_t ch1, ch2; + while (in < in_end) { + if (unichar_isspace(ch1 = *in++)) { + continue; // Skip whitespace between hex digit pairs } - if (i & 1) { - hex_byte <<= 4; - } else { - *out++ = hex_byte; - hex_byte = 0; + if (in == in_end || !unichar_isxdigit(ch1) || !unichar_isxdigit(ch2 = *in++)) { + mp_raise_ValueError(MP_ERROR_TEXT("non-hex digit")); } + *out++ = (byte)((unichar_xdigit_value(ch1) << 4) | unichar_xdigit_value(ch2)); } + vstr.len = out - (byte *)vstr.buf; // Length may be shorter due to whitespace in input return mp_obj_new_str_type_from_vstr(MP_OBJ_TO_PTR(type_in), &vstr); } @@ -2342,6 +2331,10 @@ mp_obj_t mp_obj_new_str(const char *data, size_t len) { } } +mp_obj_t mp_obj_new_str_from_cstr(const char *str) { + return mp_obj_new_str(str, strlen(str)); +} + mp_obj_t mp_obj_str_intern(mp_obj_t str) { GET_STR_DATA_LEN(str, data, len); return mp_obj_new_str_via_qstr((const char *)data, len); diff --git a/py/objtype.c b/py/objtype.c index 6def4a4bfd4de..074d6f39293db 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -44,6 +44,7 @@ #define ENABLE_SPECIAL_ACCESSORS \ (MICROPY_PY_DESCRIPTORS || MICROPY_PY_DELATTR_SETATTR || MICROPY_PY_BUILTINS_PROPERTY) +static mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo); static mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); /******************************************************************************/ @@ -83,7 +84,7 @@ static int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_t } // CIRCUITPY-CHANGE: support superclass constructors that take kw args -// This wrapper function is allows a subclass of a native type to call the +// This wrapper function allows a subclass of a native type to call the // __init__() method (corresponding to type->make_new) of the native type. static mp_obj_t native_base_init_wrapper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_instance_t *self = MP_OBJ_TO_PTR(pos_args[0]); @@ -688,6 +689,13 @@ static void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des // try __getattr__ if (attr != MP_QSTR___getattr__) { + #if MICROPY_PY_DESCRIPTORS + // With descriptors enabled, don't delegate lookups of __get__/__set__/__delete__. + if (attr == MP_QSTR___get__ || attr == MP_QSTR___set__ || attr == MP_QSTR___delete__) { + return; + } + #endif + #if MICROPY_PY_DELATTR_SETATTR // If the requested attr is __setattr__/__delattr__ then don't delegate the lookup // to __getattr__. If we followed CPython's behaviour then __setattr__/__delattr__ @@ -907,7 +915,8 @@ mp_obj_t mp_obj_instance_call(mp_obj_t self_in, size_t n_args, size_t n_kw, cons #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE mp_raise_TypeError(MP_ERROR_TEXT("object not callable")); #else - mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not callable"), + // CIRCUITPY-CHANGE: use more specific raise + mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object isn't callable"), mp_obj_get_type_qstr(self_in)); #endif } @@ -1034,11 +1043,10 @@ static mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp if (!MP_OBJ_TYPE_HAS_SLOT(self, make_new)) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE - // CIRCUITPY-CHANGE: error message change mp_raise_TypeError(MP_ERROR_TEXT("cannot create instance")); #else - // CIRCUITPY-CHANGE: error message change - mp_raise_TypeError_varg(MP_ERROR_TEXT("cannot create '%q' instances"), self->name); + // CIRCUITPY-CHANGE: more specific mp_raise + mp_raise_TypeError_varg(MP_ERROR_TEXT("can't create '%q' instances"), self->name); #endif } @@ -1179,12 +1187,11 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) // TODO: Verify with CPy, tested on function type if (!MP_OBJ_TYPE_HAS_SLOT(t, make_new)) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE - // CIRCUITPY-CHANGE: error message change - mp_raise_TypeError(MP_ERROR_TEXT("type is not an acceptable base type")); + mp_raise_TypeError(MP_ERROR_TEXT("type isn't an acceptable base type")); #else - // CIRCUITPY-CHANGE: error message change + // CIRCUITPY-CHANGE: more specific mp_raise mp_raise_TypeError_varg( - MP_ERROR_TEXT("type '%q' is not an acceptable base type"), t->name); + MP_ERROR_TEXT("type '%q' isn't an acceptable base type"), t->name); #endif } #if ENABLE_SPECIAL_ACCESSORS @@ -1194,6 +1201,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) base_flags |= t->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS; if (mp_obj_is_instance_type(t)) { t->flags |= MP_TYPE_FLAG_IS_SUBCLASSED; + base_flags |= t->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS; } #endif } @@ -1302,10 +1310,20 @@ static mp_obj_t super_make_new(const mp_obj_type_t *type_in, size_t n_args, size // 0 arguments are turned into 2 in the compiler // 1 argument is not yet implemented mp_arg_check_num(n_args, n_kw, 2, 2, false); + + // CIRCUITPY-CHANGE: check type of first arg if (!mp_obj_is_type(args[0], &mp_type_type)) { - // CIRCUITPY-CHANGE: error message mp_raise_TypeError(MP_ERROR_TEXT("first argument to super() must be type")); } + + // Per CPython: "If the second argument is an object, isinstance(obj, type) must be true. + // If the second argument is a type, issubclass(type2, type) must be true (this is useful for classmethods)." + const mp_obj_type_t *second_arg_type = mp_obj_get_type(args[1]); + mp_obj_t second_arg_obj = second_arg_type == &mp_type_type ? args[1] : MP_OBJ_FROM_PTR(second_arg_type); + if (mp_obj_is_subclass(second_arg_obj, args[0]) == mp_const_false) { + mp_raise_TypeError(NULL); + } + mp_obj_super_t *o = m_new_obj(mp_obj_super_t); *o = (mp_obj_super_t) {{type_in}, args[0], args[1]}; return MP_OBJ_FROM_PTR(o); diff --git a/py/parse.c b/py/parse.c index 9721532afd6eb..a393b0ee8c153 100644 --- a/py/parse.c +++ b/py/parse.c @@ -653,12 +653,6 @@ static const mp_rom_map_elem_t mp_constants_table[] = { static MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table); #endif -// CIRCUITPY-CHANGE: avoid compiler warning -#if defined(MICROPY_COMP_CONST_FOLDING_COMPILER_WORKAROUND) && MICROPY_COMP_CONST_FOLDING_COMPILER_WORKAROUND -// Some versions of the xtensa-esp32-elf-gcc compiler generate wrong code if this -// function is static, so provide a hook for them to work around this problem. -MP_NOINLINE -#endif static bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *num_args) { if (rule_id == RULE_or_test || rule_id == RULE_and_test) { @@ -1378,9 +1372,6 @@ mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) { } else if (lex->tok_kind == MP_TOKEN_MALFORMED_FSTRING) { exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, MP_ERROR_TEXT("malformed f-string")); - } else if (lex->tok_kind == MP_TOKEN_FSTRING_RAW) { - exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, - MP_ERROR_TEXT("raw f-strings are not supported")); #endif } else { exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, diff --git a/py/persistentcode.c b/py/persistentcode.c index 09beeef4518db..692d8f5dd6cfe 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -72,6 +72,20 @@ typedef struct _bytecode_prelude_t { static int read_byte(mp_reader_t *reader); static size_t read_uint(mp_reader_t *reader); +#if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA + +// An mp_obj_list_t that tracks native text/BSS/rodata to prevent the GC from reclaiming them. +MP_REGISTER_ROOT_POINTER(mp_obj_t persistent_code_root_pointers); + +static void track_root_pointer(void *ptr) { + if (MP_STATE_PORT(persistent_code_root_pointers) == MP_OBJ_NULL) { + MP_STATE_PORT(persistent_code_root_pointers) = mp_obj_new_list(0, NULL); + } + mp_obj_list_append(MP_STATE_PORT(persistent_code_root_pointers), MP_OBJ_FROM_PTR(ptr)); +} + +#endif + #if MICROPY_EMIT_MACHINE_CODE typedef struct _reloc_info_t { @@ -306,11 +320,10 @@ static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *co read_bytes(reader, rodata, rodata_size); } - // Viper code with BSS/rodata should not have any children. - // Reuse the children pointer to reference the BSS/rodata - // memory so that it is not reclaimed by the GC. - assert(!has_children); - children = (void *)data; + #if MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA + // Track the BSS/rodata memory so it's not reclaimed by the GC. + track_root_pointer(data); + #endif } } #endif @@ -358,16 +371,9 @@ static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *co fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len, opt_ri); #else if (native_scope_flags & MP_SCOPE_FLAG_VIPERRELOC) { - #if MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE - // If native code needs relocations then it's not guaranteed that a pointer to - // the head of `buf` (containing the machine code) will be retained for the GC - // to trace. This is because native functions can start inside `buf` and so - // it's possible that the only GC-reachable pointers are pointers inside `buf`. - // So put this `buf` on a list of reachable root pointers. - if (MP_STATE_PORT(track_reloc_code_list) == MP_OBJ_NULL) { - MP_STATE_PORT(track_reloc_code_list) = mp_obj_new_list(0, NULL); - } - mp_obj_list_append(MP_STATE_PORT(track_reloc_code_list), MP_OBJ_FROM_PTR(fun_data)); + #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA + // Track the function data memory so it's not reclaimed by the GC. + track_root_pointer(fun_data); #endif // Do the relocations. mp_native_relocate(&ri, fun_data, (uintptr_t)fun_data); @@ -671,8 +677,3 @@ void mp_raw_code_save_file(mp_compiled_module_t *cm, qstr filename) { #endif // MICROPY_PERSISTENT_CODE_SAVE_FILE #endif // MICROPY_PERSISTENT_CODE_SAVE - -#if MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE -// An mp_obj_list_t that tracks relocated native code to prevent the GC from reclaiming them. -MP_REGISTER_ROOT_POINTER(mp_obj_t track_reloc_code_list); -#endif diff --git a/py/persistentcode.h b/py/persistentcode.h index d2b310f241f8d..f0b7f70f7d7fa 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -71,6 +71,8 @@ #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSA) #elif MICROPY_EMIT_XTENSAWIN #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_XTENSAWIN) +#elif MICROPY_EMIT_RV32 + #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_RV32IMC) #else #define MPY_FEATURE_ARCH (MP_NATIVE_ARCH_NONE) #endif @@ -95,6 +97,8 @@ enum { MP_NATIVE_ARCH_ARMV7EMDP, MP_NATIVE_ARCH_XTENSA, MP_NATIVE_ARCH_XTENSAWIN, + MP_NATIVE_ARCH_RV32IMC, + MP_NATIVE_ARCH_DEBUG, // this entry should always be last }; enum { diff --git a/py/py.cmake b/py/py.cmake index 1cbbe08f0136f..d7f4ffe6df62b 100644 --- a/py/py.cmake +++ b/py/py.cmake @@ -9,6 +9,7 @@ set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/argcheck.c ${MICROPY_PY_DIR}/asmarm.c ${MICROPY_PY_DIR}/asmbase.c + ${MICROPY_PY_DIR}/asmrv32.c ${MICROPY_PY_DIR}/asmthumb.c ${MICROPY_PY_DIR}/asmx64.c ${MICROPY_PY_DIR}/asmx86.c @@ -19,12 +20,15 @@ set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/builtinhelp.c ${MICROPY_PY_DIR}/builtinimport.c ${MICROPY_PY_DIR}/compile.c + ${MICROPY_PY_DIR}/cstack.c ${MICROPY_PY_DIR}/emitbc.c ${MICROPY_PY_DIR}/emitcommon.c ${MICROPY_PY_DIR}/emitglue.c ${MICROPY_PY_DIR}/emitinlinethumb.c ${MICROPY_PY_DIR}/emitinlinextensa.c ${MICROPY_PY_DIR}/emitnarm.c + ${MICROPY_PY_DIR}/emitndebug.c + ${MICROPY_PY_DIR}/emitnrv32.c ${MICROPY_PY_DIR}/emitnthumb.c ${MICROPY_PY_DIR}/emitnx64.c ${MICROPY_PY_DIR}/emitnx86.c @@ -55,6 +59,8 @@ set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/nlr.c ${MICROPY_PY_DIR}/nlrmips.c ${MICROPY_PY_DIR}/nlrpowerpc.c + ${MICROPY_PY_DIR}/nlrrv32.c + ${MICROPY_PY_DIR}/nlrrv64.c ${MICROPY_PY_DIR}/nlrsetjmp.c ${MICROPY_PY_DIR}/nlrthumb.c ${MICROPY_PY_DIR}/nlrx64.c @@ -90,6 +96,7 @@ set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/objproperty.c ${MICROPY_PY_DIR}/objrange.c ${MICROPY_PY_DIR}/objreversed.c + ${MICROPY_PY_DIR}/objringio.c ${MICROPY_PY_DIR}/objset.c ${MICROPY_PY_DIR}/objsingleton.c ${MICROPY_PY_DIR}/objslice.c diff --git a/py/py.mk b/py/py.mk index bb5d8d2e91b95..67c51bff9f971 100644 --- a/py/py.mk +++ b/py/py.mk @@ -39,9 +39,10 @@ ifneq ($(USER_C_MODULES),) # C/C++ files that are included in the QSTR/module build SRC_USERMOD_C := SRC_USERMOD_CXX := -# Other C/C++ files (e.g. libraries or helpers) +# Other C/C++/Assembly files (e.g. libraries or helpers) SRC_USERMOD_LIB_C := SRC_USERMOD_LIB_CXX := +SRC_USERMOD_LIB_ASM := # Optionally set flags CFLAGS_USERMOD := CXXFLAGS_USERMOD := @@ -63,6 +64,7 @@ SRC_USERMOD_PATHFIX_C += $(patsubst $(USER_C_MODULES)/%.c,%.c,$(SRC_USERMOD_C)) SRC_USERMOD_PATHFIX_CXX += $(patsubst $(USER_C_MODULES)/%.cpp,%.cpp,$(SRC_USERMOD_CXX)) SRC_USERMOD_PATHFIX_LIB_C += $(patsubst $(USER_C_MODULES)/%.c,%.c,$(SRC_USERMOD_LIB_C)) SRC_USERMOD_PATHFIX_LIB_CXX += $(patsubst $(USER_C_MODULES)/%.cpp,%.cpp,$(SRC_USERMOD_LIB_CXX)) +SRC_USERMOD_PATHFIX_LIB_ASM += $(patsubst $(USER_C_MODULES)/%.S,%.S,$(SRC_USERMOD_LIB_ASM)) CFLAGS += $(CFLAGS_USERMOD) CXXFLAGS += $(CXXFLAGS_USERMOD) @@ -100,6 +102,8 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ nlrmips.o \ nlrpowerpc.o \ nlrxtensa.o \ + nlrrv32.o \ + nlrrv64.o \ nlrsetjmp.o \ malloc.o \ gc.o \ @@ -131,6 +135,9 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ emitnxtensa.o \ emitinlinextensa.o \ emitnxtensawin.o \ + asmrv32.o \ + emitnrv32.o \ + emitndebug.o \ formatfloat.o \ parsenumbase.o \ parsenum.o \ @@ -143,6 +150,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ nativeglue.o \ pairheap.o \ ringbuf.o \ + cstack.o \ stackctrl.o \ argcheck.o \ warning.o \ diff --git a/py/repl.c b/py/repl.c index ed47dbd0c174a..c9a20305c79ff 100644 --- a/py/repl.c +++ b/py/repl.c @@ -244,7 +244,6 @@ static void print_completions(const mp_print_t *print, gap += WORD_SLOT_LEN; } if (line_len + gap + d_len <= MAX_LINE_LEN) { - // TODO optimise printing of gap? for (int j = 0; j < gap; ++j) { mp_print_str(print, " "); } diff --git a/py/runtime.c b/py/runtime.c index 29fcd04490f8e..79a6fc4ed7b45 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -45,7 +45,7 @@ #include "py/stream.h" #include "py/runtime.h" #include "py/builtin.h" -#include "py/stackctrl.h" +#include "py/cstack.h" #include "py/gc.h" // CIRCUITPY-CHANGE @@ -130,8 +130,8 @@ void mp_init(void) { MP_STATE_VM(mp_module_builtins_override_dict) = NULL; #endif - #if MICROPY_PERSISTENT_CODE_TRACK_RELOC_CODE - MP_STATE_VM(track_reloc_code_list) = MP_OBJ_NULL; + #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA + MP_STATE_VM(persistent_code_root_pointers) = MP_OBJ_NULL; #endif #if MICROPY_PY_OS_DUPTERM @@ -251,8 +251,7 @@ mp_obj_t MICROPY_WRAP_MP_LOAD_GLOBAL(mp_load_global)(qstr qst) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE mp_raise_msg(&mp_type_NameError, MP_ERROR_TEXT("name not defined")); #else - // CIRCUITPY-CHANGE: slight message change - mp_raise_msg_varg(&mp_type_NameError, MP_ERROR_TEXT("name '%q' is not defined"), qst); + mp_raise_msg_varg(&mp_type_NameError, MP_ERROR_TEXT("name '%q' isn't defined"), qst); #endif } } @@ -739,8 +738,8 @@ mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, size_t n_args, size_t n_kw, cons #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE mp_raise_TypeError(MP_ERROR_TEXT("object not callable")); #else - // CIRCUITPY-CHANGE: use new raise function and different message - mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not callable"), mp_obj_get_type_qstr(fun_in)); + // CIRCUITPY-CHANGE: more specific mp_raise + mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object isn't callable"), mp_obj_get_type_qstr(fun_in)); #endif } @@ -1417,9 +1416,9 @@ mp_obj_t mp_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE mp_raise_TypeError(MP_ERROR_TEXT("object not iterable")); #else - // CIRCUITPY-CHANGE: raise function + // CIRCUITPY-CHANGE: more specific mp_raise mp_raise_TypeError_varg( - MP_ERROR_TEXT("'%q' object is not iterable"), mp_obj_get_type_qstr(o_in)); + MP_ERROR_TEXT("'%q' object isn't iterable"), mp_obj_get_type_qstr(o_in)); #endif } @@ -1454,8 +1453,8 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE mp_raise_TypeError(MP_ERROR_TEXT("object not an iterator")); #else - // CIRCUITPY-CHANGE: raise function - mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not an iterator"), + // CIRCUITPY-CHANGE: more specific mp_raise + mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object isn't an iterator"), mp_obj_get_type_qstr(o_in)); #endif } @@ -1465,7 +1464,7 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) { // will always return MP_OBJ_STOP_ITERATION instead of raising StopIteration() (or any subclass thereof) // may raise other exceptions mp_obj_t mp_iternext(mp_obj_t o_in) { - MP_STACK_CHECK(); // enumerate, filter, map and zip can recursively call mp_iternext + mp_cstack_check(); // enumerate, filter, map and zip can recursively call mp_iternext const mp_obj_type_t *type = mp_obj_get_type(o_in); if (TYPE_HAS_ITERNEXT(type)) { MP_STATE_THREAD(stop_iteration_arg) = MP_OBJ_NULL; @@ -1492,8 +1491,8 @@ mp_obj_t mp_iternext(mp_obj_t o_in) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE mp_raise_TypeError(MP_ERROR_TEXT("object not an iterator")); #else - // CIRCUITPY-CHANGE: raise function - mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not an iterator"), + // CIRCUITPY-CHANGE: more specific mp_raise + mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object isn't an iterator"), mp_obj_get_type_qstr(o_in)); #endif } diff --git a/py/runtime.h b/py/runtime.h index b92eb23c9d7bf..a2d69638ffc38 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -30,7 +30,7 @@ #include "py/mpstate.h" #include "py/pystack.h" -#include "py/stackctrl.h" +#include "py/cstack.h" // CIRCUITPY-CHANGE #include "supervisor/linker.h" @@ -188,8 +188,7 @@ void mp_call_function_1_from_nlr_jump_callback(void *ctx_in); static inline void mp_thread_init_state(mp_state_thread_t *ts, size_t stack_size, mp_obj_dict_t *locals, mp_obj_dict_t *globals) { mp_thread_set_state(ts); - mp_stack_set_top(ts + 1); // need to include ts in root-pointer scan - mp_stack_set_limit(stack_size); + mp_cstack_init_with_top(ts + 1, stack_size); // need to include ts in root-pointer scan // GC starts off unlocked ts->gc_lock_depth = 0; diff --git a/py/scheduler.c b/py/scheduler.c index 91ef7e63b38f1..5984346a6f68a 100644 --- a/py/scheduler.c +++ b/py/scheduler.c @@ -245,7 +245,13 @@ void mp_handle_pending(bool raise_exc) { // Handle any pending callbacks. #if MICROPY_ENABLE_SCHEDULER - if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) { + bool run_scheduler = (MP_STATE_VM(sched_state) == MP_SCHED_PENDING); + #if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL + // Avoid races by running the scheduler on the main thread, only. + // (Not needed if GIL enabled, as GIL ensures thread safety here.) + run_scheduler = run_scheduler && mp_thread_is_main_thread(); + #endif + if (run_scheduler) { mp_sched_run_pending(); } #endif diff --git a/py/sequence.c b/py/sequence.c index cc89d1b0b05a0..ac7ad5368b91e 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -78,11 +78,7 @@ bool mp_seq_get_fast_slice_indexes(mp_uint_t len, mp_obj_t slice, mp_bound_slice return indexes->step == 1; } -#endif - -mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t *indexes) { - (void)len; // TODO can we remove len from the arg list? - +mp_obj_t mp_seq_extract_slice(const mp_obj_t *seq, mp_bound_slice_t *indexes) { mp_int_t start = indexes->start, stop = indexes->stop; mp_int_t step = indexes->step; @@ -102,6 +98,8 @@ mp_obj_t mp_seq_extract_slice(size_t len, const mp_obj_t *seq, mp_bound_slice_t return res; } +#endif + // Special-case comparison function for sequences of bytes // Don't pass MP_BINARY_OP_NOT_EQUAL here bool mp_seq_cmp_bytes(mp_uint_t op, const byte *data1, size_t len1, const byte *data2, size_t len2) { diff --git a/py/stackctrl.c b/py/stackctrl.c index f192fad0534de..0372a1db35007 100644 --- a/py/stackctrl.c +++ b/py/stackctrl.c @@ -24,7 +24,12 @@ * THE SOFTWARE. */ +// This API is deprecated, please use py/cstack.h instead + #include "py/runtime.h" + +#if !MICROPY_PREVIEW_VERSION_2 + #include "py/stackctrl.h" void mp_stack_ctrl_init(void) { @@ -68,3 +73,5 @@ void PLACE_IN_ITCM(mp_stack_check)(void) { } #endif // MICROPY_STACK_CHECK + +#endif // !MICROPY_PREVIEW_VERSION_2 diff --git a/py/stackctrl.h b/py/stackctrl.h index 63667f8a5512a..5ff24798103b0 100644 --- a/py/stackctrl.h +++ b/py/stackctrl.h @@ -26,8 +26,12 @@ #ifndef MICROPY_INCLUDED_PY_STACKCTRL_H #define MICROPY_INCLUDED_PY_STACKCTRL_H +// This API is deprecated, please use py/cstack.h instead + #include "py/mpconfig.h" +#if !MICROPY_PREVIEW_VERSION_2 + void mp_stack_ctrl_init(void); void mp_stack_set_top(void *top); mp_uint_t mp_stack_usage(void); @@ -43,7 +47,9 @@ void mp_stack_check(void); #define mp_stack_set_limit(limit) (void)(limit) #define MP_STACK_CHECK() -#endif +#endif // MICROPY_STACK_CHECK + +#endif // !MICROPY_PREVIEW_VERSION_2 // CIRCUITPY-CHANGE: provide max stack usage #if MICROPY_MAX_STACK_USAGE diff --git a/py/usermod.cmake b/py/usermod.cmake index 853276283746d..c814369a4865e 100644 --- a/py/usermod.cmake +++ b/py/usermod.cmake @@ -5,6 +5,10 @@ function(usermod_gather_sources SOURCES_VARNAME INCLUDE_DIRECTORIES_VARNAME INCL if (NOT ${LIB} IN_LIST ${INCLUDED_VARNAME}) list(APPEND ${INCLUDED_VARNAME} ${LIB}) + if (NOT TARGET ${LIB}) + return() + endif() + # Gather library sources get_target_property(lib_sources ${LIB} INTERFACE_SOURCES) if (lib_sources) diff --git a/shared-bindings/_eve/__init__.c b/shared-bindings/_eve/__init__.c index 000e3526ed567..a3914d07f324f 100644 --- a/shared-bindings/_eve/__init__.c +++ b/shared-bindings/_eve/__init__.c @@ -970,6 +970,7 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vertex2ii_obj, 3, 5, _vertex2ii); { MP_ROM_QSTR(MP_QSTR_PaletteSource), MP_ROM_PTR(&palettesource_obj) }, \ { MP_ROM_QSTR(MP_QSTR_PaletteSourceH), MP_ROM_PTR(&palettesourceh_obj) }, \ { MP_ROM_QSTR(MP_QSTR_PointSize), MP_ROM_PTR(&pointsize_obj) }, \ + { MP_ROM_QSTR(MP_QSTR_Region), MP_ROM_PTR(®ion_obj) }, \ { MP_ROM_QSTR(MP_QSTR_RestoreContext), MP_ROM_PTR(&restorecontext_obj) }, \ { MP_ROM_QSTR(MP_QSTR_Return), MP_ROM_PTR(&return_obj) }, \ { MP_ROM_QSTR(MP_QSTR_SaveContext), MP_ROM_PTR(&savecontext_obj) }, \ @@ -1061,8 +1062,29 @@ static mp_obj_t _pointsize(mp_obj_t self, mp_obj_t a0) { common_hal__eve_PointSize(EVEHAL(self), size); return mp_const_none; } + static MP_DEFINE_CONST_FUN_OBJ_2(pointsize_obj, _pointsize); +//| def Region(self, y: int, h: int, dest: int) -> None: +//| """Specify a cull region in the display list +//| +//| :param int y: Starting Y band in the render buffer. Range 0-63 +//| :param int h: Y height in the render buffer. Range 0-63 +//| :param int dest: destination address in the display list if the raster is outside the region +//| +//| """ +//| ... +//| + +static mp_obj_t _region(size_t n_args, const mp_obj_t *args) { + uint32_t y = mp_obj_get_int_truncated(args[1]); + uint32_t h = mp_obj_get_int_truncated(args[2]); + uint32_t dest = mp_obj_get_int_truncated(args[3]); + common_hal__eve_Region(EVEHAL(args[0]), y, h, dest); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(region_obj, 4, 4, _region); + //| def VertexTranslateX(self, x: float) -> None: //| """Set the vertex transformation's x translation component //| diff --git a/shared-bindings/_eve/__init__.h b/shared-bindings/_eve/__init__.h index e75f8db792840..13ae1b8a6cb50 100644 --- a/shared-bindings/_eve/__init__.h +++ b/shared-bindings/_eve/__init__.h @@ -49,6 +49,7 @@ void common_hal__eve_Nop(common_hal__eve_t *eve); void common_hal__eve_PaletteSource(common_hal__eve_t *eve, uint32_t addr); void common_hal__eve_PaletteSourceH(common_hal__eve_t *eve, uint32_t addr); void common_hal__eve_PointSize(common_hal__eve_t *eve, mp_float_t size); +void common_hal__eve_Region(common_hal__eve_t *eve, uint32_t y, uint32_t h, uint32_t dest); void common_hal__eve_RestoreContext(common_hal__eve_t *eve); void common_hal__eve_Return(common_hal__eve_t *eve); void common_hal__eve_SaveContext(common_hal__eve_t *eve); diff --git a/shared-bindings/alarm/SleepMemory.c b/shared-bindings/alarm/SleepMemory.c index d783983008c5f..e6d65de45551d 100644 --- a/shared-bindings/alarm/SleepMemory.c +++ b/shared-bindings/alarm/SleepMemory.c @@ -20,8 +20,6 @@ //| instance of :class:`SleepMemory` is available at //| :attr:`alarm.sleep_memory`. //| -//| **Limitations:** Not supported on RP2040. -//| //| Usage:: //| //| import alarm diff --git a/shared-bindings/epaperdisplay/EPaperDisplay.c b/shared-bindings/epaperdisplay/EPaperDisplay.c index 90828cb1f5a9a..5d72df815d0a7 100644 --- a/shared-bindings/epaperdisplay/EPaperDisplay.c +++ b/shared-bindings/epaperdisplay/EPaperDisplay.c @@ -62,6 +62,7 @@ //| always_toggle_chip_select: bool = False, //| grayscale: bool = False, //| advanced_color_epaper: bool = False, +//| spectra6: bool = False, //| two_byte_sequence_length: bool = False, //| start_up_time: float = 0, //| address_little_endian: bool = False, @@ -104,6 +105,7 @@ //| :param bool always_toggle_chip_select: When True, chip select is toggled every byte //| :param bool grayscale: When true, the color ram is the low bit of 2-bit grayscale //| :param bool advanced_color_epaper: When true, the display is a 7-color advanced color epaper (ACeP) +//| :param bool spectra6: When true, the display is a 6-color spectra6 epaper //| :param bool two_byte_sequence_length: When true, use two bytes to define sequence length //| :param float start_up_time: Time to wait after reset before sending commands //| :param bool address_little_endian: Send the least significant byte (not bit) of multi-byte addresses first. Ignored when ram is addressed with one byte @@ -117,7 +119,7 @@ static mp_obj_t epaperdisplay_epaperdisplay_make_new(const mp_obj_type_t *type, ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color, ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state, - ARG_seconds_per_frame, ARG_always_toggle_chip_select, ARG_grayscale, ARG_advanced_color_epaper, + ARG_seconds_per_frame, ARG_always_toggle_chip_select, ARG_grayscale, ARG_advanced_color_epaper, ARG_spectra6, ARG_two_byte_sequence_length, ARG_start_up_time, ARG_address_little_endian }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -147,6 +149,7 @@ static mp_obj_t epaperdisplay_epaperdisplay_make_new(const mp_obj_type_t *type, { MP_QSTR_always_toggle_chip_select, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_advanced_color_epaper, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_spectra6, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_two_byte_sequence_length, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, { MP_QSTR_start_up_time, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(0)} }, { MP_QSTR_address_little_endian, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, @@ -215,7 +218,7 @@ static mp_obj_t epaperdisplay_epaperdisplay_make_new(const mp_obj_type_t *type, args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, args[ARG_color_bits_inverted].u_bool, highlight_color, refresh_buf, refresh_buf_len, refresh_time, busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, - args[ARG_always_toggle_chip_select].u_bool, args[ARG_grayscale].u_bool, args[ARG_advanced_color_epaper].u_bool, + args[ARG_always_toggle_chip_select].u_bool, args[ARG_grayscale].u_bool, args[ARG_advanced_color_epaper].u_bool, args[ARG_spectra6].u_bool, two_byte_sequence_length, args[ARG_address_little_endian].u_bool ); diff --git a/shared-bindings/epaperdisplay/EPaperDisplay.h b/shared-bindings/epaperdisplay/EPaperDisplay.h index d4475e0a6aa43..016a07f1490c5 100644 --- a/shared-bindings/epaperdisplay/EPaperDisplay.h +++ b/shared-bindings/epaperdisplay/EPaperDisplay.h @@ -26,7 +26,7 @@ void common_hal_epaperdisplay_epaperdisplay_construct(epaperdisplay_epaperdispla uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, const uint8_t *refresh_sequence, uint16_t refresh_sequence_len, mp_float_t refresh_time, const mcu_pin_obj_t *busy_pin, bool busy_state, mp_float_t seconds_per_frame, - bool always_toggle_chip_select, bool grayscale, bool acep, bool two_byte_sequence_length, + bool always_toggle_chip_select, bool grayscale, bool acep, bool spectra6, bool two_byte_sequence_length, bool address_little_endian); bool common_hal_epaperdisplay_epaperdisplay_refresh(epaperdisplay_epaperdisplay_obj_t *self); diff --git a/shared-bindings/i2ctarget/I2CTarget.c b/shared-bindings/i2ctarget/I2CTarget.c index 728d9f60e2712..8586d1843cc77 100644 --- a/shared-bindings/i2ctarget/I2CTarget.c +++ b/shared-bindings/i2ctarget/I2CTarget.c @@ -21,7 +21,7 @@ static mp_obj_t mp_obj_new_i2ctarget_i2c_target_request(i2ctarget_i2c_target_obj_t *target, uint8_t address, bool is_read, bool is_restart) { i2ctarget_i2c_target_request_obj_t *self = - mp_obj_malloc(i2ctarget_i2c_target_request_obj_t, &i2ctarget_i2c_target_request_type); + mp_obj_malloc_with_finaliser(i2ctarget_i2c_target_request_obj_t, &i2ctarget_i2c_target_request_type); self->target = target; self->address = address; self->is_read = is_read; @@ -200,7 +200,7 @@ static MP_DEFINE_CONST_DICT(i2ctarget_i2c_target_locals_dict, i2ctarget_i2c_targ MP_DEFINE_CONST_OBJ_TYPE( i2ctarget_i2c_target_type, MP_QSTR_I2CTarget, - MP_TYPE_FLAG_NONE, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, make_new, i2ctarget_i2c_target_make_new, locals_dict, &i2ctarget_i2c_target_locals_dict ); @@ -222,23 +222,38 @@ static mp_obj_t i2ctarget_i2c_target_request_make_new(const mp_obj_type_t *type, return mp_obj_new_i2ctarget_i2c_target_request(args[0], mp_obj_get_int(args[1]), mp_obj_is_true(args[2]), mp_obj_is_true(args[3])); } -//| def __enter__(self) -> I2CTargetRequest: -//| """No-op used in Context Managers.""" -//| ... -//| -// Provided by context manager helper. +static void target_request_check_for_deinit(i2ctarget_i2c_target_request_obj_t *self) { + if (self->target == NULL) { + raise_deinited_error(); + } + check_for_deinit(self->target); +} -//| def __exit__(self) -> None: -//| """Close the request.""" +//| def deinit(self) -> None: +//| """Disconnects from parent `I2CTarget`. +//| Called by `__exit__()` to indicate the `I2CTargetRequest` is no longer useful.""" //| ... //| -// Provided by context manager helper. +static mp_obj_t i2ctarget_i2c_target_request_deinit(mp_obj_t self_in) { + i2ctarget_i2c_target_request_obj_t *self = MP_OBJ_TO_PTR(self_in); + target_request_check_for_deinit(self); + + i2ctarget_i2c_target_obj_t *target = self->target; + + // Deinit I2CTargetRequest first in case _close() fails. + self->target = NULL; + + common_hal_i2ctarget_i2c_target_close(target); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(i2ctarget_i2c_target_request_deinit_obj, i2ctarget_i2c_target_request_deinit); //| address: int //| """The I2C address of the request.""" static mp_obj_t i2ctarget_i2c_target_request_get_address(mp_obj_t self_in) { i2ctarget_i2c_target_request_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self->target); + target_request_check_for_deinit(self); return mp_obj_new_int(self->address); } @@ -248,7 +263,7 @@ MP_DEFINE_CONST_PROP_GET(i2ctarget_i2c_target_request_address_obj, i2ctarget_i2c //| """The I2C main controller is reading from this target.""" static mp_obj_t i2ctarget_i2c_target_request_get_is_read(mp_obj_t self_in) { i2ctarget_i2c_target_request_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self->target); + target_request_check_for_deinit(self); return mp_obj_new_bool(self->is_read); } @@ -259,7 +274,7 @@ MP_DEFINE_CONST_PROP_GET(i2ctarget_i2c_target_request_is_read_obj, i2ctarget_i2c //| static mp_obj_t i2ctarget_i2c_target_request_get_is_restart(mp_obj_t self_in) { i2ctarget_i2c_target_request_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self->target); + target_request_check_for_deinit(self); return mp_obj_new_bool(self->is_restart); } @@ -276,7 +291,7 @@ MP_DEFINE_CONST_PROP_GET(i2ctarget_i2c_target_request_is_restart_obj, i2ctarget_ //| static mp_obj_t i2ctarget_i2c_target_request_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { i2ctarget_i2c_target_request_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - check_for_deinit(self->target); + target_request_check_for_deinit(self); enum { ARG_n, ARG_ack }; static const mp_arg_t allowed_args[] = { @@ -335,7 +350,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(i2ctarget_i2c_target_request_read_obj, 1, i2ctarget_i //| static mp_obj_t i2ctarget_i2c_target_request_write(mp_obj_t self_in, mp_obj_t buf_in) { i2ctarget_i2c_target_request_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self->target); + target_request_check_for_deinit(self); if (!self->is_read) { mp_raise_OSError(MP_EACCES); @@ -370,7 +385,7 @@ static MP_DEFINE_CONST_FUN_OBJ_2(i2ctarget_i2c_target_request_write_obj, i2ctarg //| static mp_obj_t i2ctarget_i2c_target_request_ack(uint n_args, const mp_obj_t *args) { i2ctarget_i2c_target_request_obj_t *self = MP_OBJ_TO_PTR(args[0]); - check_for_deinit(self->target); + target_request_check_for_deinit(self); bool ack = (n_args == 1) ? true : mp_obj_is_true(args[1]); @@ -383,25 +398,29 @@ static mp_obj_t i2ctarget_i2c_target_request_ack(uint n_args, const mp_obj_t *ar } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2ctarget_i2c_target_request_ack_obj, 1, 2, i2ctarget_i2c_target_request_ack); -static mp_obj_t i2ctarget_i2c_target_request_close(mp_obj_t self_in) { - i2ctarget_i2c_target_request_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self->target); +//| def __enter__(self) -> I2CTargetRequest: +//| """No-op used in Context Managers.""" +//| ... +//| +// Provided by context manager helper. - common_hal_i2ctarget_i2c_target_close(self->target); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(i2ctarget_i2c_target_request_close_obj, i2ctarget_i2c_target_request_close); +//| def __exit__(self) -> None: +//| """Close and deinit the request.""" +//| ... +//| +// Provided by context manager helper. static const mp_rom_map_elem_t i2ctarget_i2c_target_request_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&i2ctarget_i2c_target_request_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR__del__), MP_ROM_PTR(&i2ctarget_i2c_target_request_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&i2ctarget_i2c_target_request_address_obj) }, { MP_ROM_QSTR(MP_QSTR_is_read), MP_ROM_PTR(&i2ctarget_i2c_target_request_is_read_obj) }, { MP_ROM_QSTR(MP_QSTR_is_restart), MP_ROM_PTR(&i2ctarget_i2c_target_request_is_restart_obj) }, { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&i2ctarget_i2c_target_request_read_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&i2ctarget_i2c_target_request_write_obj) }, { MP_ROM_QSTR(MP_QSTR_ack), MP_ROM_PTR(&i2ctarget_i2c_target_request_ack_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&i2ctarget_i2c_target_request_close_obj) }, }; static MP_DEFINE_CONST_DICT(i2ctarget_i2c_target_request_locals_dict, i2ctarget_i2c_target_request_locals_dict_table); diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index 8303645f20183..edb32c2c5c700 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -67,6 +67,14 @@ //| in the respective state for ``debounce_threshold`` times on average. //| Successive measurements are spaced apart by ``interval`` seconds. //| The default is 1, which resolves immediately. The maximum is 127. +//| +//| .. warning:: On Raspberry Pi RP2350, using ``columns_to_anodes=False`` +//| normally depends on the internal pull-down resistors. +//| This will not work, due to an RP2350 issue. +//| The easiest fix is simply to swap the ``row_pins`` and ```column_pins`` and to set +//| ``columns_to_anodes=True``. This requires no external components. +//| An alternative is to add external pull-downs of 8.2 kohms or less, but that will draw more current. +//| See the Warning in `digitalio` for more information. //| """ //| ... //| diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 10ac81cf1fb63..64e8e51a67ded 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -69,6 +69,12 @@ //| in the respective state for ``debounce_threshold`` times on average. //| Successive measurements are spaced apart by ``interval`` seconds. //| The default is 1, which resolves immediately. The maximum is 127. +//| +//| .. warning:: On Raspberry Pi RP2350, using ``value_when_pressed=True`` and ``pull=True``, +//| to enable using the internal pull-down resistor, will not work, due to an RP2350 +//| hardware issue. Instead, wire the switch to be ``value_when_pressed=False``, or add +//| an external pull-down resistor of 8.2 kohms or less. +//| See the Warning in `digitalio` for more information. //| """ //| ... //| diff --git a/shared-bindings/keypad/__init__.c b/shared-bindings/keypad/__init__.c index b29de197262f4..b182e977829d1 100644 --- a/shared-bindings/keypad/__init__.c +++ b/shared-bindings/keypad/__init__.c @@ -65,7 +65,7 @@ MP_PROPERTY_GETTER(keypad_generic_events_obj, //| due to a GPIO hardware issue that causes excessive leakage current (~120uA). //| A pin can read as high even when driven or pulled low, if the input signal is high //| impedance or if an attached pull-down resistor is too weak (has too high a value). -//| See the warning in `digitalio` for more information. +//| See the warnings in `keypad.Keys`, `keypad.KeyMatrix`, and `digitalio` for workarounds and more information. //| //| .. jinja //| """ diff --git a/shared-bindings/rclcpy/Node.c b/shared-bindings/rclcpy/Node.c new file mode 100644 index 0000000000000..a2fa9bd36a656 --- /dev/null +++ b/shared-bindings/rclcpy/Node.c @@ -0,0 +1,145 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Lucian Copeland +// +// SPDX-License-Identifier: MIT + +#include +#include "shared-bindings/rclcpy/Node.h" +#include "shared-bindings/rclcpy/Publisher.h" +#include "shared-bindings/util.h" +#include "py/objproperty.h" +#include "py/objtype.h" +#include "py/runtime.h" + + +//| class Node: +//| """A ROS2 Node""" +//| +//| def __init__( +//| self, +//| node_name: str, +//| *, +//| namespace: str | None = None, +//| ) -> None: +//| """Create a Node. +//| +//| Creates an instance of a ROS2 Node. Nodes can be used to create other ROS +//| entities like publishers or subscribers. Nodes must have a unique name, and +//| may also be constructed from their class. +//| +//| :param str node_name: The name of the node. Must be a valid ROS 2 node name +//| :param str namespace: The namespace for the node. If None, the node will be +//| created in the root namespace +//| """ +//| ... +//| +static mp_obj_t rclcpy_node_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_node_name, ARG_namespace }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_node_name, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_namespace, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + const char *node_name = mp_obj_str_get_str(args[ARG_node_name].u_obj); + const char *namespace = ""; + if (args[ARG_namespace].u_obj != mp_const_none) { + namespace = mp_obj_str_get_str(args[ARG_namespace].u_obj); + } + + rclcpy_node_obj_t *self = mp_obj_malloc_with_finaliser(rclcpy_node_obj_t, &rclcpy_node_type); + common_hal_rclcpy_node_construct(self, node_name, namespace); + return (mp_obj_t)self; +} + +//| def deinit(self) -> None: +//| """Deinitializes the node and frees any hardware or remote agent resources +//| used by it. Deinitialized nodes cannot be used again. +//| """ +//| ... +//| +static mp_obj_t rclcpy_node_obj_deinit(mp_obj_t self_in) { + rclcpy_node_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_rclcpy_node_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rclcpy_node_deinit_obj, rclcpy_node_obj_deinit); + +static void check_for_deinit(rclcpy_node_obj_t *self) { + if (common_hal_rclcpy_node_deinited(self)) { + raise_deinited_error(); + } +} + +//| def create_publisher(self, topic: str) -> Publisher: +//| """Create a publisher for a given topic string. +//| +//| Creates an instance of a ROS2 Publisher. +//| +//| :param str topic: The name of the topic +//| :return: A new Publisher object for the specified topic +//| :rtype: Publisher +//| """ +//| ... +//| +static mp_obj_t rclcpy_node_create_publisher(mp_obj_t self_in, mp_obj_t topic) { + rclcpy_node_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + const char *topic_name = mp_obj_str_get_str(topic); + + rclcpy_publisher_obj_t *publisher = mp_obj_malloc_with_finaliser(rclcpy_publisher_obj_t, &rclcpy_publisher_type); + common_hal_rclcpy_publisher_construct(publisher, self, topic_name); + return (mp_obj_t)publisher; +} +static MP_DEFINE_CONST_FUN_OBJ_2(rclcpy_node_create_publisher_obj, rclcpy_node_create_publisher); + +//| def get_name(self) -> str: +//| """Get the name of the node. +//| +//| :return: The node's name +//| :rtype: str +//| """ +//| ... +//| +static mp_obj_t rclcpy_node_get_name(mp_obj_t self_in) { + rclcpy_node_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + const char *name_str = common_hal_rclcpy_node_get_name(self); + return mp_obj_new_str(name_str, strlen(name_str)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(rclcpy_node_get_name_obj, rclcpy_node_get_name); + +//| def get_namespace(self) -> str: +//| """Get the namespace of the node. +//| +//| :return: The node's namespace +//| :rtype: str +//| """ +//| ... +//| +static mp_obj_t rclcpy_node_get_namespace(mp_obj_t self_in) { + rclcpy_node_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + const char *namespace_str = common_hal_rclcpy_node_get_namespace(self); + return mp_obj_new_str(namespace_str, strlen(namespace_str)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(rclcpy_node_get_namespace_obj, rclcpy_node_get_namespace); + +static const mp_rom_map_elem_t rclcpy_node_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&rclcpy_node_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&rclcpy_node_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_create_publisher), MP_ROM_PTR(&rclcpy_node_create_publisher_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_name), MP_ROM_PTR(&rclcpy_node_get_name_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_namespace), MP_ROM_PTR(&rclcpy_node_get_namespace_obj) }, +}; +static MP_DEFINE_CONST_DICT(rclcpy_node_locals_dict, rclcpy_node_locals_dict_table); + + +MP_DEFINE_CONST_OBJ_TYPE( + rclcpy_node_type, + MP_QSTR_Node, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, rclcpy_node_make_new, + locals_dict, &rclcpy_node_locals_dict + ); diff --git a/shared-bindings/rclcpy/Node.h b/shared-bindings/rclcpy/Node.h new file mode 100644 index 0000000000000..be0230846f6bd --- /dev/null +++ b/shared-bindings/rclcpy/Node.h @@ -0,0 +1,18 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Lucian Copeland +// +// SPDX-License-Identifier: MIT + +#pragma once +#include "common-hal/rclcpy/Node.h" + + +extern const mp_obj_type_t rclcpy_node_type; + +void common_hal_rclcpy_node_construct(rclcpy_node_obj_t *self, + const char *node_name, const char *namespace); +bool common_hal_rclcpy_node_deinited(rclcpy_node_obj_t *self); +void common_hal_rclcpy_node_deinit(rclcpy_node_obj_t *self); +const char *common_hal_rclcpy_node_get_name(rclcpy_node_obj_t *self); +const char *common_hal_rclcpy_node_get_namespace(rclcpy_node_obj_t *self); diff --git a/shared-bindings/rclcpy/Publisher.c b/shared-bindings/rclcpy/Publisher.c new file mode 100644 index 0000000000000..be1e229cce4f8 --- /dev/null +++ b/shared-bindings/rclcpy/Publisher.c @@ -0,0 +1,99 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Lucian Copeland +// +// SPDX-License-Identifier: MIT + +#include +#include "shared-bindings/rclcpy/Publisher.h" +#include "shared-bindings/util.h" +#include "py/objproperty.h" +#include "py/objtype.h" +#include "py/runtime.h" + + +//| class Publisher: +//| """A ROS2 publisher""" +//| +//| def __init__(self) -> None: +//| """Publishers cannot be created directly. +//| +//| Use :meth:`Node.create_publisher` to create a publisher from a node. +//| +//| :raises NotImplementedError: Always, as direct instantiation is not supported +//| """ +//| ... +//| +static mp_obj_t rclcpy_publisher_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("Publishers can only be created from a parent node")); +} + +//| def deinit(self) -> None: +//| """Deinitializes the publisher and frees any hardware or remote agent resources +//| used by it. Deinitialized publishers cannot be used again. +//| """ +//| ... +//| +static mp_obj_t rclcpy_publisher_obj_deinit(mp_obj_t self_in) { + rclcpy_publisher_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_rclcpy_publisher_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(rclcpy_publisher_deinit_obj, rclcpy_publisher_obj_deinit); + +static void check_for_deinit(rclcpy_publisher_obj_t *self) { + if (common_hal_rclcpy_publisher_deinited(self)) { + raise_deinited_error(); + } +} + +//| def publish_int32(self, message: int) -> None: +//| """Publish a 32-bit signed integer message to the topic. +//| +//| :param int message: The integer value to publish. Must be within the range +//| of a 32-bit signed integer (-2,147,483,648 to 2,147,483,647) +//| """ +//| ... +//| +static mp_obj_t rclcpy_publisher_publish_int32(mp_obj_t self_in, mp_obj_t in_msg) { + rclcpy_publisher_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + int32_t msg = mp_obj_get_int(in_msg); + common_hal_rclcpy_publisher_publish_int32(self, msg); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(rclcpy_publisher_publish_int32_obj, rclcpy_publisher_publish_int32); + +//| def get_topic_name(self) -> str: +//| """Get the name of the topic this publisher publishes to. +//| +//| :return: The topic name as specified when the publisher was created +//| :rtype: str +//| """ +//| ... +//| +static mp_obj_t rclcpy_publisher_get_topic_name(mp_obj_t self_in) { + rclcpy_publisher_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + const char *topic_str = common_hal_rclcpy_publisher_get_topic_name(self); + return mp_obj_new_str(topic_str, strlen(topic_str)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(rclcpy_publisher_get_topic_name_obj, rclcpy_publisher_get_topic_name); + + +static const mp_rom_map_elem_t rclcpy_publisher_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&rclcpy_publisher_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&rclcpy_publisher_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_publish_int32), MP_ROM_PTR(&rclcpy_publisher_publish_int32_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_topic_name), MP_ROM_PTR(&rclcpy_publisher_get_topic_name_obj) }, +}; +static MP_DEFINE_CONST_DICT(rclcpy_publisher_locals_dict, rclcpy_publisher_locals_dict_table); + + +MP_DEFINE_CONST_OBJ_TYPE( + rclcpy_publisher_type, + MP_QSTR_Publisher, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, rclcpy_publisher_make_new, + locals_dict, &rclcpy_publisher_locals_dict + ); diff --git a/shared-bindings/rclcpy/Publisher.h b/shared-bindings/rclcpy/Publisher.h new file mode 100644 index 0000000000000..21909fe12bed9 --- /dev/null +++ b/shared-bindings/rclcpy/Publisher.h @@ -0,0 +1,18 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Lucian Copeland +// +// SPDX-License-Identifier: MIT + +#pragma once +#include "common-hal/rclcpy/Publisher.h" + + +extern const mp_obj_type_t rclcpy_publisher_type; + +void common_hal_rclcpy_publisher_construct(rclcpy_publisher_obj_t *self, rclcpy_node_obj_t *node, + const char *topic_name); +bool common_hal_rclcpy_publisher_deinited(rclcpy_publisher_obj_t *self); +void common_hal_rclcpy_publisher_deinit(rclcpy_publisher_obj_t *self); +void common_hal_rclcpy_publisher_publish_int32(rclcpy_publisher_obj_t *self, int32_t data); +const char *common_hal_rclcpy_publisher_get_topic_name(rclcpy_publisher_obj_t *self); diff --git a/shared-bindings/rclcpy/__init__.c b/shared-bindings/rclcpy/__init__.c new file mode 100644 index 0000000000000..a6631642ea7c0 --- /dev/null +++ b/shared-bindings/rclcpy/__init__.c @@ -0,0 +1,134 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Lucian Copeland +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/rclcpy/__init__.h" +#include "shared-bindings/rclcpy/Node.h" +#include "shared-bindings/rclcpy/Publisher.h" + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/objstr.h" +#include "py/runtime.h" + +//| """Robot Operating System (ROS2) connectivity through micro-ROS +//| +//| The `rclcpy` module contains basic classes and connectivity options for +//| communicating with a ROS network running on a linux machine, using the +//| eProsima's `micro-ROS client API `_. +//| +//| The underlying micro-ROS system uses a resource-constrained middleware layer +//| (XRCE-DDS) that must be connected to an agent running within ROS2 on a host +//| Linux computer. The API exposed by Circuitpython aims to be close to the +//| standard Python API for ROS2, ``rclpy`` with minor additions to support +//| connecting to this agent. +//| +//| Wifi must be connected before calling any `rclcpy` functions. As with +//| ``rclpy``, the `rclcpy.init()` function must be run before creating any ROS +//| objects. Child objects, such as publishers, must be created by their parent +//| objects. For example:: +//| +//| import os, wifi, time +//| import rclcpy +//| wifi.radio.connect(ssid=os.getenv('CIRCUITPY_WIFI_SSID'), +//| password=os.getenv('CIRCUITPY_WIFI_PASSWORD')) +//| rclcpy.init("192.168.10.111","8888") +//| mynode = rclcpy.Node("foo") +//| mypub = mynode.create_publisher("bar") +//| mypub.publish_int32(42) +//| """ + +//| def init( +//| agent_ip: str, +//| agent_port: str, +//| *, +//| domain_id: int = 0, +//| ) -> None: +//| """Initialize micro-ROS and connect to a micro-ROS agent. +//| +//| This function starts ROS communications and connects to the micro-ROS agent +//| on a linux computer. It must be called before creating ROS objects. +//| +//| :param str agent_ip: The IP address of the micro-ROS agent +//| :param str agent_port: The port number of the micro-ROS agent as a string +//| :param int domain_id: The ROS 2 domain ID for network isolation and organization. +//| Devices with the same domain ID can communicate with each other. +//| """ +//| ... +//| +static mp_obj_t rclcpy_init(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_agent_ip, ARG_agent_port, ARG_domain_id}; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_agent_ip, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_agent_port, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_domain_id, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + const char *agent_ip = mp_obj_str_get_str(args[ARG_agent_ip].u_obj); + const char *agent_port = mp_obj_str_get_str(args[ARG_agent_port].u_obj); + int16_t domain_id = args[ARG_domain_id].u_int; + + common_hal_rclcpy_init(agent_ip, agent_port, domain_id); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(rclcpy_init_obj, 2, rclcpy_init); + + +//| def create_node( +//| node_name: str, +//| *, +//| namespace: str | None = None +//| ) -> Node: +//| """Create a Node. +//| +//| Creates an instance of a ROS2 Node. Nodes can be used to create other ROS +//| entities like publishers or subscribers. Nodes must have a unique name, and +//| may also be constructed from their class. +//| +//| :param str node_name: The name of the node. Must be a valid ROS 2 node name. +//| :param str namespace: The namespace for the node. If None, the node will be +//| created in the root namespace. +//| :return: A new Node object +//| :rtype: Node +//| """ +//| ... +//| +static mp_obj_t rclcpy_create_node(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_node_name, ARG_namespace }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_node_name, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_namespace, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + const char *node_name = mp_obj_str_get_str(args[ARG_node_name].u_obj); + const char *namespace = ""; + if (args[ARG_namespace].u_obj != mp_const_none) { + namespace = mp_obj_str_get_str(args[ARG_namespace].u_obj); + } + + rclcpy_node_obj_t *self = mp_obj_malloc_with_finaliser(rclcpy_node_obj_t, &rclcpy_node_type); + common_hal_rclcpy_node_construct(self, node_name, namespace); + return (mp_obj_t)self; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(rclcpy_create_node_obj, 2, rclcpy_create_node); + +static const mp_rom_map_elem_t rclcpy_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_rclcpy) }, + { MP_ROM_QSTR(MP_QSTR_Node), MP_ROM_PTR(&rclcpy_node_type) }, + { MP_ROM_QSTR(MP_QSTR_Publisher), MP_ROM_PTR(&rclcpy_publisher_type) }, + { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&rclcpy_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_create_node), MP_ROM_PTR(&rclcpy_create_node_obj) }, +}; + +static MP_DEFINE_CONST_DICT(rclcpy_module_globals, rclcpy_module_globals_table); + +const mp_obj_module_t rclcpy_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&rclcpy_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_rclcpy, rclcpy_module); diff --git a/shared-bindings/rclcpy/__init__.h b/shared-bindings/rclcpy/__init__.h new file mode 100644 index 0000000000000..1b4734216889c --- /dev/null +++ b/shared-bindings/rclcpy/__init__.h @@ -0,0 +1,12 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Lucian Copeland +// +// SPDX-License-Identifier: MIT + +#pragma once +#include "common-hal/rclcpy/__init__.h" + +void common_hal_rclcpy_init(const char *agent_ip, const char *agent_port, int16_t domain_id); +rclcpy_context_t *common_hal_rclcpy_get_default_context(void); +bool common_hal_rclcpy_default_context_is_initialized(void); diff --git a/shared-module/_eve/__init__.c b/shared-module/_eve/__init__.c index ecd310b55a3c1..ca084d9b43b36 100644 --- a/shared-module/_eve/__init__.c +++ b/shared-module/_eve/__init__.c @@ -246,6 +246,11 @@ void common_hal__eve_PointSize(common_hal__eve_t *eve, mp_float_t size) { } +void common_hal__eve_Region(common_hal__eve_t *eve, uint32_t y, uint32_t h, uint32_t dest) { + C4(eve, ((52 << 24) | ((y & 0x3f) << 18) | ((h & 0x3f) << 12) | (dest & 0xfff))); +} + + void common_hal__eve_RestoreContext(common_hal__eve_t *eve) { C4(eve, ((35 << 24))); } diff --git a/shared-module/atexit/__init__.c b/shared-module/atexit/__init__.c index 562b5c3d6b348..537a2a9d969a1 100644 --- a/shared-module/atexit/__init__.c +++ b/shared-module/atexit/__init__.c @@ -28,7 +28,7 @@ void atexit_gc_collect(void) { void shared_module_atexit_register(mp_obj_t *func, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { if (!mp_obj_is_callable(func)) { - mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object is not callable"), mp_obj_get_type_qstr(func)); + mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object isn't callable"), mp_obj_get_type_qstr(func)); } size_t n_kw_args = (kw_args) ? kw_args->used : 0; atexit_callback_t cb = { diff --git a/shared-module/audiodelays/Echo.c b/shared-module/audiodelays/Echo.c index 289d6699506b9..78764d9099a1c 100644 --- a/shared-module/audiodelays/Echo.c +++ b/shared-module/audiodelays/Echo.c @@ -98,11 +98,10 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_ // read is where we read previous echo from delay_ms ago to play back now // write is where the store the latest playing sample to echo back later - self->echo_buffer_read_pos = self->buffer_len / sizeof(uint16_t); - self->echo_buffer_write_pos = 0; + self->echo_buffer_left_pos = 0; - // where we read the previous echo from delay_ms ago to play back now (for freq shift) - self->echo_buffer_left_pos = self->echo_buffer_right_pos = 0; + // use a separate buffer position for the right channel + self->echo_buffer_right_pos = 0; } void common_hal_audiodelays_echo_deinit(audiodelays_echo_obj_t *self) { @@ -128,30 +127,32 @@ void recalculate_delay(audiodelays_echo_obj_t *self, mp_float_t f_delay_ms) { // Require that delay is at least 1 sample long f_delay_ms = MAX(f_delay_ms, self->sample_ms); + // Calculate the maximum buffer size per channel in bytes + uint32_t max_echo_buffer_len = self->max_echo_buffer_len >> (self->base.channel_count - 1); + if (self->freq_shift) { // Calculate the rate of iteration over the echo buffer with 8 sub-bits self->echo_buffer_rate = (uint32_t)MAX(self->max_delay_ms / f_delay_ms * MICROPY_FLOAT_CONST(256.0), MICROPY_FLOAT_CONST(1.0)); - self->echo_buffer_len = self->max_echo_buffer_len; + // Only use half of the buffer per channel if stereo + self->echo_buffer_len = max_echo_buffer_len; } else { // Calculate the current echo buffer length in bytes - uint32_t new_echo_buffer_len = (uint32_t)(self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0) * f_delay_ms) * (self->base.channel_count * sizeof(uint16_t)); - - // Check if our new echo is too long for our maximum buffer - if (new_echo_buffer_len > self->max_echo_buffer_len) { - return; - } else if (new_echo_buffer_len < 0.0) { // or too short! - return; - } - - // If the echo buffer is larger then our audio buffer weird things happen - if (new_echo_buffer_len < self->buffer_len) { - return; + uint32_t new_echo_buffer_len = (uint32_t)(self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0) * f_delay_ms) * sizeof(uint16_t); + + // Limit to valid range + if (new_echo_buffer_len > max_echo_buffer_len) { + new_echo_buffer_len = max_echo_buffer_len; + } else if (new_echo_buffer_len < self->buffer_len) { + // If the echo buffer is smaller than our audio buffer, weird things happen + new_echo_buffer_len = self->buffer_len; } self->echo_buffer_len = new_echo_buffer_len; // Clear the now unused part of the buffer or some weird artifacts appear - memset(self->echo_buffer + self->echo_buffer_len, 0, self->max_echo_buffer_len - self->echo_buffer_len); + for (uint32_t i = 0; i < self->base.channel_count; i++) { + memset(self->echo_buffer + (i * max_echo_buffer_len) + self->echo_buffer_len, 0, max_echo_buffer_len - self->echo_buffer_len); + } } self->current_delay_ms = f_delay_ms; @@ -178,6 +179,12 @@ bool common_hal_audiodelays_echo_get_freq_shift(audiodelays_echo_obj_t *self) { } void common_hal_audiodelays_echo_set_freq_shift(audiodelays_echo_obj_t *self, bool freq_shift) { + // Clear the echo buffer and reset buffer position if changing freq_shift modes + if (self->freq_shift != freq_shift) { + memset(self->echo_buffer, 0, self->max_echo_buffer_len); + self->echo_buffer_left_pos = 0; + self->echo_buffer_right_pos = 0; + } self->freq_shift = freq_shift; uint32_t delay_ms = (uint32_t)synthio_block_slot_get(&self->delay_ms); recalculate_delay(self, delay_ms); @@ -277,15 +284,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * } uint32_t echo_buf_len = self->echo_buffer_len / sizeof(uint16_t); - - // Set our echo buffer position accounting for stereo - uint32_t echo_buffer_pos = 0; - if (self->freq_shift) { - echo_buffer_pos = self->echo_buffer_left_pos; - if (channel == 1) { - echo_buffer_pos = self->echo_buffer_right_pos; - } - } + uint32_t max_echo_buf_len = (self->max_echo_buffer_len >> (self->base.channel_count - 1)) / sizeof(uint16_t); // If we have no sample keep the echo echoing if (self->sample == NULL) { @@ -309,18 +308,22 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * int16_t echo, word = 0; uint32_t next_buffer_pos = 0; + // Get our echo buffer position and offset depending on current channel + uint32_t echo_buffer_offset = max_echo_buf_len * ((single_channel_output && channel == 1) || (!single_channel_output && (i % self->base.channel_count) == 1)); + uint32_t echo_buffer_pos = echo_buffer_offset ? self->echo_buffer_right_pos : self->echo_buffer_left_pos; + if (self->freq_shift) { - echo = echo_buffer[echo_buffer_pos >> 8]; + echo = echo_buffer[(echo_buffer_pos >> 8) + echo_buffer_offset]; next_buffer_pos = echo_buffer_pos + self->echo_buffer_rate; for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { - word = (int16_t)(echo_buffer[j % echo_buf_len] * decay); - echo_buffer[j % echo_buf_len] = word; + word = (int16_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay); + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = word; } } else { - echo = echo_buffer[self->echo_buffer_read_pos++]; + echo = echo_buffer[echo_buffer_pos + echo_buffer_offset]; word = (int16_t)(echo * decay); - echo_buffer[self->echo_buffer_write_pos++] = word; + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = word; } word = (int16_t)(echo * MIN(mix, MICROPY_FLOAT_CONST(1.0))); @@ -339,13 +342,15 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * if (self->freq_shift) { echo_buffer_pos = next_buffer_pos % (echo_buf_len << 8); + } else if (!self->freq_shift && echo_buffer_pos >= echo_buf_len) { + echo_buffer_pos = 0; + } + + // Update buffer position + if (echo_buffer_offset) { + self->echo_buffer_right_pos = echo_buffer_pos; } else { - if (self->echo_buffer_read_pos >= echo_buf_len) { - self->echo_buffer_read_pos = 0; - } - if (self->echo_buffer_write_pos >= echo_buf_len) { - self->echo_buffer_write_pos = 0; - } + self->echo_buffer_left_pos = echo_buffer_pos; } } } @@ -380,37 +385,42 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * int32_t echo, word = 0; uint32_t next_buffer_pos = 0; + + // Get our echo buffer position and offset depending on current channel + uint32_t echo_buffer_offset = max_echo_buf_len * ((single_channel_output && channel == 1) || (!single_channel_output && (i % self->base.channel_count) == 1)); + uint32_t echo_buffer_pos = echo_buffer_offset ? self->echo_buffer_right_pos : self->echo_buffer_left_pos; + if (self->freq_shift) { - echo = echo_buffer[echo_buffer_pos >> 8]; + echo = echo_buffer[(echo_buffer_pos >> 8) + echo_buffer_offset]; next_buffer_pos = echo_buffer_pos + self->echo_buffer_rate; } else { - echo = echo_buffer[self->echo_buffer_read_pos++]; + echo = echo_buffer[echo_buffer_pos + echo_buffer_offset]; word = (int32_t)(echo * decay + sample_word); } if (MP_LIKELY(self->base.bits_per_sample == 16)) { if (self->freq_shift) { for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { - word = (int32_t)(echo_buffer[j % echo_buf_len] * decay + sample_word); + word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word); word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); - echo_buffer[j % echo_buf_len] = (int16_t)word; + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)word; } } else { word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); - echo_buffer[self->echo_buffer_write_pos++] = (int16_t)word; + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)word; } } else { if (self->freq_shift) { for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { - word = (int32_t)(echo_buffer[j % echo_buf_len] * decay + sample_word); + word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word); // Do not have mix_down for 8 bit so just hard cap samples into 1 byte word = MIN(MAX(word, -128), 127); - echo_buffer[j % echo_buf_len] = (int8_t)word; + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int8_t)word; } } else { // Do not have mix_down for 8 bit so just hard cap samples into 1 byte word = MIN(MAX(word, -128), 127); - echo_buffer[self->echo_buffer_write_pos++] = (int8_t)word; + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int8_t)word; } } @@ -434,13 +444,15 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * if (self->freq_shift) { echo_buffer_pos = next_buffer_pos % (echo_buf_len << 8); + } else if (!self->freq_shift && echo_buffer_pos >= echo_buf_len) { + echo_buffer_pos = 0; + } + + // Update buffer position + if (echo_buffer_offset) { + self->echo_buffer_right_pos = echo_buffer_pos; } else { - if (self->echo_buffer_read_pos >= echo_buf_len) { - self->echo_buffer_read_pos = 0; - } - if (self->echo_buffer_write_pos >= echo_buf_len) { - self->echo_buffer_write_pos = 0; - } + self->echo_buffer_left_pos = echo_buffer_pos; } } } @@ -452,14 +464,6 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * self->sample_remaining_buffer += (n * (self->base.bits_per_sample / 8)); self->sample_buffer_length -= n; } - - if (self->freq_shift) { - if (channel == 0) { - self->echo_buffer_left_pos = echo_buffer_pos; - } else if (channel == 1) { - self->echo_buffer_right_pos = echo_buffer_pos; - } - } } // Finally pass our buffer and length to the calling audio function diff --git a/shared-module/audiodelays/Echo.h b/shared-module/audiodelays/Echo.h index 7f5dbb69f090a..cc37f7030be0e 100644 --- a/shared-module/audiodelays/Echo.h +++ b/shared-module/audiodelays/Echo.h @@ -37,12 +37,9 @@ typedef struct { uint32_t echo_buffer_len; // bytes uint32_t max_echo_buffer_len; // bytes - uint32_t echo_buffer_read_pos; // words - uint32_t echo_buffer_write_pos; // words - + uint32_t echo_buffer_left_pos; // words (<< 8 when freq_shift=True) + uint32_t echo_buffer_right_pos; // words (<< 8 when freq_shift=True) uint32_t echo_buffer_rate; // words << 8 - uint32_t echo_buffer_left_pos; // words << 8 - uint32_t echo_buffer_right_pos; // words << 8 mp_obj_t sample; } audiodelays_echo_obj_t; diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index cf5136f4e6bb6..ae7d3f02d5127 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -91,6 +91,40 @@ uint8_t displayio_colorconverter_compute_hue(uint32_t color_rgb888) { return hue; } +uint8_t displayio_colorconverter_compute_sixcolor(uint32_t color_rgb888) { + // This is DDX=1, the default for the displays. + uint8_t chroma = displayio_colorconverter_compute_chroma(color_rgb888); + if (chroma >= 64) { + uint8_t hue = displayio_colorconverter_compute_hue(color_rgb888); + // Red 0 + if (hue < 10) { + return 0x3; + } + // Yellow 42 + if (hue < 42 + 21) { + return 0x2; + } + // Green 85 + if (hue < 85 + 42) { + return 0x6; + } + // Blue 170 + if (hue < 170 + 42) { + return 0x5; + } + + // The rest is red to 255 + return 0x3; + } else { + uint8_t luma = displayio_colorconverter_compute_luma(color_rgb888); + if (luma >= 128) { + return 0x1; // White + } else { + return 0x0; // Black + } + } +} + uint8_t displayio_colorconverter_compute_sevencolor(uint32_t color_rgb888) { // This is DDX=1, the default for the displays. uint8_t chroma = displayio_colorconverter_compute_chroma(color_rgb888); @@ -309,7 +343,9 @@ void displayio_convert_color(const _displayio_colorspace_t *colorspace, bool dit return; } else if (colorspace->depth == 4) { uint8_t packed; - if (colorspace->sevencolor) { + if (colorspace->sixcolor) { + packed = displayio_colorconverter_compute_sixcolor(pixel); + } else if (colorspace->sevencolor) { packed = displayio_colorconverter_compute_sevencolor(pixel); } else { packed = displayio_colorconverter_compute_rgbd(pixel); diff --git a/shared-module/displayio/ColorConverter.h b/shared-module/displayio/ColorConverter.h index 60efc132f9ae5..d3dbedfe160ab 100644 --- a/shared-module/displayio/ColorConverter.h +++ b/shared-module/displayio/ColorConverter.h @@ -41,5 +41,6 @@ uint8_t displayio_colorconverter_compute_rgbd(uint32_t color_rgb888); uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888); uint8_t displayio_colorconverter_compute_chroma(uint32_t color_rgb888); uint8_t displayio_colorconverter_compute_hue(uint32_t color_rgb888); +uint8_t displayio_colorconverter_compute_sixcolor(uint32_t color_rgb888); uint8_t displayio_colorconverter_compute_sevencolor(uint32_t color_rgb888); void displayio_colorconverter_compute_tricolor(const _displayio_colorspace_t *colorspace, uint8_t pixel_hue, uint32_t *color); diff --git a/shared-module/displayio/Palette.h b/shared-module/displayio/Palette.h index 092b934b66a24..bb87a93d98133 100644 --- a/shared-module/displayio/Palette.h +++ b/shared-module/displayio/Palette.h @@ -19,6 +19,7 @@ typedef struct { uint8_t grayscale_bit; // The lowest grayscale bit. Normally 8 - depth. bool grayscale; bool tricolor; + bool sixcolor; // Spectra6 e-ink screens. bool sevencolor; // Acep e-ink screens. bool pixels_in_byte_share_row; bool reverse_pixels_in_byte; diff --git a/shared-module/epaperdisplay/EPaperDisplay.c b/shared-module/epaperdisplay/EPaperDisplay.c index 86ecff29b1102..a5a303d82ae75 100644 --- a/shared-module/epaperdisplay/EPaperDisplay.c +++ b/shared-module/epaperdisplay/EPaperDisplay.c @@ -36,7 +36,7 @@ void common_hal_epaperdisplay_epaperdisplay_construct(epaperdisplay_epaperdispla uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, const uint8_t *refresh_sequence, uint16_t refresh_sequence_len, mp_float_t refresh_time, const mcu_pin_obj_t *busy_pin, bool busy_state, mp_float_t seconds_per_frame, - bool chip_select, bool grayscale, bool acep, bool two_byte_sequence_length, bool address_little_endian) { + bool chip_select, bool grayscale, bool acep, bool spectra6, bool two_byte_sequence_length, bool address_little_endian) { uint16_t color_depth = 1; bool core_grayscale = true; if (highlight_color != 0x000000) { @@ -46,9 +46,10 @@ void common_hal_epaperdisplay_epaperdisplay_construct(epaperdisplay_epaperdispla } else { self->core.colorspace.tricolor = false; } - self->acep = acep; + self->acep = acep || spectra6; + self->core.colorspace.sixcolor = spectra6; self->core.colorspace.sevencolor = acep; - if (acep) { + if (self->acep) { color_depth = 4; // bits. 7 colors + clean grayscale = false; core_grayscale = false; @@ -338,7 +339,7 @@ static bool epaperdisplay_epaperdisplay_refresh_area(epaperdisplay_epaperdisplay } else if (self->core.colorspace.tricolor) { self->core.colorspace.grayscale = false; displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); - } else if (self->core.colorspace.sevencolor) { + } else if (self->core.colorspace.sixcolor || self->core.colorspace.sevencolor) { displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); } } else { diff --git a/shared-module/touchio/TouchIn.c b/shared-module/touchio/TouchIn.c index b81b52b44415f..268055d14bf53 100644 --- a/shared-module/touchio/TouchIn.c +++ b/shared-module/touchio/TouchIn.c @@ -86,7 +86,7 @@ void common_hal_touchio_touchin_deinit(touchio_touchin_obj_t *self) { self->digitalinout = MP_OBJ_NULL; } -void touchin_reset() { +void touchin_reset(void) { } bool common_hal_touchio_touchin_get_value(touchio_touchin_obj_t *self) { diff --git a/shared-module/usb_cdc/__init__.c b/shared-module/usb_cdc/__init__.c index 0248c0f180fdb..9a9f158f28cfb 100644 --- a/shared-module/usb_cdc/__init__.c +++ b/shared-module/usb_cdc/__init__.c @@ -356,10 +356,10 @@ size_t usb_vendor_descriptor_length(void) { static uint8_t *ms_os_20_descriptor = NULL; -size_t vendor_ms_os_20_descriptor_length() { +size_t vendor_ms_os_20_descriptor_length(void) { return ms_os_20_descriptor != NULL ? sizeof(ms_os_20_descriptor_template) : 0; } -uint8_t const *vendor_ms_os_20_descriptor() { +uint8_t const *vendor_ms_os_20_descriptor(void) { return ms_os_20_descriptor; } diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index 680a9f157c360..3ac752f327ce3 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -539,6 +539,7 @@ displayio_area_t *vectorio_vector_shape_get_refresh_areas(vectorio_vector_shape_ self->ephemeral_dirty_area.next = tail; tail = &self->ephemeral_dirty_area; } else { + self->current_area_dirty = true; self->current_area.next = tail; tail = &self->current_area; VECTORIO_SHAPE_DEBUG("%p get_refresh_area: redrawing current: {(%3d,%3d), (%3d,%3d)}\n", self, self->current_area.x1, self->current_area.y1, self->current_area.x2, self->current_area.y2); diff --git a/shared/netutils/netutils.c b/shared/netutils/netutils.c index 84b4405c41d38..cd1422f7c8058 100644 --- a/shared/netutils/netutils.c +++ b/shared/netutils/netutils.c @@ -63,7 +63,13 @@ void netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian return; } const char *s = addr_str; - const char *s_top = addr_str + addr_len; + const char *s_top; + // Scan for the end of valid address characters + for (s_top = addr_str; s_top < addr_str + addr_len; s_top++) { + if (!(*s_top == '.' || (*s_top >= '0' && *s_top <= '9'))) { + break; + } + } for (mp_uint_t i = 3; ; i--) { mp_uint_t val = 0; for (; s < s_top && *s != '.'; s++) { diff --git a/shared/runtime/gchelper.h b/shared/runtime/gchelper.h index 645ee837f5146..1e85e06f46ef9 100644 --- a/shared/runtime/gchelper.h +++ b/shared/runtime/gchelper.h @@ -41,6 +41,8 @@ typedef uintptr_t gc_helper_regs_t[4]; typedef uintptr_t gc_helper_regs_t[10]; #elif defined(__aarch64__) typedef uintptr_t gc_helper_regs_t[11]; // x19-x29 +#elif defined(__riscv) && (__riscv_xlen <= 64) +typedef uintptr_t gc_helper_regs_t[12]; // S0-S11 #endif #endif diff --git a/shared/runtime/gchelper_generic.c b/shared/runtime/gchelper_generic.c index 4ef2e73f7a2ee..0937231374057 100644 --- a/shared/runtime/gchelper_generic.c +++ b/shared/runtime/gchelper_generic.c @@ -150,6 +150,38 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { arr[10] = x29; } +#elif defined(__riscv) && (__riscv_xlen <= 64) + +// Fallback implementation for RV32I and RV64I, prefer gchelper_rv32i.s +// for RV32I targets or gchelper_rv64i.s for RV64I targets. + +static void gc_helper_get_regs(gc_helper_regs_t arr) { + register uintptr_t s0 asm ("x8"); + register uintptr_t s1 asm ("x9"); + register uintptr_t s2 asm ("x18"); + register uintptr_t s3 asm ("x19"); + register uintptr_t s4 asm ("x20"); + register uintptr_t s5 asm ("x21"); + register uintptr_t s6 asm ("x22"); + register uintptr_t s7 asm ("x23"); + register uintptr_t s8 asm ("x24"); + register uintptr_t s9 asm ("x25"); + register uintptr_t s10 asm ("x26"); + register uintptr_t s11 asm ("x27"); + arr[0] = s0; + arr[1] = s1; + arr[2] = s2; + arr[3] = s3; + arr[4] = s4; + arr[5] = s5; + arr[6] = s6; + arr[7] = s7; + arr[8] = s8; + arr[9] = s9; + arr[10] = s10; + arr[11] = s11; +} + #else #error "Architecture not supported for gc_helper_get_regs. Set MICROPY_GCREGS_SETJMP to use the fallback implementation." diff --git a/shared/runtime/gchelper_rv32i.s b/shared/runtime/gchelper_rv32i.s new file mode 100644 index 0000000000000..64248e771a861 --- /dev/null +++ b/shared/runtime/gchelper_rv32i.s @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Alessandro Gatti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .global gc_helper_get_regs_and_sp + .type gc_helper_get_regs_and_sp, @function + +gc_helper_get_regs_and_sp: + + /* Store registers into the given array. */ + + sw x8, 0(x10) /* Save S0. */ + sw x9, 4(x10) /* Save S1. */ + sw x18, 8(x10) /* Save S2. */ + sw x19, 12(x10) /* Save S3. */ + sw x20, 16(x10) /* Save S4. */ + sw x21, 20(x10) /* Save S5. */ + sw x22, 24(x10) /* Save S6. */ + sw x23, 28(x10) /* Save S7. */ + sw x24, 32(x10) /* Save S8. */ + sw x25, 36(x10) /* Save S9. */ + sw x26, 40(x10) /* Save S10. */ + sw x27, 44(x10) /* Save S11. */ + + /* Return the stack pointer. */ + + add x10, x0, x2 + jalr x0, x1, 0 + + .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp diff --git a/shared/runtime/gchelper_rv64i.s b/shared/runtime/gchelper_rv64i.s new file mode 100644 index 0000000000000..147a0e2bf5b5d --- /dev/null +++ b/shared/runtime/gchelper_rv64i.s @@ -0,0 +1,52 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Alessandro Gatti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + .global gc_helper_get_regs_and_sp + .type gc_helper_get_regs_and_sp, @function + +gc_helper_get_regs_and_sp: + + /* Store registers into the given array. */ + + sd x8, 0(x10) /* Save S0. */ + sd x9, 8(x10) /* Save S1. */ + sd x18, 16(x10) /* Save S2. */ + sd x19, 24(x10) /* Save S3. */ + sd x20, 32(x10) /* Save S4. */ + sd x21, 40(x10) /* Save S5. */ + sd x22, 48(x10) /* Save S6. */ + sd x23, 56(x10) /* Save S7. */ + sd x24, 64(x10) /* Save S8. */ + sd x25, 72(x10) /* Save S9. */ + sd x26, 80(x10) /* Save S10. */ + sd x27, 88(x10) /* Save S11. */ + + /* Return the stack pointer. */ + + add x10, x0, x2 + jalr x0, x1, 0 + + .size gc_helper_get_regs_and_sp, .-gc_helper_get_regs_and_sp diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 54384528a59a4..4ea8f434db96a 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -52,7 +52,6 @@ #endif pyexec_mode_kind_t pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; -int pyexec_system_exit = 0; #if MICROPY_REPL_INFO static bool repl_display_debugging_info = 0; @@ -85,9 +84,6 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input MICROPY_BOARD_BEFORE_PYTHON_EXEC(input_kind, exec_flags); #endif - // by default a SystemExit exception returns 0 - pyexec_system_exit = 0; - nlr_buf_t nlr; nlr.ret_val = NULL; if (nlr_push(&nlr) == 0) { @@ -193,7 +189,7 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(exception_obj)), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { // at the moment, the value of SystemExit is unused - ret = pyexec_system_exit; + ret = PYEXEC_FORCED_EXIT; // CIRCUITPY-CHANGE #if CIRCUITPY_ALARM } else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(exception_obj)), MP_OBJ_FROM_PTR(&mp_type_DeepSleepRequest))) { diff --git a/shared/runtime/pyexec.h b/shared/runtime/pyexec.h index 762b926c9c388..dffdc24772e7c 100644 --- a/shared/runtime/pyexec.h +++ b/shared/runtime/pyexec.h @@ -45,11 +45,6 @@ typedef struct { extern pyexec_mode_kind_t pyexec_mode_kind; -// Set this to the value (eg PYEXEC_FORCED_EXIT) that will be propagated through -// the pyexec functions if a SystemExit exception is raised by the running code. -// It will reset to 0 at the start of each execution (eg each REPL entry). -extern int pyexec_system_exit; - #define PYEXEC_FORCED_EXIT (0x100) // CIRCUITPY-CHANGE: additional flags #define PYEXEC_EXCEPTION (0x200) diff --git a/shared/runtime/semihosting.c b/shared/runtime/semihosting_arm.c similarity index 85% rename from shared/runtime/semihosting.c rename to shared/runtime/semihosting_arm.c index 18c7f5d57a3f3..f4d168f79bc81 100644 --- a/shared/runtime/semihosting.c +++ b/shared/runtime/semihosting_arm.c @@ -24,7 +24,7 @@ * THE SOFTWARE. */ -#include "semihosting.h" +#include "semihosting_arm.h" // Resources: // http://embed.rs/articles/2016/semi-hosting-rust/ @@ -34,16 +34,14 @@ #define SYS_OPEN 0x01 #define SYS_WRITEC 0x03 #define SYS_WRITE 0x05 +#define SYS_READ 0x06 #define SYS_READC 0x07 +#define SYS_EXIT 0x18 // Constants: #define OPEN_MODE_READ (0) // mode "r" #define OPEN_MODE_WRITE (4) // mode "w" -#ifndef __thumb__ -#error Semihosting is only implemented for ARM microcontrollers. -#endif - static int mp_semihosting_stdout; static uint32_t mp_semihosting_call(uint32_t num, const void *arg) { @@ -61,7 +59,13 @@ static uint32_t mp_semihosting_call(uint32_t num, const void *arg) { register uint32_t num_reg __asm__ ("r0") = num; register const void *args_reg __asm__ ("r1") = arg; __asm__ __volatile__ ( + #if defined(__ARM_ARCH_ISA_ARM) + "svc 0x00123456\n" // invoke semihosting call + #elif defined(__ARM_ARCH_ISA_THUMB) "bkpt 0xAB\n" // invoke semihosting call + #else + #error Unknown architecture + #endif : "+r" (num_reg) // call number and result : "r" (args_reg) // arguments : "memory"); // make sure args aren't optimized away @@ -85,10 +89,31 @@ void mp_semihosting_init() { mp_semihosting_stdout = mp_semihosting_open_console(OPEN_MODE_WRITE); } +void mp_semihosting_exit(int status) { + if (status == 0) { + status = 0x20026; + } + mp_semihosting_call(SYS_EXIT, (void *)(uintptr_t)status); +} + int mp_semihosting_rx_char() { return mp_semihosting_call(SYS_READC, NULL); } +// Returns 0 on success. +int mp_semihosting_rx_chars(char *str, size_t len) { + struct { + uint32_t fd; + const char *str; + uint32_t len; + } args = { + .fd = mp_semihosting_stdout, + .str = str, + .len = len, + }; + return mp_semihosting_call(SYS_READ, &args); +} + static void mp_semihosting_tx_char(char c) { mp_semihosting_call(SYS_WRITEC, &c); } diff --git a/shared/runtime/semihosting.h b/shared/runtime/semihosting_arm.h similarity index 79% rename from shared/runtime/semihosting.h rename to shared/runtime/semihosting_arm.h index d053a03edaae9..08fb66578ac14 100644 --- a/shared/runtime/semihosting.h +++ b/shared/runtime/semihosting_arm.h @@ -23,29 +23,33 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_LIB_UTILS_SEMIHOSTING_H -#define MICROPY_INCLUDED_LIB_UTILS_SEMIHOSTING_H +#ifndef MICROPY_INCLUDED_SHARED_RUNTIME_SEMIHOSTING_ARM_H +#define MICROPY_INCLUDED_SHARED_RUNTIME_SEMIHOSTING_ARM_H /* To use semi-hosting for a replacement UART: -- Add lib/semihosting/semihosting.c to the Makefile sources. +- Add shared/runtime/semihosting_arm.c to the Makefile sources. - Call mp_semihosting_init() in main(), around the time UART is initialized. - Replace mp_hal_stdin_rx_chr and similar in mphalport.c with the semihosting equivalent. -- Include lib/semihosting/semihosting.h in the relevant files. +- Include shared/runtime/semihosting_arm.h in the relevant files. Then make sure the debugger is attached and enables semihosting. In OpenOCD this is done with ARM semihosting enable followed by reset. The terminal will need further configuration to work with MicroPython (bash: stty raw -echo). +If mp_semihosting_rx_char() doesn't work then try mp_semihosting_rx_chars(str, 1). + */ #include #include void mp_semihosting_init(); +void mp_semihosting_exit(int status); int mp_semihosting_rx_char(); +int mp_semihosting_rx_chars(char *str, size_t len); uint32_t mp_semihosting_tx_strn(const char *str, size_t len); uint32_t mp_semihosting_tx_strn_cooked(const char *str, size_t len); -#endif // MICROPY_INCLUDED_LIB_UTILS_SEMIHOSTING_H +#endif // MICROPY_INCLUDED_SHARED_RUNTIME_SEMIHOSTING_ARM_H diff --git a/shared/runtime/semihosting_rv32.c b/shared/runtime/semihosting_rv32.c new file mode 100644 index 0000000000000..1d02b69b23ea8 --- /dev/null +++ b/shared/runtime/semihosting_rv32.c @@ -0,0 +1,481 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Alessandro Gatti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "semihosting_rv32.h" + +#if !defined(__riscv) || !defined(__riscv_xlen) || (__riscv_xlen != 32) +#error "This semihosting support code is only available for RV32 targets." +#endif + +// Features file magic header. +#define MAGIC_SIZE 4 +#define MAGIC_0 0x53 // 'S' +#define MAGIC_1 0x48 // 'H' +#define MAGIC_2 0x46 // 'B' +#define MAGIC_3 0x42 // 'F' + +#define CMDLINE_MIN_BUFFER_SIZE 80 + +#define SYS_OPEN 0x01 +#define SYS_CLOSE 0x02 +#define SYS_WRITEC 0x03 +#define SYS_WRITE0 0x04 +#define SYS_WRITE 0x05 +#define SYS_READ 0x06 +#define SYS_READC 0x07 +#define SYS_ISERROR 0x08 +#define SYS_ISTTY 0x09 +#define SYS_SEEK 0x0A +#define SYS_FLEN 0x0C +#define SYS_TMPNAM 0x0D +#define SYS_REMOVE 0x0E +#define SYS_RENAME 0x0F +#define SYS_CLOCK 0x10 +#define SYS_TIME 0x11 +#define SYS_SYSTEM 0x12 +#define SYS_ERRNO 0x13 +#define SYS_GET_CMDLINE 0x15 +#define SYS_HEAPINFO 0x16 +#define SYS_EXIT 0x18 +#define SYS_EXIT_EXTENDED 0x20 +#define SYS_ELAPSED 0x30 +#define SYS_TICKFREQ 0x31 + +// Extended features availability flags. +static bool exit_extended_available = false; +static bool split_stdout_stderr = false; + +// Perform a semihosting call with the given call number and using the given +// parameters block. +int mp_semihosting_call(uint32_t num, void *arg); + +// Convert the given fopen(3) open mode string into the appropriate integer +// value required by SYS_OPEN. If the mode is invalid, it will return -1. +static int mp_lookup_open_mode(const char *mode); + +// Computes the length of the given string. If it gets passed a NULL pointer +// it will return -1. +static int mp_strlen(const char *string); + +// Check which extended features are advertised by the host system. +static void mp_check_extended_features_availability(void); + +// Write the given string to the host system's debug console. +static int mp_write_to_debug_console(const char *string, size_t length); + +// The host system's STDOUT file handle. +int mp_semihosting_stdout = -1; + +// The host system's STDERR file handle. +int mp_semihosting_stderr = -1; + +int mp_semihosting_open(const char *file_name, const char *file_mode) { + if (file_name == NULL || file_mode == NULL) { + return -1; + } + + int file_name_length = mp_strlen(file_name); + if (file_name_length <= 0) { + return -1; + } + int file_open_mode = mp_lookup_open_mode(file_mode); + if (file_open_mode < 0) { + return -1; + } + + uint32_t arguments[3] = { (uintptr_t)file_name, file_open_mode, file_name_length }; + return mp_semihosting_call(SYS_OPEN, arguments); +} + +int mp_semihosting_close(int handle) { + uint32_t arguments[] = { handle }; + return mp_semihosting_call(SYS_CLOSE, arguments); +} + +void mp_semihosting_writec(char character) { + uint32_t arguments[] = { character }; + mp_semihosting_call(SYS_WRITEC, arguments); +} + +void mp_semihosting_write0(const char *string) { + if (string == NULL) { + return; + } + uint32_t arguments[] = { (uintptr_t)string }; + mp_semihosting_call(SYS_WRITE0, arguments); +} + +int mp_semihosting_write(int handle, const void *data, size_t length) { + if (data == NULL) { + return length; + } + if (length == 0) { + return 0; + } + + uint32_t arguments[] = { handle, (uintptr_t)data, length }; + return mp_semihosting_call(SYS_WRITE, arguments); +} + +int mp_semihosting_read(int handle, void *data, size_t length) { + if (data == NULL) { + return -1; + } + if (length == 0) { + return 0; + } + + uint32_t arguments[] = { handle, (uintptr_t)data, length }; + return mp_semihosting_call(SYS_READ, arguments); +} + +inline int mp_semihosting_readc(void) { + return mp_semihosting_call(SYS_READC, NULL); +} + +int mp_semihosting_iserror(int code) { + uint32_t arguments[] = { code }; + return mp_semihosting_call(SYS_ISERROR, arguments); +} + +int mp_semihosting_istty(int handle) { + uint32_t arguments[] = { handle }; + return mp_semihosting_call(SYS_ISTTY, arguments); +} + +int mp_semihosting_seek(int handle, uint32_t offset) { + uint32_t arguments[] = { handle, offset }; + return mp_semihosting_call(SYS_SEEK, arguments); +} + +int mp_semihosting_flen(int handle) { + uint32_t arguments[] = { handle }; + return mp_semihosting_call(SYS_FLEN, arguments); +} + +int mp_semihosting_tmpnam(uint8_t identifier, void *buffer, size_t buffer_length) { + if (buffer == NULL || buffer_length == 0) { + return -1; + } + + uint32_t arguments[] = { (uintptr_t)buffer, identifier, buffer_length }; + return mp_semihosting_call(SYS_TMPNAM, arguments); +} + +int mp_semihosting_remove(const char *file_name) { + if (file_name == NULL) { + return -1; + } + + int file_name_length = mp_strlen(file_name); + if (file_name_length <= 0) { + return -1; + } + + uint32_t arguments[] = { (uintptr_t)file_name, file_name_length }; + return mp_semihosting_call(SYS_REMOVE, arguments); +} + +int mp_semihosting_rename(const char *old_name, const char *new_name) { + if (old_name == NULL || new_name == NULL) { + return -1; + } + + int old_name_length = mp_strlen(old_name); + if (old_name_length <= 0) { + return -1; + } + + int new_name_length = mp_strlen(new_name); + if (new_name_length <= 0) { + return -1; + } + + uint32_t arguments[] = { + (uintptr_t)old_name, old_name_length, (uintptr_t)new_name, new_name_length + }; + return mp_semihosting_call(SYS_RENAME, arguments); +} + +inline int mp_semihosting_clock(void) { + return mp_semihosting_call(SYS_CLOCK, NULL); +} + +inline int mp_semihosting_time(void) { + return mp_semihosting_call(SYS_TIME, NULL); +} + +int mp_semihosting_system(const char *command) { + if (command == NULL) { + return -1; + } + + int command_length = mp_strlen(command); + if (command_length <= 0) { + return -1; + } + + uint32_t arguments[] = { (uintptr_t)command, command_length }; + return mp_semihosting_call(SYS_SYSTEM, arguments); +} + +inline int mp_semihosting_errno(void) { + return mp_semihosting_call(SYS_ERRNO, NULL); +} + +int mp_semihosting_get_cmdline(void *buffer, size_t buffer_length) { + if (buffer == NULL || buffer_length < CMDLINE_MIN_BUFFER_SIZE) { + return -1; + } + + uint32_t arguments[] = { (uintptr_t)buffer, buffer_length }; + return mp_semihosting_call(SYS_GET_CMDLINE, arguments); +} + +void mp_semihosting_heapinfo(mp_semihosting_heap_info_t *block) { + if (block == NULL) { + return; + } + + uint32_t arguments[] = { (uintptr_t)block }; + mp_semihosting_call(SYS_HEAPINFO, arguments); +} + +void mp_semihosting_exit(uint32_t code, uint32_t subcode) { + uint32_t arguments[] = { code, subcode }; + mp_semihosting_call(SYS_EXIT, arguments); + for (;;) {} +} + +void mp_semihosting_exit_extended(uint32_t code, uint32_t subcode) { + uint32_t arguments[] = { code, subcode }; + mp_semihosting_call(SYS_EXIT_EXTENDED, arguments); + for (;;) {} +} + +int mp_semihosting_elapsed(mp_semihosting_elapsed_ticks_t *ticks) { + if (ticks == NULL) { + return -1; + } + + uint32_t arguments[] = { (uintptr_t)ticks }; + return mp_semihosting_call(SYS_ELAPSED, arguments); +} + +inline int mp_semihosting_tickfreq(void) { + return mp_semihosting_call(SYS_TICKFREQ, NULL); +} + +void mp_semihosting_init() { + mp_check_extended_features_availability(); + mp_semihosting_stdout = mp_semihosting_open(":tt", "w"); + if (split_stdout_stderr) { + mp_semihosting_stderr = mp_semihosting_open(":tt", "a"); + } else { + mp_semihosting_stderr = mp_semihosting_stdout; + } +} + +void mp_check_extended_features_availability(void) { + int features_handle = mp_semihosting_open(":semihosting-features", "r"); + if (features_handle < 0) { + return; + } + + uint8_t magic_buffer[MAGIC_SIZE]; + if (mp_semihosting_flen(features_handle) < sizeof(magic_buffer)) { + mp_semihosting_close(features_handle); + return; + } + + if (mp_semihosting_read(features_handle, magic_buffer, sizeof(magic_buffer)) != 0) { + mp_semihosting_close(features_handle); + return; + } + + if (magic_buffer[0] != MAGIC_0 || + magic_buffer[1] != MAGIC_1 || + magic_buffer[2] != MAGIC_2 || + magic_buffer[3] != MAGIC_3) { + mp_semihosting_close(features_handle); + return; + } + + uint8_t features_byte = 0; + if (mp_semihosting_read(features_handle, &features_byte, sizeof(features_byte)) != 0) { + mp_semihosting_close(features_handle); + return; + } + + mp_semihosting_close(features_handle); + + exit_extended_available = (features_byte & 0x01) != 0; + split_stdout_stderr = (features_byte & 0x02) != 0; +} + +int mp_strlen(const char *string) { + int length = 0; + while (*string++ != 0) { + length += 1; + } + return length; +} + +int mp_lookup_open_mode(const char *mode) { + if (mode == NULL) { + return -1; + } + + int mode_found; + + switch (mode[0]) { + case 'r': + mode_found = 0x00; + break; + case 'w': + mode_found = 0x04; + break; + case 'a': + mode_found = 0x08; + break; + default: + return -1; + } + + switch (mode[1]) { + case 'b': + mode_found |= 0x01; + break; + case '+': + mode_found |= 0x02; + break; + case '\0': + return mode_found; + default: + return -1; + } + + switch (mode[2]) { + case 'b': + if (mode_found & 0x01) { + // 'b' was already seen. + return -1; + } + mode_found |= 1; + break; + case '+': + if (mode_found & 0x02) { + // '+' was already seen. + return -1; + } + mode_found |= 2; + break; + case '\0': + return mode_found; + default: + return -1; + } + + return mode[3] == '\0' ? mode_found : -1; +} + +int mp_semihosting_call(uint32_t num, void *arg) { + register uint32_t call_number_register __asm__ ("x10") = num; + register void *arguments_register __asm__ ("x11") = arg; + + __asm volatile ( + ".option push \n" // Transient options + ".option norvc \n" // Do not emit compressed instructions + ".align 4 \n" // 16 bytes alignment + "slli zero, zero, 0x1F \n" // Entry NOP + "ebreak \n" // Give control to the debugger + "srai zero, zero, 7 \n" // Semihosting call + ".option pop \n" // Restore previous options set + : "+r" (call_number_register) + : "r" (arguments_register) + : "memory" + ); + + return call_number_register; +} + +inline int mp_semihosting_rx_char() { + return mp_semihosting_call(SYS_READC, NULL); +} + +int mp_write_to_debug_console(const char *string, size_t length) { + if (length == 0) { + return 0; + } + + if (length == 1) { + mp_semihosting_writec(*string); + return 0; + } + + return mp_semihosting_write(mp_semihosting_stdout, string, length); +} + +void mp_semihosting_terminate(uint32_t code, uint32_t subcode) { + if (exit_extended_available) { + mp_semihosting_exit_extended(code, subcode); + } else { + mp_semihosting_exit(code, subcode); + } +} + +int mp_semihosting_tx_strn(const char *string, size_t length) { + if (string == NULL) { + return -1; + } + + return mp_write_to_debug_console(string, length); +} + +int mp_semihosting_tx_strn_cooked(const char *string, size_t length) { + if (string == NULL) { + return -1; + } + + if (length == 0) { + return 0; + } + + size_t current_offset = 0; + for (size_t index = 0; index < length; index++) { + if (string[index] != '\n') { + continue; + } + + mp_write_to_debug_console(string + current_offset, index - current_offset); + mp_semihosting_writec('\r'); + current_offset = index; + } + + return mp_write_to_debug_console(string + current_offset, length - current_offset); +} diff --git a/shared/runtime/semihosting_rv32.h b/shared/runtime/semihosting_rv32.h new file mode 100644 index 0000000000000..7cabd1692c1cf --- /dev/null +++ b/shared/runtime/semihosting_rv32.h @@ -0,0 +1,247 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2024 Alessandro Gatti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_SHARED_RUNTIME_SEMIHOSTING_RV32_H +#define MICROPY_INCLUDED_SHARED_RUNTIME_SEMIHOSTING_RV32_H + +/* + * To integrate semihosting, make sure to call mp_semihosting_init() first. + * Then, if the host system's STDOUT should be used instead of a UART, replace + * mp_hal_stdin_rx_chr and similar calls in mphalport.c with the semihosting + * equivalents. + * + * At runtime, make sure that the debugger is attached and semihosting is + * enabled on its end. The terminal must be configured in raw mode with local + * echo disabled, on Linux this can be done with "stty raw -echo" on the + * command line. + */ + +/* + * This follows the RISC-V Semihosting specification version 0.3. + * + * That document can be downloaded from + * https://github.com/riscv-non-isa/riscv-semihosting/releases/ + * + * Version 0.3 claims that the current RISC-V Semihosting implementation + * should follow Arm's, and more precisely the "Semihosting for AArch32 + * and AArch64" document, revision 2023Q3. + */ + +#include +#include +#include + +// A container for heap and stack pointers as returned by SYS_HEAPINFO. +typedef struct { + void *heap_base; + void *heap_limit; + void *stack_base; + void *stack_limit; +} mp_semihosting_heap_info_t; + +// A 64-bits value indicating how many ticks were counted since the target +// image's execution started. +typedef struct { + uint32_t low; + uint32_t high; +} mp_semihosting_elapsed_ticks_t; + +// The host system's STDOUT file handle. +extern int mp_semihosting_stdout; + +// The host system's STDERR file handle. If the host system does not support +// explicit STDOUT and STDERR handles, this handle will be aliased to STDOUT +// instead. +extern int mp_semihosting_stderr; + +/* + * Even though exit codes from 0x20000 to 0x20007 are part of the original Arm + * specification document, they are omitted due to them being tied to hardware + * events. Whilst some of them may still have a meaning on the RISC-V + * platform, it is not yet clear which ones are available and which ones are + * not. Thus, only "soft" error codes are provided here although the SYS_EXIT + * and SYS_EXIT_EXTENDED semihosting calls accept any 32-bits integer as an + * exit code. + */ + +enum { + MP_SEMIHOSTING_EXIT_BREAKPOINT = 0x20020, + MP_SEMIHOSTING_EXIT_WATCHPOINT, + MP_SEMIHOSTING_EXIT_STEP_COMPLETE, + MP_SEMIHOSTING_EXIT_RUNTIME_ERROR_UNKNOWN, + MP_SEMIHOSTING_EXIT_INTERNAL_ERROR, + MP_SEMIHOSTING_EXIT_USER_INTERRUPTION, + MP_SEMIHOSTING_EXIT_APPLICATION_EXIT, + MP_SEMIHOSTING_EXIT_STACK_OVERFLOW, + MP_SEMIHOSTING_EXIT_DIVISION_BY_ZERO, + MP_SEMIHOSTING_EXIT_OS_SPECIFIC +}; + +// Initialises semihosting support. +void mp_semihosting_init(); + +// Read a character from the host system's STDIN stream. +int mp_semihosting_rx_char(); + +// Write the given string to the host system's STDOUT stream. +int mp_semihosting_tx_strn(const char *string, size_t length); + +// Write the given string to the host system's STDOUT stream, writing a CR byte +// before each LF byte to be written. +int mp_semihosting_tx_strn_cooked(const char *string, size_t length); + +// Terminates execution with the given code and an optional subcode. This +// will choose the appropriate semihosting call (either SYS_EXIT or +// SYS_EXIT_EXTENDED) depending on the host system's reported capabilities. +noreturn void mp_semihosting_terminate(uint32_t code, uint32_t subcode); + +// Direct semihosting calls access. + +// Open a file on the host system with the given name and file mode. +// The file mode follows fopen(3)'s syntax. The function will return -1 if it +// failed to open the required file, or a file handle number if the operation +// succeeded. To see why the operation failed, call mp_semihosting_errno. +int mp_semihosting_open(const char *file_name, const char *file_mode); + +// Close a file previously opened with mp_semihosting_open. If the file cannot +// be closed, the function will return -1, otherwise it will return 0. To see +// why the operation failed, call mp_semihosting_errno. +int mp_semihosting_close(int handle); + +// Write the given character to the host system's STDOUT file handle. +void mp_semihosting_writec(char character); + +// Write the given NULL-terminated string to the host system's STDOUT file +// handle. +void mp_semihosting_write0(const char *string); + +// Write the given buffer to the given host system file handle. The function +// will return how many characters were left to be written (0 if the operation +// wrote the whole buffer), or -1 if the input buffer pointer is NULL. +int mp_semihosting_write(int handle, const void *data, size_t length); + +// Read from the given host system file handle into the given buffer. The +// function will return how many characters were left to be read (0 if the +// operation read whole buffer), or -1 if the input buffer pointer is NULL. +int mp_semihosting_read(int handle, void *data, size_t length); + +// Read a single character from the host system's STDIN file handle. +int mp_semihosting_readc(void); + +// Check whether the given result code represents an error. The function will +// return a non-zero value if the code is indeed an error, or zero otherwise. +int mp_semihosting_iserror(int code); + +// Check whether the given host system file handle is mapped to an interactive +// device. The function will return 1 if the handle is mapped to an +// interactive device, 0 if it is mapped to a regular file, and anything else +// if an error occurred. +int mp_semihosting_istty(int handle); + +// Move the file pointer on the given host system's file handle to the given +// absolute offset (in bytes). The function will return 0 if the file pointer +// was moved to the requested position, or a negative value if it was not +// possible to do so. To see why the operation failed, call +// mp_semihosting_errno. +int mp_semihosting_seek(int handle, uint32_t offset); + +// Get the length (in bytes) of the host system's file mapped to the given +// handle. The function will return a negative value if an error occurred, or +// the requested file's length (in bytes). +int mp_semihosting_flen(int handle); + +// Create a temporary file on the host system. The function requires a file +// identifier between 0 and 255 (inclusive) that will be bound to the requested +// temporary file. Subsequent calls to mp_semihosting_tmpnam with the same +// identifier will always return the same host system file name. On success, +// the function will fill the given buffer with the host system's file name, +// and will return 0. If the buffer pointer is NULL, the buffer name area is +// too small, or the operation failed on the host system's end, the function +// will return -1 instead. Make sure that the buffer is big enough to contain +// a host system's full path name. +int mp_semihosting_tmpnam(uint8_t identifier, void *buffer, size_t buffer_length); + +// Delete a file on the host system's matching the given file name. The +// function will return 0 if the deletion operation succeeded, or a host system +// dependent error code instead. +int mp_semihosting_remove(const char *file_name); + +// Rename a file on the host system's name matching the given file name to the +// new chosen name. The function will return 0 if the rename operation +// succeeded, or a host system dependent error code instead. +int mp_semihosting_rename(const char *old_name, const char *new_name); + +// Get how many hundredths of a second passed since execution started. If an +// error occurred whilst retrieving clock value, the function will return -1. +int mp_semihosting_clock(void); + +// Get the host system's clock in seconds since midnight of January 1st, 1970 +// at UTC. +int mp_semihosting_time(void); + +// Execute the given command on the host system. The function will return the +// command's result code retrieved on the host system. +int mp_semihosting_system(const char *command); + +// Get the last operation's status code. The function will return the host +// system's errno variable contents, and can be used to see the exact result +// code for failed I/O operations. +int mp_semihosting_errno(void); + +// Get the host system's command line that started execution of the target +// image. The function will fill the given buffer with the command line +// arguments passed to the target executable. The function will return 0 on +// success, or -1 if it failed. Make sure that the buffer can contain at +// least 80 bytes, as it is the minimum supported size defined by the +// specifications document. +int mp_semihosting_get_cmdline(void *buffer, size_t buffer_length); + +// Fill the given heap info structure with the system's stack and heap +// start/end addresses. +void mp_semihosting_heapinfo(mp_semihosting_heap_info_t *block); + +// Terminate the execution with the given reason code and optional subcode. +// This should be preferred over mp_semihosting_exit_extended if the host +// system does not support the SYS_EXIT_EXTENDED semihosting call. In doubt +// use mp_semihosting_terminate instead. +noreturn void mp_semihosting_exit(uint32_t code, uint32_t subcode); + +// Terminate the execution with the given reason code and optional subcode. +// This should be preferred over mp_semihosting_exit if the host system +// supports this semihosting call. In doubt use mp_semihosting_terminate +// instead. +noreturn void mp_semihosting_exit_extended(uint32_t code, uint32_t subcode); + +// Fill the given structure with how many ticks were counted since execution +// started. On success, the function will return 0, or -1 if it was not +// possible to compute the ticks count. +int mp_semihosting_elapsed(mp_semihosting_elapsed_ticks_t *ticks); + +// Get the system's tick frequency. If this value is not known, the function +// will return -1 instead. +int mp_semihosting_tickfreq(void); + +#endif // MICROPY_INCLUDED_SHARED_SEMIHOSTING_RUNTIME_RV32_H diff --git a/shared/timeutils/timeutils.h b/shared/timeutils/timeutils.h index e2a2666e910b7..01f54586e1315 100644 --- a/shared/timeutils/timeutils.h +++ b/shared/timeutils/timeutils.h @@ -52,9 +52,11 @@ mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date); void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm); +// Year is absolute, month/date are 1-based, hour/minute/second are 0-based. mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second); +// Year is absolute, month/mday are 1-based, hours/minutes/seconds are 0-based. mp_uint_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday, mp_int_t hours, mp_int_t minutes, mp_int_t seconds); @@ -66,10 +68,12 @@ static inline void timeutils_seconds_since_epoch_to_struct_time(uint64_t t, time timeutils_seconds_since_2000_to_struct_time(t - TIMEUTILS_SECONDS_1970_TO_2000, tm); } +// Year is absolute, month/mday are 1-based, hours/minutes/seconds are 0-based. static inline uint64_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { return timeutils_mktime_2000(year, month, mday, hours, minutes, seconds) + TIMEUTILS_SECONDS_1970_TO_2000; } +// Year is absolute, month/date are 1-based, hour/minute/second are 0-based. static inline uint64_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { // TODO this will give incorrect results for dates before 2000/1/1 diff --git a/shared/upytesthelper/upytesthelper.c b/shared/upytesthelper/upytesthelper.c deleted file mode 100644 index ba20037f7ac04..0000000000000 --- a/shared/upytesthelper/upytesthelper.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Linaro Limited - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include - -#include "py/mphal.h" -#include "py/gc.h" -#include "py/runtime.h" -#include "py/compile.h" -#include "upytesthelper.h" - -#if !MICROPY_PY_SYS_PATH -#error "upytesthelper requires MICROPY_PY_SYS_PATH=1" -#endif - -#if !MICROPY_PY_SYS_ARGV -#error "upytesthelper requires MICROPY_PY_SYS_ARGV=1" -#endif - -static const char *test_exp_output; -static int test_exp_output_len, test_rem_output_len; -static int test_failed; -static void *heap_start, *heap_end; - -void upytest_set_heap(void *start, void *end) { - heap_start = start; - heap_end = end; -} - -void upytest_set_expected_output(const char *output, unsigned len) { - test_exp_output = output; - test_exp_output_len = test_rem_output_len = len; - test_failed = false; -} - -bool upytest_is_failed(void) { - if (test_failed) { - return true; - } - #if 0 - if (test_rem_output_len != 0) { - printf("remaining len: %d\n", test_rem_output_len); - } - #endif - return test_rem_output_len != 0; -} - -// MP_PLAT_PRINT_STRN() should be redirected to this function. -// It will pass-through any content to mp_hal_stdout_tx_strn_cooked() -// (the default value of MP_PLAT_PRINT_STRN), but will also match -// it to the expected output as set by upytest_set_expected_output(). -// If mismatch happens, upytest_is_failed() returns true. -void upytest_output(const char *str, mp_uint_t len) { - if (!test_failed) { - if (len > test_rem_output_len) { - test_failed = true; - } else { - test_failed = memcmp(test_exp_output, str, len); - #if 0 - if (test_failed) { - printf("failed after char %u, within %d chars, res: %d\n", - test_exp_output_len - test_rem_output_len, (int)len, test_failed); - for (int i = 0; i < len; i++) { - if (str[i] != test_exp_output[i]) { - printf("%d %02x %02x\n", i, str[i], test_exp_output[i]); - } - } - } - #endif - test_exp_output += len; - test_rem_output_len -= len; - } - } - mp_hal_stdout_tx_strn_cooked(str, len); -} - -void upytest_execute_test(const char *src) { - // To provide clean room for each test, interpreter and heap are - // reinitialized before running each. - gc_init(heap_start, heap_end); - mp_init(); - mp_sys_path = mp_obj_new_list(0, NULL); - #if MICROPY_MODULE_FROZEN - mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__dot_frozen)); - #endif - mp_obj_list_init(mp_sys_argv, 0); - - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); - qstr source_name = lex->source_name; - mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); - mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false); - mp_call_function_0(module_fun); - nlr_pop(); - } else { - mp_obj_t exc = (mp_obj_t)nlr.ret_val; - if (mp_obj_is_subclass_fast(mp_obj_get_type(exc), &mp_type_SystemExit)) { - // Assume that sys.exit() is called to skip the test. - // TODO: That can be always true, we should set up convention to - // use specific exit code as skip indicator. - tinytest_set_test_skipped_(); - goto end; - } - mp_obj_print_exception(&mp_plat_print, exc); - tt_abort_msg("Uncaught exception\n"); - } - - if (upytest_is_failed()) { - tinytest_set_test_failed_(); - } - -end: - mp_deinit(); -} diff --git a/supervisor/shared/background_callback.c b/supervisor/shared/background_callback.c index 309210b7a12ae..ffeb78bbb8371 100644 --- a/supervisor/shared/background_callback.c +++ b/supervisor/shared/background_callback.c @@ -58,7 +58,7 @@ inline bool background_callback_pending(void) { static int background_prevention_count; -void PLACE_IN_ITCM(background_callback_run_all)() { +void PLACE_IN_ITCM(background_callback_run_all)(void) { port_background_task(); if (!background_callback_pending()) { return; @@ -89,13 +89,13 @@ void PLACE_IN_ITCM(background_callback_run_all)() { CALLBACK_CRITICAL_END; } -void background_callback_prevent() { +void background_callback_prevent(void) { CALLBACK_CRITICAL_BEGIN; ++background_prevention_count; CALLBACK_CRITICAL_END; } -void background_callback_allow() { +void background_callback_allow(void) { CALLBACK_CRITICAL_BEGIN; --background_prevention_count; CALLBACK_CRITICAL_END; @@ -103,7 +103,7 @@ void background_callback_allow() { // Filter out queued callbacks if they are allocated on the heap. -void background_callback_reset() { +void background_callback_reset(void) { background_callback_t *new_head = NULL; background_callback_t **previous_next = &new_head; background_callback_t *new_tail = NULL; diff --git a/supervisor/shared/bluetooth/bluetooth.c b/supervisor/shared/bluetooth/bluetooth.c index 73c05139eeea3..055a5cdf1fdfd 100644 --- a/supervisor/shared/bluetooth/bluetooth.c +++ b/supervisor/shared/bluetooth/bluetooth.c @@ -189,6 +189,7 @@ void supervisor_bluetooth_init(void) { boot_in_discovery_mode = false; if (reset_reason != RESET_REASON_POWER_ON && reset_reason != RESET_REASON_RESET_PIN && + reset_reason != RESET_REASON_DEEP_SLEEP_ALARM && reset_reason != RESET_REASON_UNKNOWN && reset_reason != RESET_REASON_SOFTWARE) { return; diff --git a/supervisor/shared/cpu_regs.h b/supervisor/shared/cpu_regs.h index 335201fe94231..8243c2388cd9b 100644 --- a/supervisor/shared/cpu_regs.h +++ b/supervisor/shared/cpu_regs.h @@ -7,7 +7,7 @@ #pragma once #ifdef __arm__ -#define INTEGER_REGS 8 +#define INTEGER_REGS 10 #ifdef __ARM_FP #define FLOATING_POINT_REGS 16 #endif diff --git a/supervisor/shared/reload.c b/supervisor/shared/reload.c index fb7ff0403c259..862c4ccebc7aa 100644 --- a/supervisor/shared/reload.c +++ b/supervisor/shared/reload.c @@ -35,16 +35,16 @@ void reload_initiate(supervisor_run_reason_t run_reason) { port_wake_main_task(); } -void autoreload_reset() { +void autoreload_reset(void) { last_autoreload_trigger = 0; } -void autoreload_enable() { +void autoreload_enable(void) { autoreload_enabled = true; last_autoreload_trigger = 0; } -void autoreload_disable() { +void autoreload_disable(void) { autoreload_enabled = false; } @@ -56,11 +56,11 @@ void autoreload_resume(uint32_t suspend_reason_mask) { autoreload_suspended &= ~suspend_reason_mask; } -inline bool autoreload_is_enabled() { +inline bool autoreload_is_enabled(void) { return autoreload_enabled; } -void autoreload_trigger() { +void autoreload_trigger(void) { if (!autoreload_enabled || autoreload_suspended != 0) { return; } @@ -78,7 +78,7 @@ void autoreload_trigger() { } } -bool autoreload_ready() { +bool autoreload_ready(void) { if (last_autoreload_trigger == 0 || autoreload_suspended != 0) { return false; } diff --git a/supervisor/shared/status_leds.c b/supervisor/shared/status_leds.c index 0742b6485ebfd..ffe8b46b20b7c 100644 --- a/supervisor/shared/status_leds.c +++ b/supervisor/shared/status_leds.c @@ -112,7 +112,7 @@ static uint32_t current_status_color = 0; #endif static bool status_led_init_in_progress = false; -void status_led_init() { +void status_led_init(void) { if (status_led_init_in_progress) { // Avoid recursion. return; @@ -186,7 +186,7 @@ void status_led_init() { status_led_init_in_progress = false; } -void status_led_deinit() { +void status_led_deinit(void) { #ifdef MICROPY_HW_NEOPIXEL // Make sure the pin stays low for the reset period. The pin reset may pull // it up and stop the reset period. diff --git a/supervisor/shared/tick.c b/supervisor/shared/tick.c index e19b7c4e68134..346ef9a93c4c5 100644 --- a/supervisor/shared/tick.c +++ b/supervisor/shared/tick.c @@ -92,14 +92,14 @@ static uint64_t _get_raw_subticks(void) { return (ticks << 5) | subticks; } -uint64_t supervisor_ticks_ms64() { +uint64_t supervisor_ticks_ms64(void) { uint64_t result; result = port_get_raw_ticks(NULL); result = result * 1000 / 1024; return result; } -uint32_t supervisor_ticks_ms32() { +uint32_t supervisor_ticks_ms32(void) { return supervisor_ticks_ms64(); } diff --git a/tests/README.md b/tests/README.md index 54dd078053ef0..7bd7eb587177b 100644 --- a/tests/README.md +++ b/tests/README.md @@ -177,11 +177,21 @@ internal_bench/bytebuf: ## Test key/certificates -SSL/TLS tests in `multi_net` and `net_inet` use a -self-signed key/cert pair that is randomly generated and to be used for -testing/demonstration only. You should always generate your own key/cert. +SSL/TLS tests in `multi_net` and `net_inet` use self-signed key/cert pairs +that are randomly generated to be used for testing/demonstration only. -To generate a new self-signed RSA key/cert pair with openssl do: +To run tests on-device the `.der` files should be copied and the current time +set to ensure certs validity. This can be done with: +``` +$ mpremote rtc --set cp multi_net/*.der net_inet/*.der : +``` + +### Generating new test key/certificates + +The keys used for the unit tests are included in the tests folders so don't generally +need to be re-created by end users. This section is included here for reference only. + +A new self-signed RSA key/cert pair can be created with openssl: ``` $ openssl req -x509 -newkey rsa:2048 -keyout rsa_key.pem -out rsa_cert.pem -days 365 -nodes -subj '/CN=micropython.local/O=MicroPython/C=AU' ``` @@ -193,8 +203,9 @@ $ openssl pkey -in rsa_key.pem -out rsa_key.der -outform DER $ openssl x509 -in rsa_cert.pem -out rsa_cert.der -outform DER ``` -To test elliptic curve key/cert pairs, create a key then a certificate using: +For elliptic curve tests using key/cert pairs, create a key then a certificate using: ``` -$ openssl ecparam -name prime256v1 -genkey -noout -out ec_key.der -outform DER -$ openssl req -new -x509 -key ec_key.der -out ec_cert.der -outform DER -days 365 -nodes -subj '/CN=micropython.local/O=MicroPython/C=AU' +$ openssl ecparam -name prime256v1 -genkey -noout -out ec_key.pem +$ openssl x509 -in ec_key.pem -out ec_key.der -outform DER +$ openssl req -new -x509 -key ec_key.pem -out ec_cert.der -outform DER -days 365 -nodes -subj '/CN=micropython.local/O=MicroPython/C=AU' ``` diff --git a/tests/basics/builtin_str_hex.py b/tests/basics/builtin_str_hex.py index 7390c8eaee17c..9455883012c0d 100644 --- a/tests/basics/builtin_str_hex.py +++ b/tests/basics/builtin_str_hex.py @@ -20,5 +20,20 @@ "08090a0b0c0d0e0f", "7f80ff", "313233344142434461626364", + "ab\tcd\n ef ", + "ab cd ef", + "ab cd ef ", + " ab cd ef ", + # Invalid hex strings: + "abcde", # Odd number of hex digits + "ab cd e", + "a b cd ef", # Spaces between hex pairs + "ab cd e f ", + "abga", # Invalid hex digits + "ab_cd", + "ab:cd", ): - print(bytes.fromhex(x)) + try: + print(bytes.fromhex(x)) + except ValueError as e: + print("ValueError:", e) diff --git a/tests/basics/builtin_str_hex.py.exp b/tests/basics/builtin_str_hex.py.exp index 990dd8570767e..0309cad02d1a6 100644 --- a/tests/basics/builtin_str_hex.py.exp +++ b/tests/basics/builtin_str_hex.py.exp @@ -26,3 +26,14 @@ b'\x00\x01\x02\x03\x04\x05\x06\x07' b'\x08\t\n\x0b\x0c\r\x0e\x0f' b'\x7f\x80\xff' b'1234ABCDabcd' +b'\xab\xcd\xef' +b'\xab\xcd\xef' +b'\xab\xcd\xef' +b'\xab\xcd\xef' +ValueError: non-hex digit +ValueError: non-hex digit +ValueError: non-hex digit +ValueError: non-hex digit +ValueError: non-hex digit +ValueError: non-hex digit +ValueError: non-hex digit diff --git a/tests/basics/builtin_super.py b/tests/basics/builtin_super.py new file mode 100644 index 0000000000000..5f7c3ae017e7e --- /dev/null +++ b/tests/basics/builtin_super.py @@ -0,0 +1,15 @@ +# Check that super rejects invalid arguments. +try: + super(str, 0) +except TypeError: + print("TypeError") + +try: + super(str, int) +except TypeError: + print("TypeError") + +try: + super(0, int) +except TypeError: + print("TypeError") diff --git a/tests/basics/class_descriptor.py b/tests/basics/class_descriptor.py index 54f386230fec1..83d31674301d5 100644 --- a/tests/basics/class_descriptor.py +++ b/tests/basics/class_descriptor.py @@ -21,14 +21,41 @@ class Main: try: m.__class__ except AttributeError: + # Target doesn't support __class__. print("SKIP") raise SystemExit r = m.Forward if 'Descriptor' in repr(r.__class__): + # Target doesn't support descriptors. print('SKIP') raise SystemExit +# Test assignment and deletion. + print(r) m.Forward = 'a' del m.Forward + +# Test that lookup of descriptors like __get__ are not passed into __getattr__. + + +class NonDescriptor: + def __getattr__(self, attr): + print("getattr", attr) + + +class TestClass: + non_descriptor = NonDescriptor() + + +print(isinstance(TestClass().non_descriptor, NonDescriptor)) + +t = TestClass() +t.non_descriptor = 123 +print(t.non_descriptor) + +try: + del TestClass().non_descriptor +except AttributeError: + print("AttributeError") diff --git a/tests/basics/deque2.py b/tests/basics/deque2.py index 3552d5be37abe..ebc0872c7b4e0 100644 --- a/tests/basics/deque2.py +++ b/tests/basics/deque2.py @@ -31,6 +31,16 @@ d[3] = 5 print(d[3]) +# Access the last element via index, when the last element is at various locations +d = deque((), 2) +for i in range(4): + d.append(i) + print(i, d[-1]) + +# Write the last element then access all elements from the end +d[-1] = 4 +print(d[-2], d[-1]) + # Accessing indices out of bounds raises IndexError try: d[4] diff --git a/tests/basics/gen_yield_from_throw_repeat.py b/tests/basics/gen_yield_from_throw_repeat.py index 67378ff47a17a..96636a624432e 100644 --- a/tests/basics/gen_yield_from_throw_repeat.py +++ b/tests/basics/gen_yield_from_throw_repeat.py @@ -1,4 +1,3 @@ -# CIRCUITPY-CHANGE: micropython does not have this test file # Test throwing repeatedly into the same generator, where that generator # is yielding from another generator. diff --git a/tests/basics/generator_throw_repeat.py b/tests/basics/generator_throw_repeat.py index 2b099494d367c..6d6ef60a9b0d5 100644 --- a/tests/basics/generator_throw_repeat.py +++ b/tests/basics/generator_throw_repeat.py @@ -1,4 +1,3 @@ -# CIRCUITPY-CHANGE: micropython does not have this test file # Test throwing repeatedly into the same generator. diff --git a/tests/basics/int_big_to_small.py b/tests/basics/int_big_to_small.py new file mode 100644 index 0000000000000..64280d0c635f5 --- /dev/null +++ b/tests/basics/int_big_to_small.py @@ -0,0 +1,22 @@ +try: + import micropython + micropython.heap_lock +except: + print("SKIP") + raise SystemExit + +# All less than small int max. +for d in (0, 27, 1<<29, -1861, -(1<<29)): + i = 1<<70 + print(i) + j = (1<<70) + d + print(j) + # k should now be a small int. + k = j - i + print(k) + + # Now verify that working with k doesn't allocate (i.e. it's a small int). + micropython.heap_lock() + print(k + 20) + print(k // 20) + micropython.heap_unlock() diff --git a/tests/basics/int_big_to_small.py.exp b/tests/basics/int_big_to_small.py.exp new file mode 100644 index 0000000000000..1d4986e044372 --- /dev/null +++ b/tests/basics/int_big_to_small.py.exp @@ -0,0 +1,25 @@ +1180591620717411303424 +1180591620717411303424 +0 +20 +0 +1180591620717411303424 +1180591620717411303451 +27 +47 +1 +1180591620717411303424 +1180591620717948174336 +536870912 +536870932 +26843545 +1180591620717411303424 +1180591620717411301563 +-1861 +-1841 +-94 +1180591620717411303424 +1180591620716874432512 +-536870912 +-536870892 +-26843546 diff --git a/tests/basics/int_bytes.py b/tests/basics/int_bytes.py index 1f620158ecefc..d1999bebb0e86 100644 --- a/tests/basics/int_bytes.py +++ b/tests/basics/int_bytes.py @@ -26,6 +26,12 @@ except ValueError: print("ValueError") +# zero byte destination should also raise an error +try: + (1).to_bytes(0, "little") +except OverflowError: + print("OverflowError") + # CIRCUITPY-CHANGE: more tests # too small buffer should raise an error try: @@ -39,6 +45,19 @@ except OverflowError: print("OverflowError") +# except for converting 0 to a zero-length byte array +print((0).to_bytes(0, "big")) + +# byte length can fit the integer directly +print((0xFF).to_bytes(1, "little")) +print((0xFF).to_bytes(1, "big")) +print((0xEFF).to_bytes(2, "little")) +print((0xEFF).to_bytes(2, "big")) +print((0xCDEFF).to_bytes(3, "little")) +print((0xCDEFF).to_bytes(3, "big")) + +# OverFlowError if not big enough + try: (-256).to_bytes(2, "little", signed=False) except OverflowError: diff --git a/tests/basics/int_bytes_int64.py b/tests/basics/int_bytes_int64.py new file mode 100644 index 0000000000000..032dbccc5b14e --- /dev/null +++ b/tests/basics/int_bytes_int64.py @@ -0,0 +1,52 @@ +import sys + +# Depending on the port, the numbers in this test may be implemented as "small" +# native 64 bit ints, arbitrary precision large ints, or large integers using 64-bit +# long longs. + +try: + x = int.from_bytes(b"\x6F\xAB\xCD\x12\x34\x56\x78\xFB", "big") +except OverflowError: + print("SKIP") # Port can't represent this size of integer at all + raise SystemExit + +print(hex(x)) +b = x.to_bytes(8, "little") +print(b) +print(x.to_bytes(8, "big")) + +# padding in output +print(x.to_bytes(20, "little")) +print(x.to_bytes(20, "big")) + +# check that extra zero bytes don't change the internal int value +print(int.from_bytes(b + bytes(10), "little") == x) + +# can't write to a zero-length bytes object +try: + x.to_bytes(0, "little") +except OverflowError: + print("OverflowError") + +# or one that it too short +try: + x.to_bytes(7, "big") +except OverflowError: + print("OverflowError") + +# negative representations + +# MicroPython int.to_bytes() behaves as if signed=True for negative numbers +if "micropython" in repr(sys.implementation): + + def to_bytes_compat(i, l, e): + return i.to_bytes(l, e) +else: + # Implement MicroPython compatible behaviour for CPython + def to_bytes_compat(i, l, e): + return i.to_bytes(l, e, signed=i < 0) + + +print(to_bytes_compat(-x, 8, "little")) +print(to_bytes_compat(-x, 20, "big")) +print(to_bytes_compat(-x, 20, "little")) diff --git a/tests/basics/int_bytes_intbig.py b/tests/basics/int_bytes_intbig.py index e78f55de01fbc..073c8bf78927f 100644 --- a/tests/basics/int_bytes_intbig.py +++ b/tests/basics/int_bytes_intbig.py @@ -2,6 +2,8 @@ import skip_if skip_if.no_bigint() +import sys + # CIRCUITPY-CHANGE: signed support print((2**64).to_bytes(9, "little")) print((-2**64).to_bytes(9, "little", signed=True)) @@ -17,6 +19,10 @@ print(il.to_bytes(20, "little")) print(ib.to_bytes(20, "big")) +# check padding comes out correctly +print(il.to_bytes(40, "little")) +print(ib.to_bytes(40, "big")) + # check that extra zero bytes don't change the internal int value print(int.from_bytes(b + bytes(10), "little") == int.from_bytes(b, "little")) @@ -32,7 +38,38 @@ (-2**64).to_bytes(9, "little") except OverflowError: print("OverflowError") + +# negative representations + +# MicroPython int.to_bytes() behaves as if signed=True for negative numbers +if "micropython" in repr(sys.implementation): + + def to_bytes_compat(i, l, e): + return i.to_bytes(l, e) +else: + # Implement MicroPython compatible behaviour for CPython + def to_bytes_compat(i, l, e): + return i.to_bytes(l, e, signed=i < 0) + + +print(to_bytes_compat(-ib, 20, "big")) +print(to_bytes_compat(ib * -ib, 40, "big")) + +# case where an additional byte is needed for sign bit +ib = (2**64) - 1 +print(ib.to_bytes(8, "little")) + +ib *= -1 + try: (-2**64).to_bytes(9, "little", signed=False) except OverflowError: print("OverflowError") +try: + print(to_bytes_compat(ib, 8, "little")) +except OverflowError: + print("OverflowError") + + +print(to_bytes_compat(ib, 9, "little")) +print(to_bytes_compat(ib, 9, "big")) diff --git a/tests/basics/int_bytes_optional_args_cp311.py b/tests/basics/int_bytes_optional_args_cp311.py new file mode 100644 index 0000000000000..07fdcdd282110 --- /dev/null +++ b/tests/basics/int_bytes_optional_args_cp311.py @@ -0,0 +1,9 @@ +# Check optional byteorder argument (CPython 3.11+) +print((10).to_bytes(1)) +print((100).to_bytes(10)) +print(int.from_bytes(b"\0\0\0\0\0\0\0\0\0\x01")) +print(int.from_bytes(b"\x01\0")) + +# Check optional length argument (CPython 3.11+) +print((10).to_bytes()) +print((100).to_bytes()) diff --git a/tests/basics/int_bytes_optional_args_cp311.py.exp b/tests/basics/int_bytes_optional_args_cp311.py.exp new file mode 100644 index 0000000000000..6dffa2577fc0b --- /dev/null +++ b/tests/basics/int_bytes_optional_args_cp311.py.exp @@ -0,0 +1,6 @@ +b'\n' +b'\x00\x00\x00\x00\x00\x00\x00\x00\x00d' +1 +256 +b'\n' +b'd' diff --git a/tests/basics/string_format_intbig.py b/tests/basics/string_format_intbig.py new file mode 100644 index 0000000000000..a36c36752e705 --- /dev/null +++ b/tests/basics/string_format_intbig.py @@ -0,0 +1,15 @@ +# basic functionality test for {} format string using large integers + + +def test(fmt, *args): + print("{:8s}".format(fmt) + ">" + fmt.format(*args) + "<") + + +# Separator formatter + +test("{:,}", 123_456_789_012_345_678_901_234_567) +test("{:,}", 23_456_789_012_345_678_901_234_567) +test("{:,}", 3_456_789_012_345_678_901_234_567) +test("{:,}", -123_456_789_012_345_678_901_234_567) +test("{:,}", -23_456_789_012_345_678_901_234_567) +test("{:,}", -3_456_789_012_345_678_901_234_567) diff --git a/tests/basics/string_fstring.py b/tests/basics/string_fstring.py index 42d093b37b508..d94cc0cd3e630 100644 --- a/tests/basics/string_fstring.py +++ b/tests/basics/string_fstring.py @@ -65,3 +65,17 @@ def foo(a, b): # Still allow ! in expressions. print(f"{'1' if a != '456' else '0'!r:8s}") print(f"{'1' if a != '456' else '0'!s:8s}") + +# Concatenation of adjacent f-strings. +print(f"" f"") +print(f"a" f"b") +print(f"{x}" f"{y}") +print( + f"a{x}b---------------------------------" + f"cd---------------------------------" + f"e{y}f---------------------------------" +) + +# Raw f-strings. +print(rf"\r\a\w {'f'} \s\t\r\i\n\g") +print(fr"\r{x}") diff --git a/tests/basics/subclass_native_call.py b/tests/basics/subclass_native_call.py new file mode 100644 index 0000000000000..e77287060cc70 --- /dev/null +++ b/tests/basics/subclass_native_call.py @@ -0,0 +1,27 @@ +# test calling a subclass of a native class that supports calling + +# For this test we need a native class that can be subclassed (has make_new) +# and is callable (has call). The only one available is machine.Signal, which +# in turns needs PinBase. +try: + import machine + machine.PinBase + machine.Signal +except: + print("SKIP") + raise SystemExit + +class Pin(machine.PinBase): + #def __init__(self): + # self.v = 0 + + def value(self, v=None): + return 42 + +class MySignal(machine.Signal): + pass + +s = MySignal(Pin()) + +# apply call to the subclass, which should call the native base +print(s()) diff --git a/tests/basics/subclass_native_call.py.exp b/tests/basics/subclass_native_call.py.exp new file mode 100644 index 0000000000000..d81cc0710eb6c --- /dev/null +++ b/tests/basics/subclass_native_call.py.exp @@ -0,0 +1 @@ +42 diff --git a/tests/basics/subclass_native_init.py b/tests/basics/subclass_native_init.py index 38d2f23ac3814..64167fa037e0c 100644 --- a/tests/basics/subclass_native_init.py +++ b/tests/basics/subclass_native_init.py @@ -6,6 +6,35 @@ def __init__(self, a, b): super().__init__([a, b]) print(L(2, 3)) +# with keyword arguments, with star arguments and without because those use different C calls +class D(dict): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) +print(D()) +print(D([('a', 1)])) +print(D([('a', 1)], a=2, b=3)) +print(D(a=2, b=3)) + +class D(dict): + def __init__(self): + super().__init__() +print(D()) + +class D(dict): + def __init__(self): + super().__init__([]) +print(D()) + +class D(dict): + def __init__(self): + super().__init__(a=1) +print(D()) + +class D(dict): + def __init__(self): + super().__init__([], a=1) +print(D()) + # inherits implicitly from object class A: def __init__(self): diff --git a/tests/basics/subscr_tuple.py b/tests/basics/subscr_tuple.py index 0210e24df873d..3b2703b829f89 100644 --- a/tests/basics/subscr_tuple.py +++ b/tests/basics/subscr_tuple.py @@ -1,3 +1,4 @@ +# CIRCUITPY-CHANGE: micropython does not have this test file # subscripting a subclassed tuple class Foo(tuple): pass diff --git a/tests/cmdline/cmd_parsetree.py.exp b/tests/cmdline/cmd_parsetree.py.exp index 6ec553b8a9ae2..672c212a965b9 100644 --- a/tests/cmdline/cmd_parsetree.py.exp +++ b/tests/cmdline/cmd_parsetree.py.exp @@ -1,6 +1,6 @@ ---------------- [ 1] file_input_2(1) (n=10) - tok(6) + tok(5) [ 4] \(rule\|for_stmt\)(22) (n=4) id(i) [ 4] \(rule\|atom_paren\)(45) (n=1) @@ -9,7 +9,7 @@ NULL [ 6] \(rule\|expr_stmt\)(5) (n=2) id(a) - tok(16) + tok(15) [ 7] \(rule\|expr_stmt\)(5) (n=2) id(b) str(str) diff --git a/tests/cpydiff/core_class_super_init.py b/tests/cpydiff/core_class_super_init.py new file mode 100644 index 0000000000000..1774f61dd82e4 --- /dev/null +++ b/tests/cpydiff/core_class_super_init.py @@ -0,0 +1,31 @@ +""" +categories: Core,Classes +description: When inheriting native types, calling a method in ``__init__(self, ...)`` before ``super().__init__()`` raises an ``AttributeError`` (or segfaults if ``MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG`` is not enabled). +cause: MicroPython does not have separate ``__new__`` and ``__init__`` methods in native types. +workaround: Call ``super().__init__()`` first. +""" + + +class L1(list): + def __init__(self, a): + self.append(a) + + +try: + L1(1) + print("OK") +except AttributeError: + print("AttributeError") + + +class L2(list): + def __init__(self, a): + super().__init__() + self.append(a) + + +try: + L2(1) + print("OK") +except AttributeError: + print("AttributeError") diff --git a/tests/cpydiff/core_fstring_concat.py b/tests/cpydiff/core_fstring_concat.py index 63e40da5bdde9..1ef016d5230b6 100644 --- a/tests/cpydiff/core_fstring_concat.py +++ b/tests/cpydiff/core_fstring_concat.py @@ -1,14 +1,12 @@ """ categories: Core -description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces or are f-strings +description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces cause: MicroPython is optimised for code space. -workaround: Use the + operator between literal strings when either or both are f-strings +workaround: Use the + operator between literal strings when they are not both f-strings """ x, y = 1, 2 -# fmt: off print(f"aa{x}") # works print(f"{x}ab") # works print(f"a{{}}a{x}") # fails print(f"{x}a{{}}b") # fails -print(f"{x}{y}") # fails diff --git a/tests/cpydiff/core_fstring_parser.py b/tests/cpydiff/core_fstring_parser.py index dbbe5b3d083c3..87cf1e63ed8c2 100644 --- a/tests/cpydiff/core_fstring_parser.py +++ b/tests/cpydiff/core_fstring_parser.py @@ -5,6 +5,6 @@ workaround: Always use balanced braces and brackets in expressions inside f-strings """ -# fmt: off -print(f"{'hello { world'}") -print(f"{'hello ] world'}") +# CIRCUITPY-CHANGE: add noqa so ruff won't complain about unmatched braces +print(f"{'hello { world'}") # noqa +print(f"{'hello ] world'}") # noqa diff --git a/tests/cpydiff/core_fstring_raw.py b/tests/cpydiff/core_fstring_raw.py deleted file mode 100644 index 84e265f70fc52..0000000000000 --- a/tests/cpydiff/core_fstring_raw.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -categories: Core -description: Raw f-strings are not supported -cause: MicroPython is optimised for code space. -workaround: Unknown -""" - -rf"hello" diff --git a/tests/cpydiff/types_int_to_bytes.py b/tests/cpydiff/types_int_to_bytes.py new file mode 100644 index 0000000000000..6530a2a32ecb7 --- /dev/null +++ b/tests/cpydiff/types_int_to_bytes.py @@ -0,0 +1,16 @@ +""" +categories: Types,int +description: ``to_bytes`` method doesn't implement signed parameter. +cause: The ``signed`` keyword-only parameter is not implemented for ``int.to_bytes()``. + +When the integer is negative, MicroPython behaves the same as CPython ``int.to_bytes(..., signed=True)`` + +When the integer is non-negative, MicroPython behaves the same as CPython ``int.to_bytes(..., signed=False)``. + +(The difference is subtle, but in CPython a positive integer converted with ``signed=True`` may require one byte more in the output length, in order to fit the 0 sign bit.) + +workaround: Take care when calling ``to_bytes()`` on an integer value which may be negative. +""" + +x = -1 +print(x.to_bytes(1, "big")) diff --git a/tests/extmod/asyncio_get_event_loop.py b/tests/extmod/asyncio_get_event_loop.py index c9cfa7bf00ed9..6ecbb13b57a6a 100644 --- a/tests/extmod/asyncio_get_event_loop.py +++ b/tests/extmod/asyncio_get_event_loop.py @@ -1,5 +1,4 @@ # Test get_event_loop() -# Note: CPython deprecated get_event_loop() so this test needs a .exp try: import asyncio diff --git a/tests/extmod/asyncio_get_event_loop.py.exp b/tests/extmod/asyncio_get_event_loop.py.exp deleted file mode 100644 index 5d0fb3b2d2edd..0000000000000 --- a/tests/extmod/asyncio_get_event_loop.py.exp +++ /dev/null @@ -1,2 +0,0 @@ -start -end diff --git a/tests/extmod/asyncio_new_event_loop.py b/tests/extmod/asyncio_new_event_loop.py index 5bb31f1292bb1..bebc3bf70cc57 100644 --- a/tests/extmod/asyncio_new_event_loop.py +++ b/tests/extmod/asyncio_new_event_loop.py @@ -1,5 +1,4 @@ # Test Loop.new_event_loop() -# Note: CPython deprecated get_event_loop() so this test needs a .exp try: import asyncio @@ -7,6 +6,11 @@ print("SKIP") raise SystemExit +# CPython 3.12 deprecated calling get_event_loop() when there is no current event +# loop, so to make this test run on CPython requires setting the event loop. +if hasattr(asyncio, "set_event_loop"): + asyncio.set_event_loop(asyncio.new_event_loop()) + async def task(): for i in range(4): diff --git a/tests/extmod/asyncio_new_event_loop.py.exp b/tests/extmod/asyncio_new_event_loop.py.exp deleted file mode 100644 index 9e104fda39c94..0000000000000 --- a/tests/extmod/asyncio_new_event_loop.py.exp +++ /dev/null @@ -1,6 +0,0 @@ -start -task 0 -stop -start -task 0 -stop diff --git a/tests/extmod/select_ipoll.py b/tests/extmod/select_ipoll.py deleted file mode 100644 index 0b661c11c8331..0000000000000 --- a/tests/extmod/select_ipoll.py +++ /dev/null @@ -1,55 +0,0 @@ -# Test select.ipoll(). - -try: - import socket, select -except ImportError: - print("SKIP") - raise SystemExit - - -def print_poll_output(lst): - print([(type(obj), flags) for obj, flags in lst]) - - -poller = select.poll() - -# Use a new UDP socket for tests, which should be writable but not readable. -try: - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.bind(socket.getaddrinfo("127.0.0.1", 8000)[0][-1]) -except OSError: - print("SKIP") - raise SystemExit - -poller.register(s) - -# Basic polling. -print_poll_output(poller.ipoll(0)) - -# Pass in flags=1 for one-shot behaviour. -print_poll_output(poller.ipoll(0, 1)) - -# Socket should be deregistered and poll should return nothing. -print_poll_output(poller.ipoll(0)) - -# Create a second socket. -s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -s2.bind(socket.getaddrinfo("127.0.0.1", 8001)[0][-1]) - -# Register both sockets (to reset the first one). -poller.register(s) -poller.register(s2) - -# Basic polling with two sockets. -print_poll_output(poller.ipoll(0)) - -# Unregister the first socket, to test polling the remaining one. -poller.unregister(s) -print_poll_output(poller.ipoll(0)) - -# Unregister the second socket, to test polling none. -poller.unregister(s2) -print_poll_output(poller.ipoll(0)) - -s2.close() -s.close() diff --git a/tests/extmod/select_ipoll.py.exp b/tests/extmod/select_ipoll.py.exp deleted file mode 100644 index cbeabdce902c8..0000000000000 --- a/tests/extmod/select_ipoll.py.exp +++ /dev/null @@ -1,6 +0,0 @@ -[(, 4)] -[(, 4)] -[] -[(, 4), (, 4)] -[(, 4)] -[] diff --git a/tests/extmod/select_poll_custom.py b/tests/extmod/select_poll_custom.py deleted file mode 100644 index b854a8a14da55..0000000000000 --- a/tests/extmod/select_poll_custom.py +++ /dev/null @@ -1,102 +0,0 @@ -# Test custom pollable objects implemented in Python. - -from micropython import const - -try: - import socket, select, io -except ImportError: - print("SKIP") - raise SystemExit - -_MP_STREAM_POLL = const(3) -_MP_STREAM_GET_FILENO = const(10) - -_MP_STREAM_POLL_RD = const(0x0001) -_MP_STREAM_POLL_WR = const(0x0004) - - -def print_poll_output(lst): - print([(type(obj), flags) for obj, flags in lst]) - - -class CustomPollable(io.IOBase): - def __init__(self): - self.poll_state = 0 - - def ioctl(self, cmd, arg): - if cmd == _MP_STREAM_GET_FILENO: - # Bare-metal ports don't call this ioctl, so don't print it. - return -1 - - print("CustomPollable.ioctl", cmd, arg) - if cmd == _MP_STREAM_POLL: - if self.poll_state == "delay_rd": - self.poll_state = _MP_STREAM_POLL_RD - return 0 - elif self.poll_state < 0: - return self.poll_state - else: - return self.poll_state & arg - - -poller = select.poll() - -# Use a new UDP socket for tests, which should be writable but not readable. -try: - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.bind(socket.getaddrinfo("127.0.0.1", 8000)[0][-1]) -except OSError: - print("SKIP") - raise SystemExit - -x = CustomPollable() - -# Register both a file-descriptor-based object and a custom pure-Python object. -poller.register(s) -poller.register(x) - -# Modify the flags for the custom object. -poller.modify(x, select.POLLIN) - -# Test polling. -print_poll_output(poller.poll(0)) -x.poll_state = _MP_STREAM_POLL_WR -print_poll_output(poller.poll(0)) -x.poll_state = _MP_STREAM_POLL_RD -print_poll_output(poller.poll(0)) - -# The custom object becomes readable only after being polled. -poller.modify(s, select.POLLIN) -x.poll_state = "delay_rd" -print_poll_output(poller.poll()) - -# The custom object returns an error. -x.poll_state = -1000 -try: - poller.poll(0) -except OSError as er: - print("OSError", er.errno) - -# Register then unregister a socket (a native stream), then test -# that the Python object is still pollable. -s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -x.poll_state = _MP_STREAM_POLL_RD -poller.register(s2) -poller.unregister(s2) -print_poll_output(poller.poll()) - -# Test registering and unregistering multiple times. -for _ in range(2): - poller.unregister(s) - poller.unregister(x) - poller.register(s2) - poller.register(s, select.POLLIN) - poller.register(x, select.POLLIN) - poller.unregister(s2) - print_poll_output(poller.poll()) - -# Clean up. -poller.unregister(x) -poller.unregister(s) -s2.close() -s.close() diff --git a/tests/extmod/select_poll_custom.py.exp b/tests/extmod/select_poll_custom.py.exp deleted file mode 100644 index d85508bab240e..0000000000000 --- a/tests/extmod/select_poll_custom.py.exp +++ /dev/null @@ -1,17 +0,0 @@ -CustomPollable.ioctl 3 1 -[(, 4)] -CustomPollable.ioctl 3 1 -[(, 4)] -CustomPollable.ioctl 3 1 -[(, 4), (, 1)] -CustomPollable.ioctl 3 1 -CustomPollable.ioctl 3 1 -[(, 1)] -CustomPollable.ioctl 3 1 -OSError 1000 -CustomPollable.ioctl 3 1 -[(, 1)] -CustomPollable.ioctl 3 1 -[(, 1)] -CustomPollable.ioctl 3 1 -[(, 1)] diff --git a/tests/extmod/select_poll_eintr.py b/tests/extmod/select_poll_eintr.py deleted file mode 100644 index e1cbc2aaf57d0..0000000000000 --- a/tests/extmod/select_poll_eintr.py +++ /dev/null @@ -1,50 +0,0 @@ -# Test interruption of select.poll by EINTR signal, when -# MICROPY_PY_SELECT_POSIX_OPTIMISATIONS is enabled. - -try: - import time, gc, select, socket, _thread - - time.time_ns # Check for time_ns on MicroPython - select.poll # Raises AttributeError for CPython implementations without poll() -except (ImportError, AttributeError): - print("SKIP") - raise SystemExit - - -def thread_main(): - lock.acquire() - time.sleep(0.2) - print("thread gc start") - # The unix gc.collect() implementation will raise EINTR on other threads. - # Could possibly use _thread._interrupt_main() instead if MicroPython had it. - gc.collect() - print("thread gc end") - - -# Start a thread to interrupt the main thread during its call to poll. -lock = _thread.allocate_lock() -lock.acquire() -_thread.start_new_thread(thread_main, ()) - -# Use a new UDP socket for tests, which should be writable but not readable. -s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -s.bind(socket.getaddrinfo("127.0.0.1", 8000)[0][-1]) - -# Create the poller object. -poller = select.poll() -poller.register(s, select.POLLIN) - -# Poll on the UDP socket for a set timeout, which should be reached. -print("poll") -lock.release() -t0 = time.time_ns() -result = poller.poll(400) -dt_ms = (time.time_ns() - t0) / 1e6 -print("result:", result) -if 380 <= dt_ms <= 600: - print("dt in range") -else: - print("dt not in range:", dt_ms) - -# Clean up. -s.close() diff --git a/tests/extmod/select_poll_fd.py b/tests/extmod/select_poll_fd.py deleted file mode 100644 index 5f9dcc286a0cc..0000000000000 --- a/tests/extmod/select_poll_fd.py +++ /dev/null @@ -1,63 +0,0 @@ -# Test select.poll in combination with file descriptors. - -try: - import select, errno - - select.poll # Raises AttributeError for CPython implementations without poll() -except (ImportError, AttributeError): - print("SKIP") - raise SystemExit - -# Check that poll supports registering file descriptors (integers). -try: - select.poll().register(0) -except OSError: - print("SKIP") - raise SystemExit - -# Register invalid file descriptor. -try: - select.poll().register(-1) -except ValueError: - print("ValueError") - -# Test polling stdout, it should be writable. -poller = select.poll() -poller.register(1) -poller.modify(1, select.POLLOUT) -print(poller.poll()) - -# Unregister then re-register. -poller.unregister(1) -poller.register(1, select.POLLIN) - -# Poll for input, should return an empty list. -print(poller.poll(0)) - -# Test registering a very large number of file descriptors (will trigger -# EINVAL due to more than OPEN_MAX fds). Typically it's 1024 (and on GitHub CI -# we force this via `ulimit -n 1024`). -# CIRCUITPY-CHANGE: Skip this test. poller.poll() does not have a limit and will `assert False` -# The ulimit change in the micropython tests may not be working properly. -# on GitHub CI, the limit is far larger than 6000. It is 1024 on desktop Ubuntu, but -# higher on the runners. I don't think this test is testing what it means to test. -# poller = select.poll() -# fd_last = 0 -# for fd in range(6000): -# fd_last = fd -# poller.register(fd) -# try: -# poller.poll() -# assert False -# except OSError as er: -# print("fd_last", fd_last) -# print(er.errno == errno.EINVAL) - -# Register stdout/stderr, plus many extra ones to trigger the fd vector -# resizing. Then unregister the excess ones and verify poll still works. -poller = select.poll() -for fd in range(1, 1000): - poller.register(fd) -for i in range(3, 1000): - poller.unregister(i) -print(sorted(poller.poll())) diff --git a/tests/extmod/socket_udp_nonblock.py b/tests/extmod/socket_udp_nonblock.py deleted file mode 100644 index 1e74e2917dc30..0000000000000 --- a/tests/extmod/socket_udp_nonblock.py +++ /dev/null @@ -1,21 +0,0 @@ -# test non-blocking UDP sockets - -try: - import socket, errno -except ImportError: - print("SKIP") - raise SystemExit - -try: - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.bind(socket.getaddrinfo("127.0.0.1", 8000)[0][-1]) -except OSError: - print("SKIP") - raise SystemExit - -s.settimeout(0) - -try: - s.recv(1) -except OSError as er: - print("EAGAIN:", er.errno == errno.EAGAIN) diff --git a/tests/extmod/ssl_cadata.py b/tests/extmod/ssl_cadata.py deleted file mode 100644 index e66f6ca825baf..0000000000000 --- a/tests/extmod/ssl_cadata.py +++ /dev/null @@ -1,18 +0,0 @@ -# Test ssl.wrap_socket() with cadata passed in. - -try: - import io - import ssl -except ImportError: - print("SKIP") - raise SystemExit - -# Invalid cadata. -try: - ssl.wrap_socket(io.BytesIO(), cadata=b"!") -except TypeError: - # "cadata" keyword argument is not supported by axtls. - print("SKIP") - raise SystemExit -except ValueError as er: - print(repr(er)) diff --git a/tests/extmod/ssl_cadata.py.exp b/tests/extmod/ssl_cadata.py.exp deleted file mode 100644 index 9f1cf732e33ff..0000000000000 --- a/tests/extmod/ssl_cadata.py.exp +++ /dev/null @@ -1 +0,0 @@ -ValueError('invalid cert',) diff --git a/tests/extmod/ssl_ioctl.py b/tests/extmod/ssl_ioctl.py deleted file mode 100644 index 4db7c2df82aeb..0000000000000 --- a/tests/extmod/ssl_ioctl.py +++ /dev/null @@ -1,31 +0,0 @@ -# Test SSL ioctl method. -# Direct access to this method is only available if MICROPY_UNIX_COVERAGE is enabled. - -try: - import io, ssl - - io.BytesIO -except (ImportError, AttributeError): - print("SKIP") - raise SystemExit - -_MP_STREAM_POLL = 3 -_MP_STREAM_CLOSE = 4 -_MP_STREAM_GET_FILENO = 10 - -s = ssl.wrap_socket(io.BytesIO(), server_side=1, do_handshake=0) - -if not hasattr(s, "ioctl"): - print("SKIP") - raise SystemExit - -# These ioctl's should be unsupported. -for request in (-1, 0, _MP_STREAM_GET_FILENO): - try: - s.ioctl(request, 0) - except OSError: - print(request, "OSError") - -# These ioctl's should be supported. -for request in (_MP_STREAM_CLOSE, _MP_STREAM_POLL, _MP_STREAM_CLOSE): - print(request, s.ioctl(request, 0)) diff --git a/tests/extmod/ssl_ioctl.py.exp b/tests/extmod/ssl_ioctl.py.exp deleted file mode 100644 index 22208b00cc94d..0000000000000 --- a/tests/extmod/ssl_ioctl.py.exp +++ /dev/null @@ -1,6 +0,0 @@ --1 OSError -0 OSError -10 OSError -4 0 -3 32 -4 0 diff --git a/tests/extmod/ssl_poll.py b/tests/extmod/ssl_poll.py deleted file mode 100644 index 347e5f7d37a42..0000000000000 --- a/tests/extmod/ssl_poll.py +++ /dev/null @@ -1,196 +0,0 @@ -try: - import select - import ssl - import io - import binascii -except ImportError: - print("SKIP") - raise SystemExit - -from micropython import const - -_MP_STREAM_POLL_RD = const(0x0001) -_MP_STREAM_POLL_WR = const(0x0004) -_MP_STREAM_POLL_NVAL = const(0x0020) -_MP_STREAM_POLL = const(3) -_MP_STREAM_CLOSE = const(4) - - -# This self-signed key/cert pair is randomly generated and to be used for -# testing/demonstration only. You should always generate your own key/cert. -key = binascii.unhexlify( - b"3082013b020100024100cc20643fd3d9c21a0acba4f48f61aadd675f52175a9dcf07fbef" - b"610a6a6ba14abb891745cd18a1d4c056580d8ff1a639460f867013c8391cdc9f2e573b0f" - b"872d0203010001024100bb17a54aeb3dd7ae4edec05e775ca9632cf02d29c2a089b563b0" - b"d05cdf95aeca507de674553f28b4eadaca82d5549a86058f9996b07768686a5b02cb240d" - b"d9f1022100f4a63f5549e817547dca97b5c658038e8593cb78c5aba3c4642cc4cd031d86" - b"8f022100d598d870ffe4a34df8de57047a50b97b71f4d23e323f527837c9edae88c79483" - b"02210098560c89a70385c36eb07fd7083235c4c1184e525d838aedf7128958bedfdbb102" - b"2051c0dab7057a8176ca966f3feb81123d4974a733df0f958525f547dfd1c271f9022044" - b"6c2cafad455a671a8cf398e642e1be3b18a3d3aec2e67a9478f83c964c4f1f" -) -cert = binascii.unhexlify( - b"308201d53082017f020203e8300d06092a864886f70d01010505003075310b3009060355" - b"0406130258583114301206035504080c0b54686550726f76696e63653110300e06035504" - b"070c075468654369747931133011060355040a0c0a436f6d70616e7958595a3113301106" - b"0355040b0c0a436f6d70616e7958595a3114301206035504030c0b546865486f73744e61" - b"6d65301e170d3139313231383033333935355a170d3239313231353033333935355a3075" - b"310b30090603550406130258583114301206035504080c0b54686550726f76696e636531" - b"10300e06035504070c075468654369747931133011060355040a0c0a436f6d70616e7958" - b"595a31133011060355040b0c0a436f6d70616e7958595a3114301206035504030c0b5468" - b"65486f73744e616d65305c300d06092a864886f70d0101010500034b003048024100cc20" - b"643fd3d9c21a0acba4f48f61aadd675f52175a9dcf07fbef610a6a6ba14abb891745cd18" - b"a1d4c056580d8ff1a639460f867013c8391cdc9f2e573b0f872d0203010001300d06092a" - b"864886f70d0101050500034100b0513fe2829e9ecbe55b6dd14c0ede7502bde5d46153c8" - b"e960ae3ebc247371b525caeb41bbcf34686015a44c50d226e66aef0a97a63874ca5944ef" - b"979b57f0b3" -) - - -class _Pipe(io.IOBase): - def __init__(self): - self._other = None - self.block_reads = False - self.block_writes = False - - self.write_buffers = [] - self.last_poll_arg = None - - def readinto(self, buf): - if self.block_reads or len(self._other.write_buffers) == 0: - return None - - read_buf = self._other.write_buffers[0] - l = min(len(buf), len(read_buf)) - buf[:l] = read_buf[:l] - if l == len(read_buf): - self._other.write_buffers.pop(0) - else: - self._other.write_buffers[0] = read_buf[l:] - return l - - def write(self, buf): - if self.block_writes: - return None - - self.write_buffers.append(memoryview(bytes(buf))) - return len(buf) - - def ioctl(self, request, arg): - if request == _MP_STREAM_POLL: - self.last_poll_arg = arg - ret = 0 - if arg & _MP_STREAM_POLL_RD: - if not self.block_reads and self._other.write_buffers: - ret |= _MP_STREAM_POLL_RD - if arg & _MP_STREAM_POLL_WR: - if not self.block_writes: - ret |= _MP_STREAM_POLL_WR - return ret - - elif request == _MP_STREAM_CLOSE: - return 0 - - raise NotImplementedError() - - @classmethod - def new_pair(cls): - p1 = cls() - p2 = cls() - p1._other = p2 - p2._other = p1 - return p1, p2 - - -def assert_poll(s, i, arg, expected_arg, expected_ret): - ret = s.ioctl(_MP_STREAM_POLL, arg) - assert i.last_poll_arg == expected_arg - i.last_poll_arg = None - assert ret == expected_ret - - -def assert_raises(cb, *args, **kwargs): - try: - cb(*args, **kwargs) - raise AssertionError("should have raised") - except Exception as exc: - pass - - -client_io, server_io = _Pipe.new_pair() - -client_io.block_reads = True -client_io.block_writes = True -client_sock = ssl.wrap_socket(client_io, do_handshake=False) - -server_sock = ssl.wrap_socket(server_io, key=key, cert=cert, server_side=True, do_handshake=False) - -# Do a test read, at this point the TLS handshake wants to write, -# so it returns None: -assert client_sock.read(128) is None - -# Polling for either read or write actually check if the underlying socket can write: -assert_poll(client_sock, client_io, _MP_STREAM_POLL_RD, _MP_STREAM_POLL_WR, 0) -assert_poll(client_sock, client_io, _MP_STREAM_POLL_WR, _MP_STREAM_POLL_WR, 0) - -# Mark the socket as writable, and do another test read: -client_io.block_writes = False -assert client_sock.read(128) is None - -# The client wrote the CLIENT_HELLO message -assert len(client_io.write_buffers) == 1 - -# At this point the TLS handshake wants to read, but we don't know that yet: -assert_poll(client_sock, client_io, _MP_STREAM_POLL_RD, _MP_STREAM_POLL_RD, 0) -assert_poll(client_sock, client_io, _MP_STREAM_POLL_WR, _MP_STREAM_POLL_WR, _MP_STREAM_POLL_WR) - -# Do a test write -client_sock.write(b"foo") - -# Now we know that we want to read: -assert_poll(client_sock, client_io, _MP_STREAM_POLL_RD, _MP_STREAM_POLL_RD, 0) -assert_poll(client_sock, client_io, _MP_STREAM_POLL_WR, _MP_STREAM_POLL_RD, 0) - -# Unblock reads and nudge the two sockets: -client_io.block_reads = False -while server_io.write_buffers or client_io.write_buffers: - if server_io.write_buffers: - assert client_sock.read(128) is None - if client_io.write_buffers: - assert server_sock.read(128) is None - -# At this point, the handshake is done, try writing data: -client_sock.write(b"foo") -assert server_sock.read(3) == b"foo" - -# Test reading partial data: -client_sock.write(b"foobar") -assert server_sock.read(3) == b"foo" -server_io.block_reads = True -assert_poll( - server_sock, server_io, _MP_STREAM_POLL_RD, None, _MP_STREAM_POLL_RD -) # Did not go to the socket, just consumed buffered data -assert server_sock.read(3) == b"bar" - - -# Polling on a closed socket errors out: -client_io, _ = _Pipe.new_pair() -client_sock = ssl.wrap_socket(client_io, do_handshake=False) -client_sock.close() -assert_poll( - client_sock, client_io, _MP_STREAM_POLL_RD, None, _MP_STREAM_POLL_NVAL -) # Did not go to the socket - - -# Errors propagates to poll: -client_io, server_io = _Pipe.new_pair() -client_sock = ssl.wrap_socket(client_io, do_handshake=False) - -# The server returns garbage: -server_io.write(b"fooba") # Needs to be exactly 5 bytes - -assert_poll(client_sock, client_io, _MP_STREAM_POLL_RD, _MP_STREAM_POLL_RD, _MP_STREAM_POLL_RD) -assert_raises(client_sock.read, 128) -assert_poll( - client_sock, client_io, _MP_STREAM_POLL_RD, None, _MP_STREAM_POLL_NVAL -) # Did not go to the socket diff --git a/tests/extmod/ssl_sslcontext.py b/tests/extmod/ssl_sslcontext.py deleted file mode 100644 index 23ff9c29646c0..0000000000000 --- a/tests/extmod/ssl_sslcontext.py +++ /dev/null @@ -1,25 +0,0 @@ -# Very basic test of ssl.SSLContext class. - -try: - import socket, ssl -except ImportError: - print("SKIP") - raise SystemExit - -# Test constructing with arguments. -ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) -ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) - -# Test printing object. -ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) -print("SSLContext" in str(ctx)) - -# Coverage test for destructor, and calling it twice. -if hasattr(ctx, "__del__"): - ctx.__del__() - ctx.__del__() - -# Test calling .wrap_socket() method, multiple times. -ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) -ctx.wrap_socket(socket.socket(), do_handshake_on_connect=False) -ctx.wrap_socket(socket.socket(), do_handshake_on_connect=False) diff --git a/tests/extmod/ssl_sslcontext_verify_mode.py b/tests/extmod/ssl_sslcontext_verify_mode.py deleted file mode 100644 index daccc2f4a956b..0000000000000 --- a/tests/extmod/ssl_sslcontext_verify_mode.py +++ /dev/null @@ -1,24 +0,0 @@ -# Test ssl.SSLContext.verify_mode attribute. -# It's not available in the axtls implementation, so has an independent test. - -try: - import ssl -except ImportError: - print("SKIP") - raise SystemExit - -if not hasattr(ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT), "verify_mode"): - print("SKIP") - raise SystemExit - -# Test default verify_mode for server (client default is different in MicroPython). -ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) -print(ctx.verify_mode == ssl.CERT_NONE) - -# Test setting and getting verify_mode. -ctx.verify_mode = ssl.CERT_NONE -print(ctx.verify_mode == ssl.CERT_NONE) -ctx.verify_mode = ssl.CERT_OPTIONAL -print(ctx.verify_mode == ssl.CERT_OPTIONAL) -ctx.verify_mode = ssl.CERT_REQUIRED -print(ctx.verify_mode == ssl.CERT_REQUIRED) diff --git a/tests/extmod/ticks_add.py b/tests/extmod/ticks_add.py deleted file mode 100644 index 4f465f3cfbac5..0000000000000 --- a/tests/extmod/ticks_add.py +++ /dev/null @@ -1,42 +0,0 @@ -try: - from time import ticks_diff, ticks_add -except ImportError: - print("SKIP") - raise SystemExit - -# Maximum value returned from ticks_add, ticks_ms, etc. -TICKS_MAX = ticks_add(0, -1) -# Maximum value returned from ticks_diff. -TICKS_INTERVAL_MAX = TICKS_MAX // 2 - -# Invariants: -# - ticks_diff(ticks_add(T, delta), T) == delta -# - ticks_diff(T, ticks_add(T, delta)) == -delta - -# Check actual values of ticks_add. -print(ticks_add(20, 12)) -print(ticks_add(20, -12)) - -# Check invariant. -print(ticks_diff(ticks_add(100, 123), 100)) -print(ticks_diff(ticks_add(100, -123), 100)) -print(ticks_diff(100, ticks_add(100, 123))) -print(ticks_diff(100, ticks_add(100, -123))) - -# Check limits. -for T in (0, 10, TICKS_MAX): - for delta in ( - -TICKS_INTERVAL_MAX - 1, - -TICKS_INTERVAL_MAX, - 0, - TICKS_INTERVAL_MAX, - TICKS_INTERVAL_MAX + 1, - ): - try: - print(ticks_diff(ticks_add(T, delta), T) == delta) - except OverflowError: - print("OverflowError") - try: - print(ticks_diff(T, ticks_add(T, delta)) == -delta) - except OverflowError: - print("OverflowError") diff --git a/tests/extmod/ticks_add.py.exp b/tests/extmod/ticks_add.py.exp deleted file mode 100644 index 60dc6f5afda6b..0000000000000 --- a/tests/extmod/ticks_add.py.exp +++ /dev/null @@ -1,36 +0,0 @@ -32 -8 -123 --123 --123 -123 -OverflowError -OverflowError -True -True -True -True -True -True -OverflowError -OverflowError -OverflowError -OverflowError -True -True -True -True -True -True -OverflowError -OverflowError -OverflowError -OverflowError -True -True -True -True -True -True -OverflowError -OverflowError diff --git a/tests/extmod/ticks_diff.py b/tests/extmod/ticks_diff.py deleted file mode 100644 index b2445f0d62454..0000000000000 --- a/tests/extmod/ticks_diff.py +++ /dev/null @@ -1,37 +0,0 @@ -try: - from time import ticks_diff, ticks_add -except ImportError: - print("SKIP") - raise SystemExit - -MAX = ticks_add(0, -1) -# Should be done like this to avoid small int overflow -MODULO_HALF = MAX // 2 + 1 - -# Invariants: -# if ticks_diff(a, b) = c, -# then ticks_diff(b, a) = -c - -assert ticks_diff(1, 0) == 1, ticks_diff(1, 0) -assert ticks_diff(0, 1) == -1 - -assert ticks_diff(0, MAX) == 1 -assert ticks_diff(MAX, 0) == -1 - -assert ticks_diff(0, MAX - 1) == 2 - -# Maximum "positive" distance -assert ticks_diff(MODULO_HALF, 1) == MODULO_HALF - 1, ticks_diff(MODULO_HALF, 1) -# Step further, and it becomes a negative distance -assert ticks_diff(MODULO_HALF, 0) == -MODULO_HALF - -# Offsetting that in either direction doesn't affect the result -off = 100 -# Cheating and skipping to use ticks_add() when we know there's no wraparound -# Real apps should use always it. -assert ticks_diff(MODULO_HALF + off, 1 + off) == MODULO_HALF - 1 -assert ticks_diff(MODULO_HALF + off, 0 + off) == -MODULO_HALF -assert ticks_diff(MODULO_HALF - off, ticks_add(1, -off)) == MODULO_HALF - 1 -assert ticks_diff(MODULO_HALF - off, ticks_add(0, -off)) == -MODULO_HALF - -print("OK") diff --git a/tests/extmod/time_ms_us.py b/tests/extmod/time_ms_us.py deleted file mode 100644 index e26c6e677a910..0000000000000 --- a/tests/extmod/time_ms_us.py +++ /dev/null @@ -1,23 +0,0 @@ -try: - import time - - time.sleep_ms, time.sleep_us, time.ticks_diff, time.ticks_ms, time.ticks_us, time.ticks_cpu -except (ImportError, AttributeError): - print("SKIP") - raise SystemExit - -time.sleep_ms(1) -time.sleep_us(1) - -t0 = time.ticks_ms() -t1 = time.ticks_ms() -print(0 <= time.ticks_diff(t1, t0) <= 1) - -t0 = time.ticks_us() -t1 = time.ticks_us() -print(0 <= time.ticks_diff(t1, t0) <= 500) - -# ticks_cpu may not be implemented, at least make sure it doesn't decrease -t0 = time.ticks_cpu() -t1 = time.ticks_cpu() -print(time.ticks_diff(t1, t0) >= 0) diff --git a/tests/extmod/time_ms_us.py.exp b/tests/extmod/time_ms_us.py.exp deleted file mode 100644 index b8ca7e7ef092a..0000000000000 --- a/tests/extmod/time_ms_us.py.exp +++ /dev/null @@ -1,3 +0,0 @@ -True -True -True diff --git a/tests/extmod/time_time_ns.py b/tests/extmod/time_time_ns.py deleted file mode 100644 index 3ef58e56a9459..0000000000000 --- a/tests/extmod/time_time_ns.py +++ /dev/null @@ -1,24 +0,0 @@ -# test time.time_ns() - -try: - import time - - time.sleep_us - time.time_ns -except (ImportError, AttributeError): - print("SKIP") - raise SystemExit - - -t0 = time.time_ns() -time.sleep_us(5000) -t1 = time.time_ns() - -# Check that time_ns increases. -print(t0 < t1) - -# Check that time_ns counts correctly, but be very lenient with the bounds (2ms to 50ms). -if 2000000 < t1 - t0 < 50000000: - print(True) -else: - print(t0, t1, t1 - t0) diff --git a/tests/extmod/time_time_ns.py.exp b/tests/extmod/time_time_ns.py.exp deleted file mode 100644 index dbde422651c9a..0000000000000 --- a/tests/extmod/time_time_ns.py.exp +++ /dev/null @@ -1,2 +0,0 @@ -True -True diff --git a/tests/extmod/uctypes_sizeof.py b/tests/extmod/uctypes_sizeof.py index 6e52232e39eba..d295cc85b6828 100644 --- a/tests/extmod/uctypes_sizeof.py +++ b/tests/extmod/uctypes_sizeof.py @@ -43,8 +43,47 @@ print(uctypes.sizeof(S.sub)) assert uctypes.sizeof(S.sub) == 1 -# invalid descriptor +# invalid descriptors try: print(uctypes.sizeof([])) except TypeError: print("TypeError") + +try: + print(uctypes.sizeof(())) +except TypeError: + print("TypeError") + +try: + print(uctypes.sizeof(("garbage",))) +except TypeError: + print("TypeError") + +try: + # PTR * 3 is intended to be an invalid agg_type (STRUCT, PTR, ARRAY are valid ones). + print(uctypes.sizeof((uctypes.PTR * 3,))) +except TypeError: + print("TypeError") + +try: + print(uctypes.sizeof((0, {}, "garbage"))) +except TypeError: + print("TypeError") + +try: + print(uctypes.sizeof((uctypes.PTR | 0,))) +except TypeError: + print("TypeError") + +try: + print(uctypes.sizeof((uctypes.ARRAY | 0,))) +except TypeError: + print("TypeError") + +try: + print(uctypes.sizeof((uctypes.ARRAY | 0, 1, {}, "garbage"))) +except TypeError: + print("TypeError") + +# empty descriptor +print(uctypes.sizeof({})) diff --git a/tests/extmod/uctypes_sizeof.py.exp b/tests/extmod/uctypes_sizeof.py.exp index b35b11aa0cea9..edcc05a441f79 100644 --- a/tests/extmod/uctypes_sizeof.py.exp +++ b/tests/extmod/uctypes_sizeof.py.exp @@ -5,3 +5,11 @@ TypeError 6 1 TypeError +TypeError +TypeError +TypeError +TypeError +TypeError +TypeError +TypeError +0 diff --git a/tests/extmod/uctypes_sizeof_od.py b/tests/extmod/uctypes_sizeof_od.py index 375f05f5e2ce0..8aff363631508 100644 --- a/tests/extmod/uctypes_sizeof_od.py +++ b/tests/extmod/uctypes_sizeof_od.py @@ -45,9 +45,3 @@ print(uctypes.sizeof(S.sub)) assert uctypes.sizeof(S.sub) == 1 - -# invalid descriptor -try: - print(uctypes.sizeof([])) -except TypeError: - print("TypeError") diff --git a/tests/extmod/uctypes_sizeof_od.py.exp b/tests/extmod/uctypes_sizeof_od.py.exp index b35b11aa0cea9..fb74def602b97 100644 --- a/tests/extmod/uctypes_sizeof_od.py.exp +++ b/tests/extmod/uctypes_sizeof_od.py.exp @@ -4,4 +4,3 @@ TypeError 6 1 -TypeError diff --git a/tests/extmod/vfs_blockdev_invalid.py b/tests/extmod/vfs_blockdev_invalid.py new file mode 100644 index 0000000000000..4d00f4b00273a --- /dev/null +++ b/tests/extmod/vfs_blockdev_invalid.py @@ -0,0 +1,89 @@ +# Tests where the block device returns invalid values + +try: + import vfs + + vfs.VfsFat + vfs.VfsLfs2 +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + + +class RAMBlockDevice: + ERASE_BLOCK_SIZE = 512 + + def __init__(self, blocks): + self.data = bytearray(blocks * self.ERASE_BLOCK_SIZE) + self.read_res = 0 + self.write_res = 0 + + def readblocks(self, block, buf, off=0): + # print("readblocks", block, len(buf), off) + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + buf[i] = self.data[addr + i] + return self.read_res + + def writeblocks(self, block, buf, off=None): + if off is None: + # erase, then write + off = 0 + addr = block * self.ERASE_BLOCK_SIZE + off + for i in range(len(buf)): + self.data[addr + i] = buf[i] + return self.write_res + + def ioctl(self, op, arg): + if op == 4: # block count + return len(self.data) // self.ERASE_BLOCK_SIZE + if op == 5: # block size + return self.ERASE_BLOCK_SIZE + if op == 6: # erase block + return 0 + + +try: + bdev = RAMBlockDevice(50) +except MemoryError: + print("SKIP") + raise SystemExit + + +def test(vfs_class): + print(vfs_class) + bdev.read_res = 0 # reset function results + bdev.write_res = 0 + + vfs_class.mkfs(bdev) + fs = vfs_class(bdev) + + with fs.open("test", "w") as f: + f.write("a" * 64) + + for res in (0, -5, 5, 33, "invalid"): + # -5 is a legitimate negative failure (EIO), positive integer + # is not + + # This variant will fail on open + bdev.read_res = res + try: + with fs.open("test", "r") as f: + print("opened") + except OSError as e: + print("OSError", e) + + # This variant should succeed on open, may fail on read + # unless the filesystem cached the contents already + bdev.read_res = 0 + try: + with fs.open("test", "r") as f: + bdev.read_res = res + print("read 1", f.read(1)) + print("read rest", f.read()) + except OSError as e: + print("OSError", e) + + +test(vfs.VfsLfs2) +test(vfs.VfsFat) diff --git a/tests/extmod/vfs_blockdev_invalid.py.exp b/tests/extmod/vfs_blockdev_invalid.py.exp new file mode 100644 index 0000000000000..13695e0d88916 --- /dev/null +++ b/tests/extmod/vfs_blockdev_invalid.py.exp @@ -0,0 +1,28 @@ + +opened +read 1 a +read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +OSError [Errno 5] EIO +read 1 a +read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +OSError [Errno 22] EINVAL +read 1 a +read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +OSError [Errno 22] EINVAL +read 1 a +read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +OSError [Errno 22] EINVAL +read 1 a +read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +opened +read 1 a +read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +OSError [Errno 5] EIO +OSError [Errno 5] EIO +OSError [Errno 5] EIO +OSError [Errno 5] EIO +OSError [Errno 5] EIO +OSError [Errno 5] EIO +OSError [Errno 5] EIO +OSError [Errno 5] EIO diff --git a/tests/extmod/vfs_lfs_mtime.py b/tests/extmod/vfs_lfs_mtime.py index 3d163dc2687f0..d4404de4dcb88 100644 --- a/tests/extmod/vfs_lfs_mtime.py +++ b/tests/extmod/vfs_lfs_mtime.py @@ -3,7 +3,7 @@ try: import time, vfs - time.time + time.time_ns time.sleep vfs.VfsLfs2 except (ImportError, AttributeError): @@ -47,7 +47,8 @@ def test(bdev, vfs_class): fs = vfs_class(bdev, mtime=True) # Create an empty file, should have a timestamp. - current_time = int(time.time()) + # Use time_ns() for current time because that's what's used for VfsLfs2 time. + current_time = time.time_ns() // 1_000_000_000 fs.open("test1", "wt").close() # Wait 1 second so mtime will increase by at least 1. @@ -61,7 +62,7 @@ def test(bdev, vfs_class): stat2 = fs.stat("test2") print(stat1[8] != 0, stat2[8] != 0) - # Check that test1 has mtime which matches time.time() at point of creation. + # Check that test1 has mtime which matches time.time_ns() at point of creation. print(current_time <= stat1[8] <= current_time + 1) # Check that test1 is older than test2. diff --git a/tests/feature_check/target_info.py b/tests/feature_check/target_info.py new file mode 100644 index 0000000000000..df89496708aa9 --- /dev/null +++ b/tests/feature_check/target_info.py @@ -0,0 +1,22 @@ +# Retrieve the native architecture of the target. +# See https://docs.micropython.org/en/latest/reference/mpyfiles.html#versioning-and-compatibility-of-mpy-files +# for more details. + +import sys + +sys_mpy = getattr(sys.implementation, "_mpy", 0) +arch = [ + None, + "x86", + "x64", + "armv6", + "armv6m", + "armv7m", + "armv7em", + "armv7emsp", + "armv7emdp", + "xtensa", + "xtensawin", + "rv32imc", +][sys_mpy >> 10] +print(arch) diff --git a/tests/extmod/ssl_poll.py.exp b/tests/feature_check/target_info.py.exp similarity index 100% rename from tests/extmod/ssl_poll.py.exp rename to tests/feature_check/target_info.py.exp diff --git a/tests/float/float_format_ints_power10.py b/tests/float/float_format_ints_power10.py index 98900c135b2e4..7ea200f18ef06 100644 --- a/tests/float/float_format_ints_power10.py +++ b/tests/float/float_format_ints_power10.py @@ -3,6 +3,6 @@ # Check that powers of 10 (that fit in float32) format correctly. for i in range(31): - # It works to 12 digits on all platforms *except* qemu-arm, where + # It works to 12 digits on all platforms *except* qemu, where # 10^11 comes out as 10000000820 or something. print(i, "{:.7g}".format(float("1e" + str(i)))) diff --git a/tests/micropython/heapalloc_exc_compressed.py b/tests/micropython/heapalloc_exc_compressed.py index cddc0f7b4095d..aa071d641c21c 100644 --- a/tests/micropython/heapalloc_exc_compressed.py +++ b/tests/micropython/heapalloc_exc_compressed.py @@ -4,7 +4,7 @@ # mp_obj_new_exception_msg_varg (exception requires decompression at raise-time to format) # mp_obj_new_exception_msg (decompression can be deferred) -# NameError uses mp_obj_new_exception_msg_varg for NameError("name '%q' is not defined") +# NameError uses mp_obj_new_exception_msg_varg for NameError("name '%q' isn't defined") # `raise 0` uses mp_obj_new_exception_msg for TypeError("exceptions must derive from BaseException") # Tests that deferred decompression works both via print(e) and accessing the message directly via e.args. diff --git a/tests/micropython/heapalloc_exc_compressed.py.exp b/tests/micropython/heapalloc_exc_compressed.py.exp index c2690353b07f2..c3e6e5dd9f749 100644 --- a/tests/micropython/heapalloc_exc_compressed.py.exp +++ b/tests/micropython/heapalloc_exc_compressed.py.exp @@ -1,6 +1,6 @@ -NameError name 'name' is not defined +NameError name 'name' isn't defined TypeError exceptions must derive from BaseException -name 'name' is not defined +name 'name' isn't defined exceptions must derive from BaseException NameError TypeError diff --git a/tests/micropython/heapalloc_exc_compressed_emg_exc.py.exp b/tests/micropython/heapalloc_exc_compressed_emg_exc.py.exp index c3974250d4e26..1fc81093392a2 100644 --- a/tests/micropython/heapalloc_exc_compressed_emg_exc.py.exp +++ b/tests/micropython/heapalloc_exc_compressed_emg_exc.py.exp @@ -1,4 +1,4 @@ -NameError name 'name' is not defined +NameError name 'name' isn't defined TypeError exceptions must derive from BaseException -name 'name' is not defined +name 'name' isn't defined exceptions must derive from BaseException diff --git a/tests/micropython/import_mpy_native_gc.py b/tests/micropython/import_mpy_native_gc.py index 2f21e417d30d6..977efb2672cc5 100644 --- a/tests/micropython/import_mpy_native_gc.py +++ b/tests/micropython/import_mpy_native_gc.py @@ -1,4 +1,4 @@ -# Test that native code loaded from a .mpy file is retained after a GC. +# Test that native text/BSS/rodata loaded from a .mpy file is retained after a GC. try: import gc, sys, io, vfs @@ -44,12 +44,14 @@ def open(self, path, mode): return UserFile(self.files[path]) -# Pre-compiled examples/natmod/features0 example for various architectures, keyed +# Pre-compiled import_mpy_native_gc_module example for various architectures, keyed # by the required value of sys.implementation._mpy (without sub-version). -# cd examples/natmod/features0 -# make clean -# make ARCH=x64 # or ARCH=armv6m -# cat features0.mpy | python -c 'import sys; print(sys.stdin.buffer.read())' +# To rebuild: +# $ cd import_mpy_native_gc_module +# $ make clean +# $ make ARCH=x64 # or ARCH=armv6m or ARCH=xtensawin +# Then copy the bytes object printed on the last line. + # CIRCUITPY-CHANGE: 'C' instead of 'M' mpy marker. features0_file_contents = { # -march=x64 @@ -77,11 +79,24 @@ def open(self, path, mode): # Import the native function. gc.collect() -from features0 import factorial +from features0 import get, add1 + +# Test that the native functions work to begin with. +print(get()) +print(add1(12)) # Free the module that contained the function. del sys.modules["features0"] + +# Sweep the stack to remove any stray pointers that we are aiming to reclaim. +def recurse(n): + if n: + recurse(n - 1) + + +recurse(10) + # Run a GC cycle which should reclaim the module but not the function. gc.collect() @@ -89,8 +104,9 @@ def open(self, path, mode): for i in range(1000): [] -# Run the native function, it should not have been freed or overwritten. -print(factorial(10)) +# Run the native function, its text/BSS/rodata should not have been freed or overwritten. +print(get()) +print(add1(12)) # Unmount and undo path addition. vfs.umount("/userfs") diff --git a/tests/micropython/import_mpy_native_gc.py.exp b/tests/micropython/import_mpy_native_gc.py.exp index 3fbd4a8698fa3..4250a13c72693 100644 --- a/tests/micropython/import_mpy_native_gc.py.exp +++ b/tests/micropython/import_mpy_native_gc.py.exp @@ -1 +1,4 @@ -3628800 +123456 +13 +123456 +13 diff --git a/tests/micropython/native_with.py.exp b/tests/micropython/native_with.py.exp index 6eef7822fbaf8..7e28663f6fcf0 100644 --- a/tests/micropython/native_with.py.exp +++ b/tests/micropython/native_with.py.exp @@ -5,5 +5,5 @@ __exit__ None None None __init__ __enter__ 1 -__exit__ name 'fail' is not defined None +__exit__ name 'fail' isn't defined None NameError diff --git a/tests/micropython/opt_level_lineno.py b/tests/micropython/opt_level_lineno.py new file mode 100644 index 0000000000000..40650b6819221 --- /dev/null +++ b/tests/micropython/opt_level_lineno.py @@ -0,0 +1,7 @@ +import micropython as micropython + +# check that level 3 doesn't store line numbers +# the expected output is that any line is printed as "line 1" +micropython.opt_level(3) +# CIRCUITPY-CHANGE: use traceback.print_exception() instead of sys.print_exception() +exec("try:\n xyz\nexcept NameError as er:\n import traceback\n traceback.print_exception(er)") diff --git a/tests/micropython/opt_level_lineno.py.exp b/tests/micropython/opt_level_lineno.py.exp new file mode 100644 index 0000000000000..469b90ba7938a --- /dev/null +++ b/tests/micropython/opt_level_lineno.py.exp @@ -0,0 +1,3 @@ +Traceback (most recent call last): + File "", line 1, in +NameError: name 'xyz' isn't defined diff --git a/tests/micropython/viper_with.py.exp b/tests/micropython/viper_with.py.exp index 6eef7822fbaf8..7e28663f6fcf0 100644 --- a/tests/micropython/viper_with.py.exp +++ b/tests/micropython/viper_with.py.exp @@ -5,5 +5,5 @@ __exit__ None None None __init__ __enter__ 1 -__exit__ name 'fail' is not defined None +__exit__ name 'fail' isn't defined None NameError diff --git a/tests/misc/cexample_class.py b/tests/misc/cexample_class.py index 6b8718ad8cc5f..06d741922d289 100644 --- a/tests/misc/cexample_class.py +++ b/tests/misc/cexample_class.py @@ -22,3 +22,20 @@ print(timer) print(0 <= t_start <= TOLERANCE_MS) print(SLEEP_MS - TOLERANCE_MS <= t_end <= SLEEP_MS + TOLERANCE_MS) + +advanced_timer = cexample.AdvancedTimer() + +time.sleep_ms(100) + +print(repr(advanced_timer)) +print(str(advanced_timer)) + +print(advanced_timer.seconds) +advanced_timer.seconds = 123 +print(advanced_timer.seconds) +print(advanced_timer.time() < 123000 + TOLERANCE_MS) + +try: + advanced_timer.seconds = "bad input" +except TypeError: + print("TypeError") diff --git a/tests/misc/cexample_class.py.exp b/tests/misc/cexample_class.py.exp index b9a06602a316a..a86d4d14f78df 100644 --- a/tests/misc/cexample_class.py.exp +++ b/tests/misc/cexample_class.py.exp @@ -1,3 +1,9 @@ True True +AdvancedTimer() +AdvancedTimer() # created 0 seconds ago +0 +123 +True +TypeError diff --git a/tests/misc/cexample_module.py b/tests/misc/cexample_module.py index c1da2ecf7ab24..979c1fa24b376 100644 --- a/tests/misc/cexample_module.py +++ b/tests/misc/cexample_module.py @@ -12,5 +12,6 @@ d = dir(cexample) d.index("add_ints") d.index("Timer") +d.index("AdvancedTimer") print(cexample.add_ints(1, 3)) diff --git a/tests/misc/cexample_subclass.py b/tests/misc/cexample_subclass.py new file mode 100644 index 0000000000000..9f52a2c737add --- /dev/null +++ b/tests/misc/cexample_subclass.py @@ -0,0 +1,37 @@ +# test subclassing custom native class + +try: + from cexample import AdvancedTimer +except ImportError: + print("SKIP") + raise SystemExit + + +class SubTimer(AdvancedTimer): + def __init__(self): + # At this point, self does not yet represent a AdvancedTimer instance. + print(self) + + # So lookups via type.attr handler will fail. + try: + self.seconds + except AttributeError: + print("AttributeError") + + # Also applies to builtin methods. + try: + self.time() + except AttributeError: + print("AttributeError") + + # Initialize base class. + super().__init__(self) + + # Now you can access methods and attributes normally. + self.time() + print(self.seconds) + self.seconds = 123 + print(self.seconds) + + +watch = SubTimer() diff --git a/tests/misc/cexample_subclass.py.exp b/tests/misc/cexample_subclass.py.exp new file mode 100644 index 0000000000000..a035649e475db --- /dev/null +++ b/tests/misc/cexample_subclass.py.exp @@ -0,0 +1,5 @@ + +AttributeError +AttributeError +0 +123 diff --git a/tests/run-tests-exp.py b/tests/run-tests-exp.py deleted file mode 100644 index bbb057f4cede9..0000000000000 --- a/tests/run-tests-exp.py +++ /dev/null @@ -1,94 +0,0 @@ -# -# This is minimal MicroPython variant of run-tests.py script, which uses -# .exp files as generated by run-tests.py --write-exp. It is useful to run -# testsuite on systems which have neither CPython3 nor unix shell. -# This script is intended to be run by the same interpreter executable -# which is to be tested, so should use minimal language functionality. -# -import sys -import os - - -tests = ["basics", "micropython", "float", "import", "io", " misc", "unicode", "extmod", "unix"] - -if sys.platform == "win32": - MICROPYTHON = "micropython.exe" -else: - MICROPYTHON = "micropython" - - -def should_skip(test): - if test.startswith("native"): - return True - if test.startswith("viper"): - return True - - -test_count = 0 -passed_count = 0 -skip_count = 0 - -for suite in tests: - # print("Running in: %s" % suite) - if sys.platform == "win32": - # dir /b prints only contained filenames, one on a line - # http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/dir.mspx - r = os.system("dir /b %s/*.py >tests.lst" % suite) - else: - r = os.system("ls %s/*.py | xargs -n1 basename >tests.lst" % suite) - assert r == 0 - - with open("tests.lst") as f: - testcases = f.readlines() - testcases = [l[:-1] for l in testcases] - assert testcases, "No tests found in dir '%s', which is implausible" % suite - # print(testcases) - for t in testcases: - if t == "native_check.py": - continue - - qtest = "%s/%s" % (suite, t) - - if should_skip(t): - print("skip " + qtest) - skip_count += 1 - continue - - exp = None - try: - f = open(qtest + ".exp") - exp = f.read() - f.close() - except OSError: - pass - - if exp is not None: - # print("run " + qtest) - r = os.system(MICROPYTHON + " %s >.tst.out" % qtest) - if r == 0: - f = open(".tst.out") - out = f.read() - f.close() - else: - out = "CRASH" - - if out == "SKIP\n": - print("skip " + qtest) - skip_count += 1 - else: - if out == exp: - print("pass " + qtest) - passed_count += 1 - else: - print("FAIL " + qtest) - - test_count += 1 - else: - skip_count += 1 - -print("%s tests performed" % test_count) -print("%s tests passed" % passed_count) -if test_count != passed_count: - print("%s tests failed" % (test_count - passed_count)) -if skip_count: - print("%s tests skipped" % skip_count) diff --git a/tests/run-tests-exp.sh b/tests/run-tests-exp.sh deleted file mode 100755 index 177090cd8db93..0000000000000 --- a/tests/run-tests-exp.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/sh -# -# This is plain shell variant of run-tests.py script, which uses .exp files -# as generated by run-tests.py --write-exp. It is useful to run testsuite -# on embedded systems which don't have CPython3. -# - -RM="rm -f" -MP_PY=micropython - -numtests=0 -numtestcases=0 -numpassed=0 -numskipped=0 -numfailed=0 -nameskipped= -namefailed= - -if [ $# -eq 0 ] -then - tests="basics/*.py micropython/*.py float/*.py import/*.py io/*.py misc/*.py unicode/*.py extmod/*.py unix/*.py" -else - tests="$@" -fi - -for infile in $tests -do - basename=`basename $infile .py` - outfile=${basename}.py.out - expfile=$infile.exp - - $MP_PY $infile > $outfile - numtestcases=$(expr $numtestcases + $(cat $expfile | wc -l)) - - if grep -q "SKIP\|SyntaxError: invalid micropython decorator" $outfile - then - # we don't count tests that explicitly ask to be skipped - # we don't count tests that fail due to unsupported decorator - echo "skip $infile" - $RM $outfile - numskipped=$(expr $numskipped + 1) - nameskipped="$nameskipped $basename" - else - diff --brief $expfile $outfile > /dev/null - - if [ $? -eq 0 ] - then - echo "pass $infile" - $RM $outfile - numpassed=$(expr $numpassed + 1) - else - echo "FAIL $infile" - numfailed=$(expr $numfailed + 1) - namefailed="$namefailed $basename" - fi - fi - - numtests=$(expr $numtests + 1) -done - -echo "$numtests tests performed ($numtestcases individual testcases)" -echo "$numpassed tests passed" -if [ $numskipped != 0 ] -then - echo "$numskipped tests skipped -$nameskipped" -fi -if [ $numfailed != 0 ] -then - echo "$numfailed tests failed -$namefailed" - exit 1 -else - exit 0 -fi diff --git a/tests/run-tests.py b/tests/run-tests.py index 3b7bca64cce9a..b032bbc79f39c 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -3,6 +3,7 @@ import os import subprocess import sys +import sysconfig import platform import argparse import inspect @@ -466,9 +467,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): upy_float_precision = 32 - # If we're asked to --list-tests, we can't assume that there's a - # connection to target, so we can't run feature checks usefully. - if not (args.list_tests or args.write_exp): + if True: # Even if we run completely different tests in a different directory, # we need to access feature_checks from the same directory as the # run-tests.py script itself so use base_path. @@ -564,6 +563,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): # These tests don't test slice explicitly but rather use it to perform the test misc_slice_tests = ( "builtin_range", + "bytearray1", "class_super", "containment", "errno1", @@ -574,6 +574,7 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): "memoryview_gc", "object1", "python34", + "string_format_modulo", "struct_endian", ) @@ -581,14 +582,10 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): if os.getenv("GITHUB_ACTIONS") == "true": skip_tests.add("thread/stress_schedule.py") # has reliability issues - if os.getenv("RUNNER_OS") == "Windows": + if os.getenv("RUNNER_OS") == "Windows" and os.getenv("CI_BUILD_CONFIGURATION") == "Debug": # fails with stack overflow on Debug builds skip_tests.add("misc/sys_settrace_features.py") - if os.getenv("MSYSTEM") is not None: - # fails due to wrong path separator - skip_tests.add("import/import_file.py") - if upy_float_precision == 0: skip_tests.add("extmod/uctypes_le_float.py") skip_tests.add("extmod/uctypes_native_float.py") @@ -640,6 +637,9 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): skip_tests.add("thread/thread_lock2.py") skip_tests.add("thread/thread_lock3.py") skip_tests.add("thread/thread_shared2.py") + elif args.target == "zephyr": + skip_tests.add("thread/stress_heap.py") + skip_tests.add("thread/thread_lock3.py") # Some tests shouldn't be run on pyboard if args.target != "unix": @@ -658,6 +658,8 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): skip_tests.add("extmod/random_basic.py") # requires random skip_tests.add("extmod/random_extra.py") # requires random elif args.target == "esp8266": + skip_tests.add("micropython/viper_args.py") # too large + skip_tests.add("micropython/viper_binop_arith.py") # too large skip_tests.add("misc/rge_sm.py") # too large elif args.target == "minimal": skip_tests.add("basics/class_inplace_op.py") # all special methods not supported @@ -678,8 +680,12 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): skip_tests.add( "extmod/time_time_ns.py" ) # RA fsp rtc function doesn't support nano sec info - elif args.target == "qemu-arm": - skip_tests.add("misc/print_exception.py") # requires sys stdfiles + elif args.target == "qemu": + skip_tests.add("inlineasm/asmfpaddsub.py") # requires Cortex-M4 + skip_tests.add("inlineasm/asmfpcmp.py") + skip_tests.add("inlineasm/asmfpldrstr.py") + skip_tests.add("inlineasm/asmfpmuldiv.py") + skip_tests.add("inlineasm/asmfpsqrt.py") elif args.target == "webassembly": skip_tests.add("basics/string_format_modulo.py") # can't print nulls to stdout skip_tests.add("basics/string_strip.py") # can't print nulls to stdout @@ -711,7 +717,9 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): # Some tests use unsupported features on Windows if os.name == "nt": - skip_tests.add("import/import_file.py") # works but CPython prints forward slashes + if not sysconfig.get_platform().startswith("mingw"): + # Works but CPython uses '\' path separator + skip_tests.add("import/import_file.py") # Some tests are known to fail with native emitter # Remove them from the below when they work @@ -806,11 +814,6 @@ def run_one_test(test_file): skip_it |= skip_io_module and is_io_module skip_it |= skip_fstring and is_fstring - if args.list_tests: - if not skip_it: - print(test_file) - return - if skip_it: print("skip ", test_file) skipped_tests.append(test_name) @@ -842,22 +845,22 @@ def run_one_test(test_file): # CIRCUITPY-CHANGE: pass environment env=e, ) - if args.write_exp: - with open(test_file_expected, "wb") as f: - f.write(output_expected) except subprocess.CalledProcessError: output_expected = b"CPYTHON3 CRASH" # canonical form for all host platforms is to use \n for end-of-line output_expected = output_expected.replace(b"\r\n", b"\n") - if args.write_exp: - return - # run MicroPython output_mupy = run_micropython(pyb, args, test_file, test_file_abspath) if output_mupy == b"SKIP\n": + if pyb is not None and hasattr(pyb, "read_until"): + # Running on a target over a serial connection, and the target requested + # to skip the test. It does this via a SystemExit which triggers a soft + # reset. Wait for the soft reset to finish, so we don't interrupt the + # start-up code (eg boot.py) when preparing to run the next test. + pyb.read_until(1, b"raw REPL; CTRL-B to exit\r\n") print("skip ", test_file) skipped_tests.append(test_name) return @@ -882,7 +885,7 @@ def run_one_test(test_file): test_count.increment() - if pyb or args.list_tests: + if pyb: num_threads = 1 if num_threads > 1: @@ -892,10 +895,6 @@ def run_one_test(test_file): for test in tests: run_one_test(test) - # Leave RESULTS_FILE untouched here for future runs. - if args.list_tests: - return True - print( "{} tests performed ({} individual testcases)".format( test_count.value, testcase_count.value @@ -1004,14 +1003,6 @@ def main(): dest="filters", help="include test by regex on path/name.py", ) - cmd_parser.add_argument( - "--write-exp", - action="store_true", - help="use CPython to generate .exp files to run tests w/o CPython", - ) - cmd_parser.add_argument( - "--list-tests", action="store_true", help="list tests instead of running them" - ) cmd_parser.add_argument( "--emit", default="bytecode", help="MicroPython emitter to use (bytecode or native)" ) @@ -1069,7 +1060,6 @@ def main(): LOCAL_TARGETS = ( "unix", - "qemu-arm", "webassembly", ) EXTERNAL_TARGETS = ( @@ -1079,18 +1069,13 @@ def main(): "esp32", "minimal", "nrf", + "qemu", "renesas-ra", "rp2", + "zephyr", ) - if args.list_tests: - pyb = None - elif args.target in LOCAL_TARGETS: + if args.target in LOCAL_TARGETS: pyb = None - if not args.mpy_cross_flags: - if args.target == "unix": - args.mpy_cross_flags = "-march=host" - elif args.target == "qemu-arm": - args.mpy_cross_flags = "-march=armv7m" if args.target == "webassembly": pyb = PyboardNodeRunner() elif args.target in EXTERNAL_TARGETS: @@ -1098,24 +1083,19 @@ def main(): sys.path.append(base_path("../tools")) import pyboard - if not args.mpy_cross_flags: - if args.target == "esp8266": - args.mpy_cross_flags = "-march=xtensa" - elif args.target == "esp32": - args.mpy_cross_flags = "-march=xtensawin" - elif args.target == "rp2": - args.mpy_cross_flags = "-march=armv6m" - elif args.target == "pyboard": - args.mpy_cross_flags = "-march=armv7emsp" - else: - args.mpy_cross_flags = "-march=armv7m" - pyb = pyboard.Pyboard(args.device, args.baudrate, args.user, args.password) pyboard.Pyboard.run_script_on_remote_target = run_script_on_remote_target pyb.enter_raw_repl() else: raise ValueError("target must be one of %s" % ", ".join(LOCAL_TARGETS + EXTERNAL_TARGETS)) + # Automatically detect the native architecture for mpy-cross if not given. + if not args.mpy_cross_flags: + output = run_feature_check(pyb, args, "target_info.py") + arch = str(output, "ascii").strip() + if arch != "None": + args.mpy_cross_flags = "-march=" + arch + if args.run_failures and (any(args.files) or args.test_dirs is not None): raise ValueError( "--run-failures cannot be used together with files or --test-dirs arguments" @@ -1147,8 +1127,12 @@ def main(): elif args.target in ("renesas-ra"): test_dirs += ("float", "inlineasm", "ports/renesas-ra") elif args.target == "rp2": - test_dirs += ("float", "stress", "inlineasm", "thread", "ports/rp2") - elif args.target in ("esp8266", "esp32", "minimal", "nrf"): + test_dirs += ("float", "stress", "thread", "ports/rp2") + if "arm" in args.mpy_cross_flags: + test_dirs += ("inlineasm",) + elif args.target == "esp32": + test_dirs += ("float", "stress", "thread") + elif args.target in ("esp8266", "minimal", "nrf"): test_dirs += ("float",) elif args.target == "wipy": # run WiPy tests @@ -1164,15 +1148,11 @@ def main(): "cmdline", "ports/unix", ) - elif args.target == "qemu-arm": - if not args.write_exp: - raise ValueError("--target=qemu-arm must be used with --write-exp") - # Generate expected output files for qemu run. - # This list should match the test_dirs tuple in tinytest-codegen.py. + elif args.target == "qemu": test_dirs += ( "float", "inlineasm", - "ports/qemu-arm", + "ports/qemu", ) else: # run tests from these directories diff --git a/tests/stress/bytecode_limit.py b/tests/stress/bytecode_limit.py index ad090637f6a68..948d7668da551 100644 --- a/tests/stress/bytecode_limit.py +++ b/tests/stress/bytecode_limit.py @@ -3,14 +3,18 @@ body = " with f()()() as a:\n try:\n f()()()\n except Exception:\n pass\n" # Test overflow of jump offset. +# Print results at the end in case an intermediate value of n fails with MemoryError. +results = [] for n in (433, 432, 431, 430): try: exec("cond = 0\nif cond:\n" + body * n + "else:\n print('cond false')\n") + results.append((n, "ok")) except MemoryError: print("SKIP") raise SystemExit except RuntimeError: - print("RuntimeError") + results.append((n, "RuntimeError")) +print(results) # Test changing size of code info (source line/bytecode mapping) due to changing # bytecode size in the final passes. This test is very specific to how the diff --git a/tests/stress/bytecode_limit.py.exp b/tests/stress/bytecode_limit.py.exp index 1d892250b01e6..cda52b1b97348 100644 --- a/tests/stress/bytecode_limit.py.exp +++ b/tests/stress/bytecode_limit.py.exp @@ -1,5 +1,4 @@ -RuntimeError -RuntimeError cond false cond false +[(433, 'RuntimeError'), (432, 'RuntimeError'), (431, 'ok'), (430, 'ok')] [123] diff --git a/tests/thread/disable_irq.py b/tests/thread/disable_irq.py new file mode 100644 index 0000000000000..3f1ac74f30877 --- /dev/null +++ b/tests/thread/disable_irq.py @@ -0,0 +1,51 @@ +# Ensure that disabling IRQs creates mutual exclusion between threads +# (also tests nesting of disable_irq across threads) +import machine +import time +import _thread + +if not hasattr(machine, "disable_irq"): + print("SKIP") + raise SystemExit + +count = 0 +thread_done = False + + +def inc_count(): + global count + a = machine.disable_irq() + try: + count += 1 + i = 0 + while i < 20: + b = machine.disable_irq() + try: + count += 1 + count -= 1 + i += 1 + finally: + machine.enable_irq(b) + finally: + machine.enable_irq(a) + + +def inc_count_multiple(times): + for _ in range(times): + inc_count() + + +def thread_entry(inc_times): + global thread_done + inc_count_multiple(inc_times) + thread_done = True + + +_thread.start_new_thread(thread_entry, (1000,)) +inc_count_multiple(1000) + +time.sleep(1) + +print("count", count, thread_done) +if count == 2000: + print("PASS") diff --git a/tests/thread/disable_irq.py.exp b/tests/thread/disable_irq.py.exp new file mode 100644 index 0000000000000..2174b91d0d044 --- /dev/null +++ b/tests/thread/disable_irq.py.exp @@ -0,0 +1,2 @@ +count 2000 True +PASS diff --git a/tests/thread/stress_aes.py b/tests/thread/stress_aes.py index b25da855aeffc..d8d0acd568a7a 100644 --- a/tests/thread/stress_aes.py +++ b/tests/thread/stress_aes.py @@ -273,7 +273,7 @@ def thread_entry(n_loop): elif sys.platform == "rp2": n_thread = 1 n_loop = 2 - elif sys.platform in ("esp32", "pyboard"): + elif sys.platform in ("esp32", "pyboard", "zephyr"): n_thread = 2 n_loop = 2 else: @@ -282,6 +282,6 @@ def thread_entry(n_loop): for i in range(n_thread): _thread.start_new_thread(thread_entry, (n_loop,)) thread_entry(n_loop) - while count.value < n_thread: + while count.value < n_thread + 1: time.sleep(1) print("done") diff --git a/tests/thread/stress_schedule.py b/tests/thread/stress_schedule.py index a5d7dc824edea..97876f0f77ca8 100644 --- a/tests/thread/stress_schedule.py +++ b/tests/thread/stress_schedule.py @@ -52,6 +52,8 @@ def thread(): thread_run = False time.sleep_ms(20) +gc.enable() + if n < _NUM_TASKS: # Not all the tasks were scheduled, likely the scheduler stopped working. print(n) diff --git a/tests/thread/thread_coop.py b/tests/thread/thread_coop.py new file mode 100644 index 0000000000000..aefc4af074db5 --- /dev/null +++ b/tests/thread/thread_coop.py @@ -0,0 +1,53 @@ +# Threads should be semi-cooperative, to the point where one busy +# thread can't starve out another. +# +# (Note on ports without the GIL this one should always be true, on ports with GIL it's +# a test of the GIL behaviour.) + +import _thread +import sys +from time import ticks_ms, ticks_diff, sleep_ms + + +done = False + +ITERATIONS = 5 +SLEEP_MS = 250 +MAX_DELTA = 30 + +if sys.platform in ("win32", "linux", "darwin"): + # Conventional operating systems get looser timing restrictions + SLEEP_MS = 300 + MAX_DELTA = 100 + + +def busy_thread(): + while not done: + pass + + +def test_sleeps(): + global done + ok = True + for _ in range(ITERATIONS): + t0 = ticks_ms() + sleep_ms(SLEEP_MS) + t1 = ticks_ms() + d = ticks_diff(t1, t0) + if d < SLEEP_MS - MAX_DELTA or d > SLEEP_MS + MAX_DELTA: + print("Slept too long ", d) + ok = False + print("OK" if ok else "Not OK") + done = True + + +# make the thread the busy one, and check sleep time on main task +_thread.start_new_thread(busy_thread, ()) +test_sleeps() + +sleep_ms(100) +done = False + +# now swap them +_thread.start_new_thread(test_sleeps, ()) +busy_thread() diff --git a/tests/extmod/ticks_diff.py.exp b/tests/thread/thread_coop.py.exp similarity index 50% rename from tests/extmod/ticks_diff.py.exp rename to tests/thread/thread_coop.py.exp index d86bac9de59ab..2c94e48371001 100644 --- a/tests/extmod/ticks_diff.py.exp +++ b/tests/thread/thread_coop.py.exp @@ -1 +1,2 @@ OK +OK diff --git a/tests/thread/thread_stdin.py b/tests/thread/thread_stdin.py new file mode 100644 index 0000000000000..a469933f19b55 --- /dev/null +++ b/tests/thread/thread_stdin.py @@ -0,0 +1,44 @@ +# Test that having multiple threads block on stdin doesn't cause any issues. +# +# The test doesn't expect any input on stdin. +# +# This is a regression test for https://github.com/micropython/micropython/issues/15230 +# on rp2, but doubles as a general property to test across all ports. +import sys +import _thread + +try: + import select +except ImportError: + print("SKIP") + raise SystemExit + + +class StdinWaiter: + def __init__(self): + self._done = False + + def wait_stdin(self, timeout_ms): + poller = select.poll() + poller.register(sys.stdin, select.POLLIN) + poller.poll(timeout_ms) + # Ignoring the poll result as we don't expect any input + self._done = True + + def is_done(self): + return self._done + + +thread_waiter = StdinWaiter() +_thread.start_new_thread(thread_waiter.wait_stdin, (1000,)) +StdinWaiter().wait_stdin(1000) + +# Spinning here is mostly not necessary but there is some inconsistency waking +# the two threads, especially on CPython CI runners where the thread may not +# have run yet. The actual delay is <20ms but spinning here instead of +# sleep(0.1) means the test can run on MP builds without float support. +while not thread_waiter.is_done(): + pass + +# The background thread should have completed its wait by now. +print(thread_waiter.is_done()) diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index c75676fad9aff..743823dcf4a55 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -90,9 +90,11 @@ data 1 12345 6 +-1 # runtime utils TypeError: unsupported type for __abs__: 'str' TypeError: unsupported types for __divmod__: 'str', 'str' +0 1 2 OverflowError: overflow converting long int to machine word @@ -144,6 +146,11 @@ cc99 22ff -1 -1 +0 +0 +abc123 +-1 +-2 # pairheap create: 0 0 0 0 pop all: 0 1 2 3 @@ -164,6 +171,8 @@ pop all: 1 2 4 5 1 1 0 0 1 1 +# stackctrl +1 1 # end coverage.c 0123456789 b'0123456789' 7300 diff --git a/tests/unix/ffi_int_base.py b/tests/unix/ffi_int_base.py new file mode 100644 index 0000000000000..906bc3c1e1467 --- /dev/null +++ b/tests/unix/ffi_int_base.py @@ -0,0 +1,49 @@ +# common tests for ffi_int_types/long32/long64 +# requires ffi_lib.c to be compiled as: $(CC) -shared -o ffi_lib.so ffi_lib.c + +import os, sys + +try: + import ffi +except ImportError: + print("SKIP") + raise SystemExit + +ffi_lib_filename = sys.argv[0].rsplit("/", 1)[0] + "/ffi_lib.so" +try: + os.stat(ffi_lib_filename) +except OSError: + print("SKIP") + raise SystemExit + +ffi_lib = ffi.open(ffi_lib_filename) + + +def test(funcs): + for type, name in funcs: + func = ffi_lib.func(type, name, type) + for val in ( + 0, + 0x7F, + 0x80, + 0xFF, + 0x100, + 0x7FFF, + 0x8000, + 0xFFFF, + 0x10000, + 0x7FFFFFFF, + 0x80000000, + 0xFFFFFFFF, + 0x100000000, + 0x7FFF_FFFF_FFFF_FFFF, + 0x8000_0000_0000_0000, + 0xFFFF_FFFF_FFFF_FFFF, + 0x1_0000_0000_0000_0000, + ): + print("{}({:x}) = {:x}".format(name, val, func(val))) + + +if __name__ == "__main__": + print("SKIP") + raise SystemExit diff --git a/tests/unix/ffi_int_long32.py b/tests/unix/ffi_int_long32.py new file mode 100644 index 0000000000000..32fdb8e0ec7df --- /dev/null +++ b/tests/unix/ffi_int_long32.py @@ -0,0 +1,16 @@ +# test 32-bit long arguments and return types for ffi functions + +import struct + +import ffi_int_base + +if struct.calcsize("l") != 4: + print("SKIP") + raise SystemExit + +ffi_int_base.test( + [ + ("l", "fli"), + ("L", "flu"), + ] +) diff --git a/tests/unix/ffi_int_long32.py.exp b/tests/unix/ffi_int_long32.py.exp new file mode 100644 index 0000000000000..e0f1338a48ed2 --- /dev/null +++ b/tests/unix/ffi_int_long32.py.exp @@ -0,0 +1,34 @@ +fli(0) = 1 +fli(7f) = 7e +fli(80) = 81 +fli(ff) = fe +fli(100) = 101 +fli(7fff) = 7ffe +fli(8000) = 8001 +fli(ffff) = fffe +fli(10000) = 10001 +fli(7fffffff) = 7ffffffe +fli(80000000) = -7fffffff +fli(ffffffff) = -2 +fli(100000000) = 1 +fli(7fffffffffffffff) = -2 +fli(8000000000000000) = 1 +fli(ffffffffffffffff) = -2 +fli(10000000000000000) = 1 +flu(0) = 1 +flu(7f) = 7e +flu(80) = 81 +flu(ff) = fe +flu(100) = 101 +flu(7fff) = 7ffe +flu(8000) = 8001 +flu(ffff) = fffe +flu(10000) = 10001 +flu(7fffffff) = 7ffffffe +flu(80000000) = 80000001 +flu(ffffffff) = fffffffe +flu(100000000) = 1 +flu(7fffffffffffffff) = fffffffe +flu(8000000000000000) = 1 +flu(ffffffffffffffff) = fffffffe +flu(10000000000000000) = 1 diff --git a/tests/unix/ffi_int_long64.py b/tests/unix/ffi_int_long64.py new file mode 100644 index 0000000000000..55bf6605232f0 --- /dev/null +++ b/tests/unix/ffi_int_long64.py @@ -0,0 +1,16 @@ +# test 64-bit long arguments and return types for ffi functions + +import struct + +import ffi_int_base + +if struct.calcsize("l") != 8: + print("SKIP") + raise SystemExit + +ffi_int_base.test( + [ + ("l", "fli"), + ("L", "flu"), + ] +) diff --git a/tests/unix/ffi_int_long64.py.exp b/tests/unix/ffi_int_long64.py.exp new file mode 100644 index 0000000000000..904e6c3ed445e --- /dev/null +++ b/tests/unix/ffi_int_long64.py.exp @@ -0,0 +1,34 @@ +fli(0) = 1 +fli(7f) = 7e +fli(80) = 81 +fli(ff) = fe +fli(100) = 101 +fli(7fff) = 7ffe +fli(8000) = 8001 +fli(ffff) = fffe +fli(10000) = 10001 +fli(7fffffff) = 7ffffffe +fli(80000000) = 80000001 +fli(ffffffff) = fffffffe +fli(100000000) = 100000001 +fli(7fffffffffffffff) = 7ffffffffffffffe +fli(8000000000000000) = -7fffffffffffffff +fli(ffffffffffffffff) = -2 +fli(10000000000000000) = 1 +flu(0) = 1 +flu(7f) = 7e +flu(80) = 81 +flu(ff) = fe +flu(100) = 101 +flu(7fff) = 7ffe +flu(8000) = 8001 +flu(ffff) = fffe +flu(10000) = 10001 +flu(7fffffff) = 7ffffffe +flu(80000000) = 80000001 +flu(ffffffff) = fffffffe +flu(100000000) = 100000001 +flu(7fffffffffffffff) = 7ffffffffffffffe +flu(8000000000000000) = 8000000000000001 +flu(ffffffffffffffff) = fffffffffffffffe +flu(10000000000000000) = 1 diff --git a/tests/unix/ffi_int_types.py b/tests/unix/ffi_int_types.py new file mode 100644 index 0000000000000..24fa2a721b210 --- /dev/null +++ b/tests/unix/ffi_int_types.py @@ -0,0 +1,16 @@ +# test 8/16/32/64 bit signed/unsigned integer arguments and return types for ffi functions + +import ffi_int_base + +ffi_int_base.test( + [ + ("b", "f8i"), + ("B", "f8u"), + ("h", "f16i"), + ("H", "f16u"), + ("i", "f32i"), + ("I", "f32u"), + ("q", "f64i"), + ("Q", "f64u"), + ] +) diff --git a/tests/unix/ffi_int_types.py.exp b/tests/unix/ffi_int_types.py.exp new file mode 100644 index 0000000000000..d6324477d6105 --- /dev/null +++ b/tests/unix/ffi_int_types.py.exp @@ -0,0 +1,136 @@ +f8i(0) = 1 +f8i(7f) = 7e +f8i(80) = -7f +f8i(ff) = -2 +f8i(100) = 1 +f8i(7fff) = -2 +f8i(8000) = 1 +f8i(ffff) = -2 +f8i(10000) = 1 +f8i(7fffffff) = -2 +f8i(80000000) = 1 +f8i(ffffffff) = -2 +f8i(100000000) = 1 +f8i(7fffffffffffffff) = -2 +f8i(8000000000000000) = 1 +f8i(ffffffffffffffff) = -2 +f8i(10000000000000000) = 1 +f8u(0) = 1 +f8u(7f) = 7e +f8u(80) = 81 +f8u(ff) = fe +f8u(100) = 1 +f8u(7fff) = fe +f8u(8000) = 1 +f8u(ffff) = fe +f8u(10000) = 1 +f8u(7fffffff) = fe +f8u(80000000) = 1 +f8u(ffffffff) = fe +f8u(100000000) = 1 +f8u(7fffffffffffffff) = fe +f8u(8000000000000000) = 1 +f8u(ffffffffffffffff) = fe +f8u(10000000000000000) = 1 +f16i(0) = 1 +f16i(7f) = 7e +f16i(80) = 81 +f16i(ff) = fe +f16i(100) = 101 +f16i(7fff) = 7ffe +f16i(8000) = -7fff +f16i(ffff) = -2 +f16i(10000) = 1 +f16i(7fffffff) = -2 +f16i(80000000) = 1 +f16i(ffffffff) = -2 +f16i(100000000) = 1 +f16i(7fffffffffffffff) = -2 +f16i(8000000000000000) = 1 +f16i(ffffffffffffffff) = -2 +f16i(10000000000000000) = 1 +f16u(0) = 1 +f16u(7f) = 7e +f16u(80) = 81 +f16u(ff) = fe +f16u(100) = 101 +f16u(7fff) = 7ffe +f16u(8000) = 8001 +f16u(ffff) = fffe +f16u(10000) = 1 +f16u(7fffffff) = fffe +f16u(80000000) = 1 +f16u(ffffffff) = fffe +f16u(100000000) = 1 +f16u(7fffffffffffffff) = fffe +f16u(8000000000000000) = 1 +f16u(ffffffffffffffff) = fffe +f16u(10000000000000000) = 1 +f32i(0) = 1 +f32i(7f) = 7e +f32i(80) = 81 +f32i(ff) = fe +f32i(100) = 101 +f32i(7fff) = 7ffe +f32i(8000) = 8001 +f32i(ffff) = fffe +f32i(10000) = 10001 +f32i(7fffffff) = 7ffffffe +f32i(80000000) = -7fffffff +f32i(ffffffff) = -2 +f32i(100000000) = 1 +f32i(7fffffffffffffff) = -2 +f32i(8000000000000000) = 1 +f32i(ffffffffffffffff) = -2 +f32i(10000000000000000) = 1 +f32u(0) = 1 +f32u(7f) = 7e +f32u(80) = 81 +f32u(ff) = fe +f32u(100) = 101 +f32u(7fff) = 7ffe +f32u(8000) = 8001 +f32u(ffff) = fffe +f32u(10000) = 10001 +f32u(7fffffff) = 7ffffffe +f32u(80000000) = 80000001 +f32u(ffffffff) = fffffffe +f32u(100000000) = 1 +f32u(7fffffffffffffff) = fffffffe +f32u(8000000000000000) = 1 +f32u(ffffffffffffffff) = fffffffe +f32u(10000000000000000) = 1 +f64i(0) = 1 +f64i(7f) = 7e +f64i(80) = 81 +f64i(ff) = fe +f64i(100) = 101 +f64i(7fff) = 7ffe +f64i(8000) = 8001 +f64i(ffff) = fffe +f64i(10000) = 10001 +f64i(7fffffff) = 7ffffffe +f64i(80000000) = 80000001 +f64i(ffffffff) = fffffffe +f64i(100000000) = 100000001 +f64i(7fffffffffffffff) = 7ffffffffffffffe +f64i(8000000000000000) = -7fffffffffffffff +f64i(ffffffffffffffff) = -2 +f64i(10000000000000000) = 1 +f64u(0) = 1 +f64u(7f) = 7e +f64u(80) = 81 +f64u(ff) = fe +f64u(100) = 101 +f64u(7fff) = 7ffe +f64u(8000) = 8001 +f64u(ffff) = fffe +f64u(10000) = 10001 +f64u(7fffffff) = 7ffffffe +f64u(80000000) = 80000001 +f64u(ffffffff) = fffffffe +f64u(100000000) = 100000001 +f64u(7fffffffffffffff) = 7ffffffffffffffe +f64u(8000000000000000) = 8000000000000001 +f64u(ffffffffffffffff) = fffffffffffffffe +f64u(10000000000000000) = 1 diff --git a/tests/unix/ffi_lib.c b/tests/unix/ffi_lib.c index 35340536aeede..dae4e04bc4463 100644 --- a/tests/unix/ffi_lib.c +++ b/tests/unix/ffi_lib.c @@ -31,3 +31,11 @@ int64_t f64i(int64_t x) { uint64_t f64u(uint64_t x) { return x ^ 1; } + +long fli(long x) { + return x ^ 1; +} + +unsigned long flu(unsigned long x) { + return x ^ 1; +} diff --git a/tools/.gitignore b/tools/.gitignore deleted file mode 100644 index 9f65f493bc655..0000000000000 --- a/tools/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -tinytest/.gitignore -tinytest/.travis.yml -tinytest/Makefile -tinytest/Makefile.arm-cortex-m3-qemu -tinytest/Makefile.avr -tinytest/TODO -tinytest/portable_demo.c -tinytest/tinytest_demo.c diff --git a/tools/ci.sh b/tools/ci.sh index bac225caa4df1..6f0f23a1c4810 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -17,6 +17,11 @@ function ci_gcc_arm_setup { arm-none-eabi-gcc --version } +function ci_gcc_riscv_setup { + sudo apt-get install gcc-riscv64-unknown-elf picolibc-riscv64-unknown-elf + riscv64-unknown-elf-gcc --version +} + ######################################################################################## # c code formatting @@ -50,12 +55,13 @@ function ci_code_size_setup { sudo apt-get install gcc-multilib gcc --version ci_gcc_arm_setup + ci_gcc_riscv_setup } function ci_code_size_build { # check the following ports for the change in their code size - PORTS_TO_CHECK=bmusxpd - SUBMODULES="lib/asf4 lib/berkeley-db-1.xx lib/mbedtls lib/micropython-lib lib/nxp_driver lib/pico-sdk lib/stm32lib lib/tinyusb" + PORTS_TO_CHECK=bmusxpdv + SUBMODULES="lib/asf4 lib/berkeley-db-1.xx lib/btstack lib/cyw43-driver lib/lwip lib/mbedtls lib/micropython-lib lib/nxp_driver lib/pico-sdk lib/stm32lib lib/tinyusb" # starts off at either the ref/pull/N/merge FETCH_HEAD, or the current branch HEAD git checkout -b pull_request # save the current location @@ -111,7 +117,7 @@ function ci_cc3200_build { # ports/esp32 # GitHub tag of ESP-IDF to use for CI (note: must be a tag or a branch) -IDF_VER=v5.0.4 +IDF_VER=v5.2.2 export IDF_CCACHE_ENABLE=1 @@ -239,24 +245,35 @@ function ci_powerpc_build { } ######################################################################################## -# ports/qemu-arm +# ports/qemu -function ci_qemu_arm_setup { +function ci_qemu_setup_arm { ci_gcc_arm_setup sudo apt-get update sudo apt-get install qemu-system qemu-system-arm --version } -function ci_qemu_arm_build { +function ci_qemu_setup_rv32 { + ci_gcc_riscv_setup + sudo apt-get update + sudo apt-get install qemu-system + qemu-system-riscv32 --version +} + +function ci_qemu_build_arm { + make ${MAKEOPTS} -C mpy-cross + make ${MAKEOPTS} -C ports/qemu submodules + make ${MAKEOPTS} -C ports/qemu CFLAGS_EXTRA=-DMP_ENDIANNESS_BIG=1 + make ${MAKEOPTS} -C ports/qemu clean + make ${MAKEOPTS} -C ports/qemu test + make ${MAKEOPTS} -C ports/qemu BOARD=SABRELITE test +} + +function ci_qemu_build_rv32 { make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/qemu-arm submodules - make ${MAKEOPTS} -C ports/qemu-arm CFLAGS_EXTRA=-DMP_ENDIANNESS_BIG=1 - make ${MAKEOPTS} -C ports/qemu-arm clean - make ${MAKEOPTS} -C ports/qemu-arm -f Makefile.test submodules - make ${MAKEOPTS} -C ports/qemu-arm -f Makefile.test test - make ${MAKEOPTS} -C ports/qemu-arm -f Makefile.test clean - make ${MAKEOPTS} -C ports/qemu-arm -f Makefile.test BOARD=sabrelite test + make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV32 submodules + make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV32 test } ######################################################################################## @@ -292,6 +309,8 @@ function ci_rp2_build { make ${MAKEOPTS} -C ports/rp2 make ${MAKEOPTS} -C ports/rp2 BOARD=RPI_PICO_W submodules make ${MAKEOPTS} -C ports/rp2 BOARD=RPI_PICO_W USER_C_MODULES=../../examples/usercmodule/micropython.cmake + make ${MAKEOPTS} -C ports/rp2 BOARD=RPI_PICO2 submodules + make ${MAKEOPTS} -C ports/rp2 BOARD=RPI_PICO2 make ${MAKEOPTS} -C ports/rp2 BOARD=W5100S_EVB_PICO submodules make ${MAKEOPTS} -C ports/rp2 BOARD=W5100S_EVB_PICO @@ -331,7 +350,7 @@ function ci_stm32_pyb_build { git submodule update --init lib/mynewt-nimble make ${MAKEOPTS} -C ports/stm32 BOARD=PYBV11 MICROPY_PY_NETWORK_WIZNET5K=5200 USER_C_MODULES=../../examples/usercmodule make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF2 - make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF6 NANBOX=1 MICROPY_BLUETOOTH_NIMBLE=0 MICROPY_BLUETOOTH_BTSTACK=1 + make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF6 COPT=-O2 NANBOX=1 MICROPY_BLUETOOTH_NIMBLE=0 MICROPY_BLUETOOTH_BTSTACK=1 make ${MAKEOPTS} -C ports/stm32/mboot BOARD=PYBV10 CFLAGS_EXTRA='-DMBOOT_FSLOAD=1 -DMBOOT_VFS_LFS2=1' make ${MAKEOPTS} -C ports/stm32/mboot BOARD=PYBD_SF6 make ${MAKEOPTS} -C ports/stm32/mboot BOARD=STM32F769DISC CFLAGS_EXTRA='-DMBOOT_ADDRESS_SPACE_64BIT=1 -DMBOOT_SDCARD_ADDR=0x100000000ULL -DMBOOT_SDCARD_BYTE_SIZE=0x400000000ULL -DMBOOT_FSLOAD=1 -DMBOOT_VFS_FAT=1' @@ -394,7 +413,6 @@ CI_UNIX_OPTS_QEMU_MIPS=( CROSS_COMPILE=mips-linux-gnu- VARIANT=coverage MICROPY_STANDALONE=1 - LDFLAGS_EXTRA="-static" ) CI_UNIX_OPTS_QEMU_ARM=( @@ -403,6 +421,12 @@ CI_UNIX_OPTS_QEMU_ARM=( MICROPY_STANDALONE=1 ) +CI_UNIX_OPTS_QEMU_RISCV64=( + CROSS_COMPILE=riscv64-linux-gnu- + VARIANT=coverage + MICROPY_STANDALONE=1 +) + function ci_unix_build_helper { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/unix "$@" submodules @@ -623,29 +647,30 @@ function ci_unix_macos_build { function ci_unix_macos_run_tests { # Issues with macOS tests: - # - import_pkg7 has a problem with relative imports - # - random_basic has a problem with getrandbits(0) - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-standard/micropython ./run-tests.py --exclude 'import_pkg7.py' --exclude 'random_basic.py') + # - float_parse and float_parse_doubleprec parse/print floats out by a few mantissa bits + # - ffi_callback crashes for an unknown reason + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-standard/micropython ./run-tests.py --exclude '(float_parse|float_parse_doubleprec|ffi_callback).py') } function ci_unix_qemu_mips_setup { sudo apt-get update - sudo apt-get install gcc-mips-linux-gnu g++-mips-linux-gnu + sudo apt-get install gcc-mips-linux-gnu g++-mips-linux-gnu libc6-mips-cross sudo apt-get install qemu-user qemu-mips --version + sudo mkdir /etc/qemu-binfmt + sudo ln -s /usr/mips-linux-gnu/ /etc/qemu-binfmt/mips } function ci_unix_qemu_mips_build { - # qemu-mips on GitHub Actions will seg-fault if not linked statically ci_unix_build_helper "${CI_UNIX_OPTS_QEMU_MIPS[@]}" + ci_unix_build_ffi_lib_helper mips-linux-gnu-gcc } function ci_unix_qemu_mips_run_tests { # Issues with MIPS tests: # - (i)listdir does not work, it always returns the empty list (it's an issue with the underlying C call) - # - ffi tests do not work file ./ports/unix/build-coverage/micropython - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py --exclude 'vfs_posix.*\.py' --exclude 'ffi_(callback|float|float2).py') + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py --exclude 'vfs_posix.*\.py') } function ci_unix_qemu_arm_setup { @@ -653,6 +678,8 @@ function ci_unix_qemu_arm_setup { sudo apt-get install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi sudo apt-get install qemu-user qemu-arm --version + sudo mkdir /etc/qemu-binfmt + sudo ln -s /usr/arm-linux-gnueabi/ /etc/qemu-binfmt/arm } function ci_unix_qemu_arm_build { @@ -663,11 +690,29 @@ function ci_unix_qemu_arm_build { function ci_unix_qemu_arm_run_tests { # Issues with ARM tests: # - (i)listdir does not work, it always returns the empty list (it's an issue with the underlying C call) - export QEMU_LD_PREFIX=/usr/arm-linux-gnueabi file ./ports/unix/build-coverage/micropython (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py --exclude 'vfs_posix.*\.py') } +function ci_unix_qemu_riscv64_setup { + sudo apt-get update + sudo apt-get install gcc-riscv64-linux-gnu g++-riscv64-linux-gnu + sudo apt-get install qemu-user + qemu-riscv64 --version + sudo mkdir /etc/qemu-binfmt + sudo ln -s /usr/riscv64-linux-gnu/ /etc/qemu-binfmt/riscv64 +} + +function ci_unix_qemu_riscv64_build { + ci_unix_build_helper "${CI_UNIX_OPTS_QEMU_RISCV64[@]}" + ci_unix_build_ffi_lib_helper riscv64-linux-gnu-gcc +} + +function ci_unix_qemu_riscv64_run_tests { + file ./ports/unix/build-coverage/micropython + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py) +} + ######################################################################################## # ports/windows @@ -684,9 +729,9 @@ function ci_windows_build { ######################################################################################## # ports/zephyr -ZEPHYR_DOCKER_VERSION=v0.21.0 -ZEPHYR_SDK_VERSION=0.13.2 -ZEPHYR_VERSION=v3.1.0 +ZEPHYR_DOCKER_VERSION=v0.26.13 +ZEPHYR_SDK_VERSION=0.16.8 +ZEPHYR_VERSION=v3.7.0 function ci_zephyr_setup { docker pull zephyrprojectrtos/ci:${ZEPHYR_DOCKER_VERSION} @@ -698,6 +743,11 @@ function ci_zephyr_setup { -w /micropython/ports/zephyr \ zephyrprojectrtos/ci:${ZEPHYR_DOCKER_VERSION} docker ps -a + + # qemu-system-arm is needed to run the test suite. + sudo apt-get update + sudo apt-get install qemu-system-arm + qemu-system-arm --version } function ci_zephyr_install { @@ -712,3 +762,10 @@ function ci_zephyr_build { docker exec zephyr-ci west build -p auto -b mimxrt1050_evk docker exec zephyr-ci west build -p auto -b nucleo_wb55rg # for bluetooth } + +function ci_zephyr_run_tests { + docker exec zephyr-ci west build -p auto -b qemu_cortex_m3 -- -DCONF_FILE=prj_minimal.conf + # Issues with zephyr tests: + # - inf_nan_arith fails pow(-1, nan) test + (cd tests && ./run-tests.py --target minimal --device execpty:"qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -monitor null -serial pty -kernel ../ports/zephyr/build/zephyr/zephyr.elf" -d basics float --exclude inf_nan_arith) +} diff --git a/tools/ci_check_duplicate_usb_vid_pid.py b/tools/ci_check_duplicate_usb_vid_pid.py index 233c7acdffc42..5361914af199b 100644 --- a/tools/ci_check_duplicate_usb_vid_pid.py +++ b/tools/ci_check_duplicate_usb_vid_pid.py @@ -53,6 +53,7 @@ "0x303A:0x7003": [ "espressif_esp32s3_devkitc_1_n8", "espressif_esp32s3_devkitc_1_n8r2", + "espressif_esp32s3_devkitc_1_n8r2_ros", "espressif_esp32s3_devkitc_1_n8r8", "espressif_esp32s3_devkitc_1_n8r8_hacktablet", "espressif_esp32s3_devkitc_1_n16", @@ -63,6 +64,10 @@ "espressif_esp32s2_devkitc_1_n4r2", "espressif_esp32s2_devkitc_1_n8r2", ], + "0x303A:0x81DA": [ + "m5stack_cardputer", + "m5stack_cardputer_ros", + ], "0x239A:0x102E": ["weact_studio_pico", "weact_studio_pico_16mb"], "0x303A:0x8166": ["yd_esp32_s3_n8r8", "yd_esp32_s3_n16r8"], "0x2341:0x056B": ["arduino_nano_esp32s3", "arduino_nano_esp32s3_inverted_statusled"], diff --git a/tools/makemanifest.py b/tools/makemanifest.py index a74a6934aeabe..e076a03e0be3c 100644 --- a/tools/makemanifest.py +++ b/tools/makemanifest.py @@ -245,7 +245,11 @@ def main(): b'#include "py/emitglue.h"\n' b"extern const qstr_pool_t mp_qstr_const_pool;\n" b"const qstr_pool_t mp_qstr_frozen_const_pool = {\n" - b" (qstr_pool_t*)&mp_qstr_const_pool, MP_QSTRnumber_of, 0, 0\n" + b" #if MICROPY_QSTR_BYTES_IN_HASH\n" + b" (qstr_pool_t*)&mp_qstr_const_pool, MP_QSTRnumber_of, 0, 0, 0, NULL, NULL, {},\n" + b" #else\n" + b" (qstr_pool_t*)&mp_qstr_const_pool, MP_QSTRnumber_of, 0, 0, 0, NULL, {},\n" + b" #endif\n" b"};\n" b'const char mp_frozen_names[] = { MP_FROZEN_STR_NAMES "\\0"};\n' b"const mp_raw_code_t *const mp_frozen_mpy_content[] = {NULL};\n" diff --git a/tools/merge_micropython.py b/tools/merge_micropython.py index 37d44c3b7e3a0..97dd53fd33a25 100644 --- a/tools/merge_micropython.py +++ b/tools/merge_micropython.py @@ -8,7 +8,7 @@ I add a sys.exit(0) after a section, and once a section runs, I delete it temporarily and move on to the next section. -- dhalbert -Updated for v1.22.2 merge - dhalbert +Updated for v1.24.1 merge - dhalbert """ @@ -18,256 +18,224 @@ from sh import git import sys -out_buf = StringIO() -ports_to_delete = [ - "bare-arm", - "cc3200", - "embed", - "esp32", - "esp8266", - "mimxrt", - "minimal", - "nrf", - "pic16bit", - "powerpc", - "qemu-arm", - "renesas-ra", - "rp2", - "samd", - "stm32", - "webassembly", - "windows", - "zephyr", -] -for p in ports_to_delete: - try: - git.rm("-rf", "ports/" + p) - except sh.ErrorReturnCode_128: - pass +def rm_paths(base, paths): + for path in paths: + try: + git.rm("-rf", base + "/" + path) + except sh.ErrorReturnCode_128: + pass -# We inherit stm32 changes into stm because we did a git rename. -git.status("--porcelain=1", "ports/stm", _out=out_buf) -out_buf.seek(0) -line = out_buf.readline() -while line: - state, path = line.split() - if state == "UU": - git.checkout("--ours", path) - git.add(path) - elif state == "UA": - git.rm(path) - line = out_buf.readline() -# MicroPython has their own CI settings. Let's not use them now. -out_buf = StringIO() -git.status("--porcelain=1", ".github/workflows", _out=out_buf) -out_buf.seek(0) -line = out_buf.readline() -while line: - state, path = line.split() - if state == "A": - git.rm("-f", path) - else: - print(state, path) - line = out_buf.readline() - -# Delete docs and tests for things we don't need anymore -docs_to_delete = [ - "conf.py", - "develop", - "differences", - "esp32", - "esp8266", - "library/bluetooth.rst", - "library/btree.rst", - "library/cryptolib.rst", - "library/esp*.rst", - "library/framebuf.rst", - "library/hashlib.rst", - "library/lcd160cr.rst", - "library/machine*.rst", - "library/math.rst", - "library/network*.rst", - "library/os.rst", - "library/pyb*.rst", - "library/random.rst", - "library/rp2*.rst", - "library/uos.rst", - "library/socket.rst", - "library/ssl.rst", - "library/stm.rst", - "library/struct.rst", - "library/_thread.rst", - "library/time.rst", - "library/uasyncio.rst", - "library/uctypes.rst", - "library/wipy.rst", - "library/wm8960.rst", - "library/zephyr*.rst", - "library/zlib.rst", - "make.bat", - "mimxrt", - "pyboard", - "reference", - "renesas-ra", - "rp2", - "samd", - "templates/topindex.html", - "wipy", - "zephyr", -] -for d in docs_to_delete: - try: - git.rm("-rf", "docs/" + d) - except sh.ErrorReturnCode_128: - pass - -tests_to_delete = [ - "esp32", - "multi_bluetooth", - "multi_espnow", - "multi_net", - "net_hosted", - "net_inet", - "pyb", - "wipy", -] -for t in tests_to_delete: - try: - git.rm("-rf", "tests/" + t) - except sh.ErrorReturnCode_128: - pass - - -libs_to_delete = [ - "asf4", - "btstack", - "libhydrogen", - "lwip", - "micropython-lib", - "mynewt-nimble", - "nrfx", - "nxp_driver", - "pico-sdk", - "protobuf-c", - "stm32lib", - "wiznet5k", -] -for l in libs_to_delete: - try: - git.rm("-rf", "lib/" + l) - except sh.ErrorReturnCode_128: - pass - -extmod_to_delete = [ - "btstack", - "extmod.cmake", - "machine_*", - "mbedtls", - "modbluetooth.*", - "modbtree.*", - "modframebuf.*", - "modlwip.*", - "modnetwork.*", - "modonewire.*", - "moducryptolib.*", - "modsocket.*", - "modssl_*.*", - "modtimeq.*", - "modwebsocket.*", - "modwebrepl.*", - "mpbthci.*", - "network_*.*", - "nimble", -] -for e in extmod_to_delete: - try: - git.rm("-rf", "extmod/" + e) - except sh.ErrorReturnCode_128 as error: - print(error) - -top_delete = [ - "drivers", - "README.md", - "CODEOFCONDUCT.md", - "CODECONVENTIONS.md", -] -for t in top_delete: - try: - git.rm("-rf", t) - except sh.ErrorReturnCode_128: - pass - -dot_github_delete = [ - ".github/dependabot.yml", - ".github/FUNDING.yml", - ".github/ISSUE_TEMPLATE/documentation.md", - ".github/ISSUE_TEMPLATE/security.md", - ".github/workflows/code_formatting.yml", - ".github/workflows/code_size_comment.yml", - ".github/workflows/code_size.yml", - ".github/workflows/commit_formatting.yml", - ".github/workflows/docs.yml", - ".github/workflows/examples.yml", - ".github/workflows/mpremote.yml", - ".github/workflows/mpy_format.yml", - ".github/workflows/mpy_format.yml", - ".github/workflows/ports_*.yml", -] -for t in dot_github_delete: - try: - git.rm("-rf", t) - except sh.ErrorReturnCode_128: - pass - -# Always ours: -always_ours = [ - ".github", - "devices", - "supervisor", - "shared-bindings", - "shared-module", - "ports/atmel-samd", - "ports/cxd56", - "ports/espressif", - "ports/mimxrt10xx", - "ports/raspberrypi", - "ports/stm", -] -for ours in always_ours: - out_buf = StringIO() - git.status("--porcelain=1", ours, _out=out_buf) - out_buf.seek(0) - line = out_buf.readline() - while line: - state, path = line.split() - if state == "UU": - print("ours", path) - git.checkout("--ours", path) - git.add(path) - else: - print(state, path) +def checkout_ours(always_ours): + for ours in always_ours: + out_buf = StringIO() + git.status("--porcelain=1", ours, _out=out_buf) + out_buf.seek(0) line = out_buf.readline() + while line: + state, path = line.split() + if state == "UU": + print("ours", path) + git.checkout("--ours", path) + git.add(path) + else: + print(state, path) + line = out_buf.readline() + + +rm_paths( + "ports", + [ + "bare-arm", + "cc3200", + "embed", + "esp32", + "esp8266", + "mimxrt", + "minimal", + "nrf", + "pic16bit", + "powerpc", + "qemu", + "renesas-ra", + "rp2", + "samd", + "stm32", + "webassembly", + "windows", + "zephyr", + ], +) + +# Delete MicroPython-specific docs. +rm_paths( + "docs", + [ + "conf.py", + "develop", + "differences", + "esp32", + "esp8266", + "library/bluetooth.rst", + "library/btree.rst", + "library/cryptolib.rst", + "library/esp*.rst", + "library/framebuf.rst", + "library/hashlib.rst", + "library/lcd160cr.rst", + "library/machine*.rst", + "library/math.rst", + "library/network*.rst", + "library/os.rst", + "library/pyb*.rst", + "library/random.rst", + "library/rp2*.rst", + "library/uos.rst", + "library/socket.rst", + "library/ssl.rst", + "library/stm.rst", + "library/struct.rst", + "library/_thread.rst", + "library/time.rst", + "library/uasyncio.rst", + "library/uctypes.rst", + "library/wipy.rst", + "library/wm8960.rst", + "library/zephyr*.rst", + "library/zlib.rst", + "make.bat", + "mimxrt", + "pyboard", + "renesas-ra", + "rp2", + "samd", + "templates/topindex.html", + "wipy", + "zephyr", + ], +) + +# Delete MicroPython-specific tests. +rm_paths( + "tests", + [ + "esp32", + "multi_bluetooth", + "multi_espnow", + "multi_net", + "net_hosted", + "net_inet", + "pyb", + "wipy", + ], +) + +# libs we don't use +rm_paths( + "lib", + [ + "asf4", + "btstack", + "libhydrogen", + "lwip", + "micropython-lib", + "mynewt-nimble", + "nrfx", + "nxp_driver", + "pico-sdk", + "protobuf-c", + "stm32lib", + "wiznet5k", + ], +) + +# extmod modules we don't use +rm_paths( + "extmod", + [ + "btstack", + "extmod.cmake", + "machine_*", + "mbedtls", + "modbluetooth.*", + "modbtree.*", + "modframebuf.*", + "modlwip.*", + "modnetwork.*", + "modonewire.*", + "moducryptolib.*", + "modsocket.*", + "modssl_*.*", + "modtimeq.*", + "modwebsocket.*", + "modwebrepl.*", + "mpbthci.*", + "network_*.*", + "nimble", + ], +) + +# shared things we don't use +rm_paths( + "shared", + [ + "tinyusb", + "runtime/softtimer.*", + ], +) + +# top-level files and dirs we don't use +rm_paths( + "", + [ + "drivers", + "LICENSE_MicroPython", + "README.md", + "CODEOFCONDUCT.md", + "CODECONVENTIONS.md", + ], +) + +# .github and CI we don't use +rm_paths( + ".github", + [ + "dependabot.yml", + "FUNDING.yml", + "ISSUE_TEMPLATE/feature_request.yml", + "ISSUE_TEMPLATE/documentation.yml", + "ISSUE_TEMPLATE/security.yml", + "workflows/biome.yml", + "workflows/code_formatting.yml", + "workflows/code_size_comment.yml", + "workflows/code_size.yml", + "workflows/codespell.yml", + "workflows/commit_formatting.yml", + "workflows/docs.yml", + "workflows/examples.ymlworkflows/mpremote.yml", + "workflows/mpy_format.yml", + "workflows/ports_*.yml", + "workflows/ruff.yml", + ], +) -# # Check to see if any files changed only in formatting -# out_buf = StringIO() -# git.status("--porcelain=1", ".", _out=out_buf) -# out_buf.seek(0) -# line = out_buf.readline() -# while line: -# state = line.split()[0] -# if state in ("D", "R", "DD"): -# line = out_buf.readline() -# continue -# state, path = line.split() -# log_buf = StringIO() -# git.log("--pretty=tformat:%H", "25ae98f..HEAD", path, _out=log_buf, _tty_out=False) -# log_buf.seek(0) -# commits = [] -# for line in log_buf.readlines(): -# commits.append(line.strip()) -# if state in ["UU", "M"] and commits == ["a52eb88031620a81521b937f2a0651dbac2bb350"]: -# git.checkout("--theirs", path) -# git.add(path) -# line = out_buf.readline() +# Always ours: +checkout_ours( + [ + ".github", + "devices", + "lib/mbedtls_config", + "supervisor", + "shared-bindings", + "shared-module", + "ports/atmel-samd", + "ports/cxd56", + "ports/espressif", + "ports/mimxrt10xx", + "ports/raspberrypi", + "ports/silabs", + # We inherit stm32 changes into stm because we did a git rename. + "ports/stm", + ] +) diff --git a/tools/metrics.py b/tools/metrics.py index 9c5ed1d7d5a60..f6189e65abb4d 100755 --- a/tools/metrics.py +++ b/tools/metrics.py @@ -69,8 +69,9 @@ def __init__(self, name, dir, output, make_flags=None): "x": PortData("mimxrt", "mimxrt", "build-TEENSY40/firmware.elf"), "e": PortData("renesas-ra", "renesas-ra", "build-EK_RA6M2/firmware.elf"), "r": PortData("nrf", "nrf", "build-PCA10040/firmware.elf"), - "p": PortData("rp2", "rp2", "build-RPI_PICO/firmware.elf"), + "p": PortData("rp2", "rp2", "build-RPI_PICO_W/firmware.elf", "BOARD=RPI_PICO_W"), "d": PortData("samd", "samd", "build-ADAFRUIT_ITSYBITSY_M4_EXPRESS/firmware.elf"), + "v": PortData("qemu rv32", "qemu", "build-VIRT_RV32/firmware.elf", "BOARD=VIRT_RV32"), } diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 1d46d9700a69d..b56be0f05b648 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -113,6 +113,7 @@ class Config: MP_NATIVE_ARCH_ARMV7EMDP = 8 MP_NATIVE_ARCH_XTENSA = 9 MP_NATIVE_ARCH_XTENSAWIN = 10 +MP_NATIVE_ARCH_RV32IMC = 11 MP_PERSISTENT_OBJ_FUN_TABLE = 0 MP_PERSISTENT_OBJ_NONE = 1 @@ -735,8 +736,8 @@ def freeze_constant_obj(self, obj_name, obj): elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_NONE: raise FreezeError(self, "target does not support long int") elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_LONGLONG: - # TODO - raise FreezeError(self, "freezing int to long-long is not implemented") + print("static const mp_obj_int_t %s = {{&mp_type_int}, %d};" % (obj_name, obj)) + return "MP_ROM_PTR(&%s)" % obj_name elif config.MICROPY_LONGINT_IMPL == config.MICROPY_LONGINT_IMPL_MPZ: neg = 0 if obj < 0: @@ -1083,6 +1084,7 @@ def __init__( MP_NATIVE_ARCH_X64, MP_NATIVE_ARCH_XTENSA, MP_NATIVE_ARCH_XTENSAWIN, + MP_NATIVE_ARCH_RV32IMC, ): self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",@progbits # ")))' else: @@ -1098,8 +1100,10 @@ def __init__( ): # ARMV6 or Xtensa -- four byte align. self.fun_data_attributes += " __attribute__ ((aligned (4)))" - elif MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP: - # ARMVxxM -- two byte align. + elif ( + MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP + ) or config.native_arch == MP_NATIVE_ARCH_RV32IMC: + # ARMVxxM or RV32IMC -- two byte align. self.fun_data_attributes += " __attribute__ ((aligned (2)))" def disassemble(self): diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index efde6af6ba5c9..f3ccd1f119e83 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -69,6 +69,7 @@ R_386_GOTOFF = 9 R_386_GOTPC = 10 R_ARM_THM_CALL = 10 +R_XTENSA_ASM_EXPAND = 11 R_XTENSA_DIFF32 = 19 R_XTENSA_SLOT0_OP = 20 R_ARM_BASE_PREL = 25 # aka R_ARM_GOTPC @@ -88,10 +89,26 @@ def asm_jump_x86(entry): def asm_jump_thumb(entry): - # Only signed values that fit in 12 bits are supported + # This function must return the same number of bytes for the encoding of the jump + # regardless of the value of `entry`. b_off = entry - 4 - assert b_off >> 11 == 0 or b_off >> 11 == -1, b_off - return struct.pack("> 1 & 0x07FF)) + if b_off >> 11 == 0 or b_off >> 11 == -1: + # Signed value fits in 12 bits. + b0 = 0xE000 | (b_off >> 1 & 0x07FF) + b1 = 0 + b2 = 0 + b3 = 0 + else: + # Use bl to do a large jump/call: + # push {r0, lr} + # bl + # pop {r0, pc} + b_off -= 2 # skip "push {r0, lr}" + b0 = 0xB400 | 0x0100 | 0x0001 # push, lr, r0 + b1 = 0xF000 | (((b_off) >> 12) & 0x07FF) + b2 = 0xF800 | (((b_off) >> 1) & 0x07FF) + b3 = 0xBC00 | 0x0100 | 0x0001 # pop, pc, r0 + return struct.pack("` argument... - -test_dirs = set( - ( - "basics", - "extmod", - "float", - "micropython", - "misc", - ) -) - -exclude_tests = set( - ( - # pattern matching in .exp - "basics/bytes_compare3.py", - "extmod/ticks_diff.py", - "extmod/time_ms_us.py", - # unicode char issue - "extmod/json_loads.py", - # doesn't output to python stdout - "extmod/re_debug.py", - "extmod/vfs_basic.py", - "extmod/vfs_fat_ramdisk.py", - "extmod/vfs_fat_fileio.py", - "extmod/vfs_fat_fsusermount.py", - "extmod/vfs_fat_oldproto.py", - # rounding issues - "float/float_divmod.py", - # requires double precision floating point to work - "float/float2int_doubleprec_intbig.py", - "float/float_format_ints_doubleprec.py", - "float/float_parse_doubleprec.py", - # different filename in output - "micropython/emg_exc.py", - "micropython/heapalloc_traceback.py", - # don't have emergency exception buffer - "micropython/heapalloc_exc_compressed_emg_exc.py", - # pattern matching in .exp - "micropython/meminfo.py", - # needs sys stdfiles - "misc/print_exception.py", - # settrace .exp files are too large - "misc/sys_settrace_loop.py", - "misc/sys_settrace_generator.py", - "misc/sys_settrace_features.py", - # don't have f-string - "basics/string_fstring.py", - "basics/string_fstring_debug.py", - ) -) - -output = [] -tests = [] - -argparser = argparse.ArgumentParser( - description="Convert native MicroPython tests to tinytest/upytesthelper C code" -) -argparser.add_argument("--stdin", action="store_true", help="read list of tests from stdin") -argparser.add_argument("--exclude", action="append", help="exclude test by name") -argparser.add_argument( - "--profile", - type=argparse.FileType("rt", encoding="utf-8"), - help="optional profile file providing test directories and exclusion list", -) -args = argparser.parse_args() - -if not args.stdin: - if args.profile: - test_dirs, exclude_tests = load_profile(args.profile, test_dirs, exclude_tests) - if args.exclude: - exclude_tests = exclude_tests.union(args.exclude) - for group in test_dirs: - tests += [test for test in glob("{}/*.py".format(group)) if test not in exclude_tests] -else: - for l in sys.stdin: - tests.append(l.rstrip()) - -output.extend([test_function.format(**script_to_map(test)) for test in tests]) -testcase_members = [testcase_member.format(**chew_filename(test)) for test in tests] -output.append(testcase_struct.format(name="", body="\n".join(testcase_members))) - -testgroup_members = [testgroup_member.format(name=group) for group in [""]] - -output.append(testgroup_struct.format(body="\n".join(testgroup_members))) - -## XXX: may be we could have `--output ` argument... -# Don't depend on what system locale is set, use utf8 encoding. -sys.stdout.buffer.write("\n\n".join(output).encode("utf8"))