diff options
70 files changed, 1368 insertions, 551 deletions
diff --git a/.github/workflows/ports_unix.yml b/.github/workflows/ports_unix.yml index 662121654e..4b22926eaf 100644 --- a/.github/workflows/ports_unix.yml +++ b/.github/workflows/ports_unix.yml @@ -71,6 +71,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. + # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. + with: + python-version: '3.11' - name: Install packages run: source tools/ci.sh && ci_unix_coverage_setup - name: Build @@ -169,23 +174,6 @@ jobs: if: failure() run: tests/run-tests.py --print-failures - settrace: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. - # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. - with: - python-version: '3.11' - - name: Build - run: source tools/ci.sh && ci_unix_settrace_build - - name: Run main test suite - run: source tools/ci.sh && ci_unix_settrace_run_tests - - name: Print failures - if: failure() - run: tests/run-tests.py --print-failures - settrace_stackless: runs-on: ubuntu-latest steps: @@ -263,10 +251,40 @@ jobs: if: failure() run: tests/run-tests.py --print-failures + sanitize_address: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. + # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. + with: + python-version: '3.11' + - name: Install packages + run: source tools/ci.sh && ci_unix_coverage_setup + - name: Build + run: source tools/ci.sh && ci_unix_sanitize_address_build + - name: Run main test suite + run: source tools/ci.sh && ci_unix_sanitize_address_run_tests + - name: Test merging .mpy files + run: source tools/ci.sh && ci_unix_coverage_run_mpy_merge_tests + - name: Build native mpy modules + run: source tools/ci.sh && ci_native_mpy_modules_build + - name: Test importing .mpy generated by mpy_ld.py + run: source tools/ci.sh && ci_unix_coverage_run_native_mpy_tests + - name: Print failures + if: failure() + run: tests/run-tests.py --print-failures + sanitize_undefined: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + # Python 3.12 is the default for ubuntu-24.04, but that has compatibility issues with settrace tests. + # Can remove this step when ubuntu-latest uses a more recent Python 3.x as the default. + with: + python-version: '3.11' - name: Install packages run: source tools/ci.sh && ci_unix_coverage_setup - name: Build diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 65a3412ecb..b53559ed8c 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -825,6 +825,12 @@ static mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_ // Check for any pending errors STREAM_ERROR_CHECK(socket); + if (socket->state == STATE_LISTENING) { + // original socket in listening state, not the accepted connection. + *_errno = MP_ENOTCONN; + return -1; + } + if (socket->incoming.tcp.pbuf == NULL) { // Non-blocking socket or flag diff --git a/ports/alif/Makefile b/ports/alif/Makefile index 6870667436..d258b27b1d 100644 --- a/ports/alif/Makefile +++ b/ports/alif/Makefile @@ -21,6 +21,7 @@ Reset\n\ Exit ALIF_TOC_CONFIG = alif_cfg.json +ALIF_TOC_BIN = $(BUILD)/firmware.toc.bin ALIF_TOC_APPS = $(BUILD)/$(ALIF_TOC_CONFIG) ALIF_TOC_CFLAGS += -DTOC_CFG_FILE=$(ALIF_TOOLKIT_CFG_FILE) @@ -69,7 +70,7 @@ include $(TOP)/extmod/extmod.mk # Main targets .PHONY: all -all: $(BUILD)/firmware.toc.bin +all: $(BUILD)/firmware.zip # Force make commands to run the targets every time # regardless of whether firmware.toc.bin already exists @@ -81,24 +82,28 @@ $(BUILD): $(MKDIR) -p $@ $(BUILD)/M55_HP/firmware.bin: - make -f alif.mk MCU_CORE=M55_HP MICROPY_PY_OPENAMP_MODE=0 + make -f alif.mk BUILD=$(BUILD)/M55_HP MCU_CORE=M55_HP MICROPY_PY_OPENAMP_MODE=0 $(BUILD)/M55_HE/firmware.bin: - make -f alif.mk MCU_CORE=M55_HE MICROPY_PY_OPENAMP_MODE=1 + make -f alif.mk BUILD=$(BUILD)/M55_HE MCU_CORE=M55_HE MICROPY_PY_OPENAMP_MODE=1 $(BUILD)/$(ALIF_TOC_CONFIG): mcu/$(ALIF_TOC_CONFIG).in | $(BUILD) $(ECHO) "Preprocess toc config $@" $(Q)$(CPP) -P -E $(ALIF_TOC_CFLAGS) - < mcu/$(ALIF_TOC_CONFIG).in > $@ -$(BUILD)/firmware.toc.bin: $(ALIF_TOC_APPS) +$(ALIF_TOC_BIN): $(ALIF_TOC_APPS) $(Q)python $(ALIF_TOOLS)/app-gen-toc.py \ --filename $(abspath $(BUILD)/$(ALIF_TOC_CONFIG)) \ --output-dir $(BUILD) \ --firmware-dir $(BUILD) \ --output $@ +$(BUILD)/firmware.zip: $(ALIF_TOC_BIN) $(ALIF_TOC_APPS) + $(ECHO) "Create $@" + $(Q)$(ZIP) -q - $(BUILD)/application_package.ds $^ > $@ + .PHONY: deploy -deploy: $(BUILD)/firmware.toc.bin +deploy: $(ALIF_TOC_BIN) $(ECHO) "Writing $< to the board" $(Q)python $(ALIF_TOOLS)/app-write-mram.py \ --cfg-part $(ALIF_TOOLKIT_CFG_PART) \ diff --git a/ports/alif/README.md b/ports/alif/README.md index 824a63da18..dcf327060f 100644 --- a/ports/alif/README.md +++ b/ports/alif/README.md @@ -19,3 +19,61 @@ The following more advanced features will follow later: - Ethernet support. - SDRAM support. - Other machine modules. + +Build instructions +------------------ + +Before building the firmware for a given board the MicroPython cross-compiler +must be built; it will be used to pre-compile some of the built-in scripts to +bytecode. The cross-compiler is built and run on the host machine, using: +```bash +$ make -C mpy-cross +``` + +This command should be executed from the root directory of this repository. +All other commands below should be executed from the ports/alif/ directory. + +An ARM compiler is required for the build, along with the associated binary +utilities. The recommended toolchain version to use with this port is +Arm GNU toolchain version 13.3.Rel1. The compiler can be changed using the +`CROSS_COMPILE` variable when invoking `make`. + +Next, the board to build must be selected. The default board is `ALIF_ENSEMBLE` +but any of the names of the subdirectories in the `boards/` directory is valid. +The board name must be passed as the argument to `BOARD=` when invoking `make`. + +All boards require certain submodules to be obtained before they can be built. +The correct set of submodules can be initialised using (with `ALIF_ENSEMBLE` +as an example of the selected board): +```bash +make BOARD=ALIF_ENSEMBLE submodules +``` + +Then to build the board's firmware run: +```bash +make BOARD=ALIF_ENSEMBLE +``` + +The above command should produce binary images in the `build-ALIF_ENSEMBLE/` +subdirectory (or the equivalent directory for the board specified). + +### Update the SE Firmware + +The SE firmware must be updated **before** flashing the main firmware to match +the version used by MicroPython. This step only needs to be performed once. +Connect the board to your PC via the **SE UART USB** port (on the Ensemble kit, +this is labeled **PRG USB**), then run: + +```bash +make update-system-package +``` + +**Note:** The board must be power-cycled after this step. + +### Deploy MicroPython + +To flash the firmware, run: + +```bash +make BOARD=ALIF_ENSEMBLE deploy +``` diff --git a/ports/alif/alif.mk b/ports/alif/alif.mk index bb07a3aa20..265418aa07 100644 --- a/ports/alif/alif.mk +++ b/ports/alif/alif.mk @@ -3,7 +3,6 @@ BOARD ?= ALIF_ENSEMBLE BOARD_DIR ?= boards/$(BOARD) -BUILD ?= build-$(BOARD)/$(MCU_CORE) ifeq ($(wildcard $(BOARD_DIR)/.),) $(error Invalid BOARD specified: $(BOARD_DIR)) diff --git a/ports/alif/boards/ALIF_ENSEMBLE/board.json b/ports/alif/boards/ALIF_ENSEMBLE/board.json new file mode 100644 index 0000000000..0c63494f7a --- /dev/null +++ b/ports/alif/boards/ALIF_ENSEMBLE/board.json @@ -0,0 +1,17 @@ +{ + "deploy": [ + "./deploy.md" + ], + "docs": "", + "features": [ + "Ethernet" + ], + "images": [ + "ensemble-devkit-gen-2.jpg" + ], + "mcu": "AE722F80F55D5XX", + "product": "Ensemble E7 DevKit", + "thumbnail": "", + "url": "https://alifsemi.com/support/kits/ensemble-devkit/", + "vendor": "Alif Semiconductor" +} diff --git a/ports/alif/boards/ALIF_ENSEMBLE/deploy.md b/ports/alif/boards/ALIF_ENSEMBLE/deploy.md new file mode 100644 index 0000000000..acbc85617e --- /dev/null +++ b/ports/alif/boards/ALIF_ENSEMBLE/deploy.md @@ -0,0 +1,37 @@ +### Alif Security Toolkit + +This board can be programmed via the SE UART interface using the Alif Security +Toolkit. MicroPython uses a custom version of the toolkit, which can be downloaded +from [here](https://github.com/micropython/alif-security-toolkit/) or cloned: + +```bash +git clone https://github.com/micropython/alif-security-toolkit/ +``` + +--- + +### Update the SE Firmware (Optional) + +If needed, update the SE firmware to match the version used by MicroPython. Ensure +you have the correct port, part number, and chip revision. + +```bash +python alif-security-toolkit/toolkit/updateSystemPackage.py --port /dev/ttyACM0 --cfg-part AE722F80F55D5LS --cfg-rev B4 +``` + +**Note:** The board must be power-cycled after this step. + +--- + +### Deploy MicroPython + +Download (or build) the firmware package, unzip it, then deploy it: + +```bash + +python alif-security-toolkit/toolkit/app-write-mram.py --port /dev/ttyACM0 --cfg-part AE722F80F55D5LS --cfg-rev B4 --pad --images file:build-ALIF_ENSEMBLE/application_package.ds +``` + +The MicroPython REPL is available on the second USB serial port, eg `/dev/ttyACM1`. + +--- diff --git a/ports/alif/irq.h b/ports/alif/irq.h index 08b8ef8086..02df524a49 100644 --- a/ports/alif/irq.h +++ b/ports/alif/irq.h @@ -48,6 +48,7 @@ #define IRQ_PRI_USB NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 7, 0) #define IRQ_PRI_HWSEM NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 8, 0) #define IRQ_PRI_GPU NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 10, 0) +#define IRQ_PRI_GPIO NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 50, 0) #define IRQ_PRI_RTC NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 100, 0) #define IRQ_PRI_CYW43 NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 126, 0) #define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_7, 127, 0) diff --git a/ports/alif/machine_pin.c b/ports/alif/machine_pin.c index 02c5e482ad..b8773f103f 100644 --- a/ports/alif/machine_pin.c +++ b/ports/alif/machine_pin.c @@ -30,8 +30,76 @@ #include "extmod/virtpin.h" #include "shared/runtime/mpirq.h" +#ifndef MACHINE_PIN_NUM_VECTORS +#define MACHINE_PIN_NUM_PORT_IO (8) +#define MACHINE_PIN_NUM_VECTORS (16 * MACHINE_PIN_NUM_PORT_IO) +#endif + +typedef struct _machine_pin_irq_obj_t { + mp_irq_obj_t base; + uint32_t flags; + uint32_t trigger; + IRQn_Type irq_num; + bool reserved; // for use by other drivers +} machine_pin_irq_obj_t; + +#define MACHINE_PIN_IRQ_INDEX(port, pin) \ + ((port) * MACHINE_PIN_NUM_PORT_IO + (pin)) + +#define MACHINE_PIN_IRQ_OBJECT(port, pin) \ + (MP_STATE_PORT(machine_pin_irq_obj[MACHINE_PIN_IRQ_INDEX((port), (pin))])) + +// Defines a single GPIO IRQ handler +#define DEFINE_GPIO_IRQ_HANDLER(pname, port, pin) \ + void pname##_IRQ##pin##Handler(void) { \ + machine_pin_irq_obj_t *irq = MACHINE_PIN_IRQ_OBJECT(port, pin); \ + machine_pin_obj_t *self = MP_OBJ_TO_PTR(irq->base.parent); \ + gpio_interrupt_eoi(self->gpio, pin); \ + irq->flags = irq->trigger; \ + mp_irq_handler(&irq->base); \ + } + +// Defines all 8 pin IRQ handlers for a port +#define DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(gpio, port) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 0) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 1) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 2) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 3) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 4) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 5) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 6) \ + DEFINE_GPIO_IRQ_HANDLER(gpio, port, 7) + +// Generate handlers for GPIO ports 0 to 14 + LPGPIO +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO0, 0) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO1, 1) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO2, 2) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO3, 3) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO4, 4) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO5, 5) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO6, 6) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO7, 7) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO8, 8) + +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 0) +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 1) +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 2) +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 3) +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 4) +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 5) +// DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 6) // Reserved for WiFi +DEFINE_GPIO_IRQ_HANDLER(GPIO9, 9, 7) + +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO10, 10) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO11, 11) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO12, 12) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO13, 13) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(GPIO14, 14) +DEFINE_GPIO_IRQ_HANDLERS_FOR_PORT(LPGPIO, 15) + extern const mp_obj_dict_t machine_pin_cpu_pins_locals_dict; extern const mp_obj_dict_t machine_pin_board_pins_locals_dict; +static const mp_irq_methods_t machine_pin_irq_methods; static const machine_pin_obj_t *machine_pin_find_named(const mp_obj_dict_t *named_pins, mp_obj_t name) { const mp_map_t *named_map = &named_pins->map; @@ -171,6 +239,7 @@ mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); machine_pin_obj_init_helper(self, n_args - 1, args + 1, &kw_args); } + return MP_OBJ_FROM_PTR(self); } @@ -225,6 +294,129 @@ static mp_obj_t machine_pin_toggle(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(machine_pin_toggle_obj, machine_pin_toggle); +static mp_uint_t machine_pin_irq_trigger(mp_obj_t self_in, mp_uint_t trigger) { + machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + machine_pin_irq_obj_t *irq = MACHINE_PIN_IRQ_OBJECT(self->port, self->pin); + + irq->flags = 0; + irq->trigger = trigger; + + // Disable IRQs. + gpio_disable_interrupt(self->gpio, self->pin); + gpio_mask_interrupt(self->gpio, self->pin); + + NVIC_ClearPendingIRQ(irq->irq_num); + NVIC_DisableIRQ(irq->irq_num); + + // Return if the trigger is disabled. + if (trigger == 0) { + return 0; + } + + // Clear and enable GPIO IRQ. + gpio_enable_interrupt(self->gpio, self->pin); + gpio_unmask_interrupt(self->gpio, self->pin); + + // Clear GPIO config. + self->gpio->GPIO_INT_BOTHEDGE &= ~(1 << self->pin); + self->gpio->GPIO_INT_POLARITY &= ~(1 << self->pin); + self->gpio->GPIO_INTTYPE_LEVEL &= ~(1 << self->pin); + + // Configure GPIO IRQ trigger + if (trigger == MP_HAL_PIN_TRIGGER_FALL) { + gpio_interrupt_set_edge_trigger(self->gpio, self->pin); + gpio_interrupt_set_polarity_low(self->gpio, self->pin); + } else if (trigger == MP_HAL_PIN_TRIGGER_RISE) { + gpio_interrupt_set_edge_trigger(self->gpio, self->pin); + gpio_interrupt_set_polarity_high(self->gpio, self->pin); + } else if (trigger == (MP_HAL_PIN_TRIGGER_FALL | MP_HAL_PIN_TRIGGER_RISE)) { + gpio_interrupt_set_both_edge_trigger(self->gpio, self->pin); + } else { + mp_raise_ValueError(MP_ERROR_TEXT("Invalid IRQ trigger")); + } + + // Clear GPIO IRQ (must be done after configuring trigger) + gpio_interrupt_eoi(self->gpio, self->pin); + + // Clear and enable NVIC GPIO IRQ. + NVIC_ClearPendingIRQ(irq->irq_num); + NVIC_SetPriority(irq->irq_num, IRQ_PRI_GPIO); + NVIC_EnableIRQ(irq->irq_num); + + return 0; +} + +static mp_uint_t machine_pin_irq_info(mp_obj_t self_in, mp_uint_t info_type) { + machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in); + machine_pin_irq_obj_t *irq = MACHINE_PIN_IRQ_OBJECT(self->port, self->pin); + + if (info_type == MP_IRQ_INFO_FLAGS) { + return irq->flags; + } else if (info_type == MP_IRQ_INFO_TRIGGERS) { + return irq->trigger; + } + return 0; +} + +static const mp_irq_methods_t machine_pin_irq_methods = { + .trigger = machine_pin_irq_trigger, + .info = machine_pin_irq_info, +}; + +// pin.irq(handler=None, trigger=IRQ_FALLING|IRQ_RISING, hard=False) +static mp_obj_t machine_pin_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_handler, ARG_trigger, ARG_hard }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_trigger, MP_ARG_INT, {.u_int = MP_HAL_PIN_TRIGGER_FALL | MP_HAL_PIN_TRIGGER_RISE} }, + { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} }, + }; + + machine_pin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + machine_pin_irq_obj_t *irq = MACHINE_PIN_IRQ_OBJECT(self->port, self->pin); + + // Allocate a new IRQ object if it doesn't exist. + if (irq == NULL) { + irq = m_new_obj(machine_pin_irq_obj_t); + uint32_t idx = MACHINE_PIN_IRQ_INDEX(self->port, self->pin); + + irq->base.base.type = &mp_irq_type; + irq->base.methods = (mp_irq_methods_t *)&machine_pin_irq_methods; + irq->base.parent = MP_OBJ_FROM_PTR(self); + irq->base.handler = mp_const_none; + irq->base.ishard = false; + irq->reserved = false; + irq->irq_num = (self->port < 15) ? (GPIO0_IRQ0_IRQn + idx) : (LPGPIO_IRQ0_IRQn + self->pin); + MP_STATE_PORT(machine_pin_irq_obj[idx]) = irq; + } + + if (n_args > 1 || kw_args->used != 0) { + if (irq->reserved) { + mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Pin IRQ is reserved")); + } + irq->base.handler = args[ARG_handler].u_obj; + irq->base.ishard = args[ARG_hard].u_bool; + machine_pin_irq_trigger(self, args[ARG_trigger].u_int); + } + + return MP_OBJ_FROM_PTR(irq); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(machine_pin_irq_obj, 1, machine_pin_irq); + +void machine_pin_irq_deinit(void) { + for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(machine_pin_irq_obj)); i++) { + machine_pin_irq_obj_t *irq = MP_STATE_PORT(machine_pin_irq_obj[i]); + if (irq != NULL) { + machine_pin_obj_t *self = MP_OBJ_TO_PTR(irq->base.parent); + machine_pin_irq_trigger(self, 0); + MP_STATE_PORT(machine_pin_irq_obj[i]) = NULL; + } + } +} + static MP_DEFINE_CONST_OBJ_TYPE( pin_cpu_pins_obj_type, MP_QSTR_cpu, @@ -248,6 +440,7 @@ static const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&machine_pin_low_obj) }, { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&machine_pin_high_obj) }, { MP_ROM_QSTR(MP_QSTR_toggle), MP_ROM_PTR(&machine_pin_toggle_obj) }, + { MP_ROM_QSTR(MP_QSTR_irq), MP_ROM_PTR(&machine_pin_irq_obj) }, // class attributes { MP_ROM_QSTR(MP_QSTR_board), MP_ROM_PTR(&pin_board_pins_obj_type) }, @@ -259,6 +452,8 @@ static const mp_rom_map_elem_t machine_pin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_OPEN_DRAIN), MP_ROM_INT(MP_HAL_PIN_MODE_OPEN_DRAIN) }, { MP_ROM_QSTR(MP_QSTR_PULL_UP), MP_ROM_INT(MP_HAL_PIN_PULL_UP) }, { MP_ROM_QSTR(MP_QSTR_PULL_DOWN), MP_ROM_INT(MP_HAL_PIN_PULL_DOWN) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_FALLING), MP_ROM_INT(MP_HAL_PIN_TRIGGER_FALL) }, + { MP_ROM_QSTR(MP_QSTR_IRQ_RISING), MP_ROM_INT(MP_HAL_PIN_TRIGGER_RISE) }, }; static MP_DEFINE_CONST_DICT(machine_pin_locals_dict, machine_pin_locals_dict_table); @@ -296,3 +491,5 @@ MP_DEFINE_CONST_OBJ_TYPE( mp_hal_pin_obj_t mp_hal_get_pin_obj(mp_obj_t obj) { return machine_pin_find(obj); } + +MP_REGISTER_ROOT_POINTER(void *machine_pin_irq_obj[MACHINE_PIN_NUM_VECTORS]); diff --git a/ports/alif/machine_spi.c b/ports/alif/machine_spi.c index abb60bc4e8..b2c14745cf 100644 --- a/ports/alif/machine_spi.c +++ b/ports/alif/machine_spi.c @@ -39,6 +39,7 @@ typedef struct _machine_spi_obj_t { uint8_t id; SPI_Type *inst; bool is_lp; + uint32_t bits; } machine_spi_obj_t; static machine_spi_obj_t machine_spi_obj[] = { @@ -246,6 +247,9 @@ mp_obj_t machine_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n // Get static peripheral object. machine_spi_obj_t *self = &machine_spi_obj[spi_id]; + // Set args + self->bits = args[ARG_bits].u_int; + // here we would check the sck/mosi/miso pins and configure them, but it's not implemented if (args[ARG_sck].u_obj != MP_OBJ_NULL || args[ARG_mosi].u_obj != MP_OBJ_NULL || @@ -294,22 +298,50 @@ static void machine_spi_deinit(mp_obj_base_t *self_in) { } } +static void machine_spi_poll_flag(SPI_Type *spi, uint32_t flag, uint32_t timeout) { + mp_uint_t tick_start = mp_hal_ticks_ms(); + while (!(spi->SPI_SR & flag)) { + if (mp_hal_ticks_ms() - tick_start >= timeout) { + mp_raise_OSError(MP_ETIMEDOUT); + } + mp_event_handle_nowait(); + } +} + static void machine_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { machine_spi_obj_t *self = (machine_spi_obj_t *)self_in; - spi_transfer_t spi_xfer = { - .tx_buff = src, - .tx_total_cnt = len, - .rx_buff = dest, - .rx_total_cnt = len, - .tx_default_val = 0xFF, - .tx_default_enable = true, - .mode = SPI_TMOD_TX_AND_RX, - }; - // TODO redo transfer_blocking to timeout and poll events. - if (!self->is_lp) { - spi_transfer_blocking(self->inst, &spi_xfer); - } else { - lpspi_transfer_blocking(self->inst, &spi_xfer); + volatile uint32_t *dr = self->inst->SPI_DR; + + spi_set_tmod(self->inst, SPI_TMOD_TX_AND_RX); + + for (size_t i = 0; i < len; i++) { + // Wait for space in the TX FIFO + machine_spi_poll_flag(self->inst, SPI_SR_TFNF, 100); + + // Send data + if (src == NULL) { + *dr = 0xFFFFFFFFU; + } else if (self->bits > 16) { + *dr = ((uint32_t *)src)[i]; + } else if (self->bits > 8) { + *dr = ((uint16_t *)src)[i]; + } else { + *dr = ((uint8_t *)src)[i]; + } + + // Wait for data in the RX FIFO + machine_spi_poll_flag(self->inst, SPI_SR_RFNE, 100); + + // Recv data + if (dest == NULL) { + (void)*dr; + } else if (self->bits > 16) { + ((uint32_t *)dest)[i] = *dr; + } else if (self->bits > 8) { + ((uint16_t *)dest)[i] = *dr; + } else { + ((uint8_t *)dest)[i] = *dr; + } } } diff --git a/ports/alif/main.c b/ports/alif/main.c index 4783611357..ab5e85d5b9 100644 --- a/ports/alif/main.c +++ b/ports/alif/main.c @@ -55,6 +55,7 @@ extern uint8_t __StackTop, __StackLimit; extern uint8_t __GcHeapStart, __GcHeapEnd; +extern void machine_pin_irq_deinit(void); MP_NORETURN void panic(const char *msg) { mp_hal_stdout_tx_strn("\nFATAL ERROR:\n", 14); @@ -164,6 +165,7 @@ int main(void) { mp_bluetooth_deinit(); #endif soft_timer_deinit(); + machine_pin_irq_deinit(); gc_sweep_all(); mp_deinit(); } diff --git a/ports/alif/mphalport.h b/ports/alif/mphalport.h index 4f81439b54..f03dc7c1c1 100644 --- a/ports/alif/mphalport.h +++ b/ports/alif/mphalport.h @@ -90,6 +90,9 @@ extern ringbuf_t stdin_ringbuf; #define MP_HAL_PIN_SPEED_LOW (0) #define MP_HAL_PIN_SPEED_HIGH (PADCTRL_SLEW_RATE_FAST) +#define MP_HAL_PIN_TRIGGER_FALL (1) +#define MP_HAL_PIN_TRIGGER_RISE (2) + #define mp_hal_pin_obj_t const machine_pin_obj_t * #define MP_HAL_PIN_ALT(function, unit) (MP_HAL_PIN_ALT_MAKE((MP_HAL_PIN_ALT_##function), (unit))) diff --git a/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/board.json b/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/board.json new file mode 100644 index 0000000000..d2ada7cccd --- /dev/null +++ b/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/board.json @@ -0,0 +1,23 @@ +{ + "deploy": [ + "../deploy_nativeusb.md" + ], + "deploy_options": { + "flash_offset": "0" + }, + "docs": "", + "features": [ + "BLE", + "External Flash", + "RGB LED", + "WiFi" + ], + "images": [ + "GAR-PYBSTICK26-C3-mUSB-00.JPG" + ], + "mcu": "esp32c3", + "product": "PYBSTICK26_ESP32C3", + "thumbnail": "", + "url": "https://shop.mchobby.be/fr/pybstick/2505-pybstick26-esp32-c3-micropython-et-arduino-3232100025059.html", + "vendor": "McHobby" +} diff --git a/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/mpconfigboard.cmake b/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/mpconfigboard.cmake new file mode 100644 index 0000000000..81cfff1d77 --- /dev/null +++ b/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/mpconfigboard.cmake @@ -0,0 +1,7 @@ +set(IDF_TARGET esp32c3) + +set(SDKCONFIG_DEFAULTS + boards/sdkconfig.base + boards/sdkconfig.ble + boards/GARATRONIC_PYBSTICK26_ESP32C3/sdkconfig.board +) diff --git a/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/mpconfigboard.h b/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/mpconfigboard.h new file mode 100644 index 0000000000..c9796d1f65 --- /dev/null +++ b/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/mpconfigboard.h @@ -0,0 +1,10 @@ +#define MICROPY_HW_BOARD_NAME "PYBSTICK26_ESP32C3" +#define MICROPY_HW_MCU_NAME "ESP32C3" +#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "pybstick26_esp32c3" + +#define MICROPY_HW_I2C0_SCL (1) +#define MICROPY_HW_I2C0_SDA (0) + +#define MICROPY_HW_SPI1_MOSI (7) +#define MICROPY_HW_SPI1_MISO (2) +#define MICROPY_HW_SPI1_SCK (6) diff --git a/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/pins.csv b/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/pins.csv new file mode 100644 index 0000000000..d786654903 --- /dev/null +++ b/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/pins.csv @@ -0,0 +1,13 @@ +GP0,GPIO0 +GP1,GPIO1 +GP2,GPIO2 +GP3,GPIO3 +GP4,GPIO4 +GP5,GPIO5 +GP6,GPIO6 +GP7,GPIO7 +GP8,GPIO8 +GP9,GPIO9 +GP10,GPIO10 +GP20,GPIO20 +GP21,GPIO21 diff --git a/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/sdkconfig.board b/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/sdkconfig.board new file mode 100644 index 0000000000..70e5f1f0d1 --- /dev/null +++ b/ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/sdkconfig.board @@ -0,0 +1,4 @@ +CONFIG_ESP32C3_REV_MIN_3=y + +# Workaround for https://github.com/espressif/esp-idf/issues/14456 +CONFIG_ESP_SYSTEM_HW_STACK_GUARD=n diff --git a/ports/esp32/panichandler.c b/ports/esp32/panichandler.c index e6ff98ded2..5211286f84 100644 --- a/ports/esp32/panichandler.c +++ b/ports/esp32/panichandler.c @@ -42,11 +42,20 @@ #endif void __real_esp_panic_handler(void *); -void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms); void panic_print_str(const char *str); +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 2) +void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms); +#else +void esp_panic_handler_feed_wdts(void); +#endif + void MICROPY_WRAP_PANICHANDLER_FUN(__wrap_esp_panic_handler)(void *info) { + #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 4, 2) esp_panic_handler_reconfigure_wdts(1000); + #else + esp_panic_handler_feed_wdts(); + #endif const static char *msg = MICROPY_WRAP_PANICHANDLER_STR( "\r\n" diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 8ac9a8af03..eabbd64a3b 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -417,6 +417,12 @@ HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\ ) endif +ifeq ($(MCU_SERIES),$(filter $(MCU_SERIES),h7)) +HAL_SRC_C += $(addprefix $(STM32LIB_HAL_BASE)/Src/stm32$(MCU_SERIES)xx_,\ + hal_uart_ex.c \ + ) +endif + USBDEV_SRC_C += $(addprefix $(USBDEV_DIR)/,\ core/src/usbd_core.c \ core/src/usbd_ctlreq.c \ diff --git a/ports/stm32/boards/ARDUINO_GIGA/mpconfigboard.h b/ports/stm32/boards/ARDUINO_GIGA/mpconfigboard.h index cef45d730c..44f6ce66bc 100644 --- a/ports/stm32/boards/ARDUINO_GIGA/mpconfigboard.h +++ b/ports/stm32/boards/ARDUINO_GIGA/mpconfigboard.h @@ -31,6 +31,7 @@ typedef unsigned int mp_uint_t; // must be pointer size #define MICROPY_HW_ENABLE_MMCARD (0) #define MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET (0) #define MICROPY_HW_TIM_IS_RESERVED(id) (id == 1) +#define MICROPY_GC_SPLIT_HEAP (1) // ROMFS config #define MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI (1) diff --git a/ports/stm32/boards/ARDUINO_GIGA/stm32h747.ld b/ports/stm32/boards/ARDUINO_GIGA/stm32h747.ld index e7bb950dbe..dceb1a7489 100644 --- a/ports/stm32/boards/ARDUINO_GIGA/stm32h747.ld +++ b/ports/stm32/boards/ARDUINO_GIGA/stm32h747.ld @@ -12,6 +12,7 @@ MEMORY SRAM2 (xrw) : ORIGIN = 0x30020000, LENGTH = 128K /* SRAM2 D2 */ SRAM3 (xrw) : ORIGIN = 0x30040000, LENGTH = 32K /* SRAM3 D2 */ SRAM4 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K /* SRAM4 D3 */ + SDRAM (xrw) : ORIGIN = 0x60000000, LENGTH = 8M /* SDRAM */ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K /* Total available flash */ FLASH_BL (rx) : ORIGIN = 0x08000000, LENGTH = 128K /* Arduino bootloader */ FLASH_FS (r) : ORIGIN = 0x08020000, LENGTH = 128K /* filesystem */ @@ -53,3 +54,27 @@ _openamp_shm_region_start = ORIGIN(SRAM4); _openamp_shm_region_end = ORIGIN(SRAM4) + LENGTH(SRAM4); INCLUDE common_blifs.ld + +SECTIONS +{ + /* GC blocks addresses and sizes */ + .gc.blocks.table (READONLY) : { + . = ALIGN(4); + _gc_blocks_table_start = .; + + LONG (ORIGIN(SRAM1)); + LONG (128K); + + LONG (ORIGIN(SDRAM) + 0M); + LONG (2M); + + LONG (ORIGIN(SDRAM) + 2M); + LONG (2M); + + LONG (ORIGIN(SDRAM) + 4M); + LONG (4M); + + _gc_blocks_table_end = .; + . = ALIGN(4); + } > FLASH_TEXT +} diff --git a/ports/stm32/boards/ARDUINO_PORTENTA_H7/mpconfigboard.h b/ports/stm32/boards/ARDUINO_PORTENTA_H7/mpconfigboard.h index 90a1469056..a9ecf38fbf 100644 --- a/ports/stm32/boards/ARDUINO_PORTENTA_H7/mpconfigboard.h +++ b/ports/stm32/boards/ARDUINO_PORTENTA_H7/mpconfigboard.h @@ -30,7 +30,6 @@ typedef unsigned int mp_uint_t; // must be pointer size #define MICROPY_HW_ENABLE_SDCARD (1) #define MICROPY_HW_ENABLE_MMCARD (0) #define MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET (0) -#define MICROPY_HW_TIM_IS_RESERVED(id) (id == 1) // ROMFS config #define MICROPY_HW_ROMFS_ENABLE_EXTERNAL_QSPI (1) diff --git a/ports/stm32/boards/stm32h7xx_hal_conf_base.h b/ports/stm32/boards/stm32h7xx_hal_conf_base.h index 670dee383f..1953ba020b 100644 --- a/ports/stm32/boards/stm32h7xx_hal_conf_base.h +++ b/ports/stm32/boards/stm32h7xx_hal_conf_base.h @@ -90,6 +90,7 @@ #include "stm32h7xx_hal_spi.h" #include "stm32h7xx_hal_tim.h" #include "stm32h7xx_hal_uart.h" +#include "stm32h7xx_hal_uart_ex.h" #include "stm32h7xx_hal_usart.h" #include "stm32h7xx_hal_wwdg.h" #include "stm32h7xx_ll_adc.h" diff --git a/ports/stm32/main.c b/ports/stm32/main.c index e8395013b9..5e114f562f 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -521,6 +521,23 @@ soft_reset: // GC init gc_init(MICROPY_HEAP_START, MICROPY_HEAP_END); + // Add additional GC blocks (if enabled). + #if MICROPY_GC_SPLIT_HEAP + typedef struct { + uint8_t *addr; + uint32_t size; + } gc_blocks_table_t; + + extern const gc_blocks_table_t _gc_blocks_table_start; + extern const gc_blocks_table_t _gc_blocks_table_end; + + for (gc_blocks_table_t const *block = &_gc_blocks_table_start; block < &_gc_blocks_table_end; block++) { + if (block->size) { + gc_add(block->addr, block->addr + block->size); + } + } + #endif + #if MICROPY_ENABLE_PYSTACK static mp_obj_t pystack[384]; mp_pystack_init(pystack, &pystack[384]); diff --git a/ports/stm32/uart.c b/ports/stm32/uart.c index 91db91395e..55fa622142 100644 --- a/ports/stm32/uart.c +++ b/ports/stm32/uart.c @@ -653,7 +653,7 @@ bool uart_init(machine_uart_obj_t *uart_obj, huart.Init.HwFlowCtl = flow; huart.Init.OverSampling = UART_OVERSAMPLING_16; - #if defined(STM32G4) // H7 and WB also have fifo.. + #if defined(STM32G4) || defined(STM32H7) // WB also has a fifo.. huart.FifoMode = UART_FIFOMODE_ENABLE; #endif @@ -701,6 +701,12 @@ bool uart_init(machine_uart_obj_t *uart_obj, uart_obj->char_width = CHAR_WIDTH_8BIT; } + #if defined(STM32H7) + HAL_UARTEx_SetTxFifoThreshold(&huart, UART_TXFIFO_THRESHOLD_1_8); + HAL_UARTEx_SetRxFifoThreshold(&huart, UART_RXFIFO_THRESHOLD_1_8); + HAL_UARTEx_EnableFifoMode(&huart); + #endif + uart_obj->mp_irq_trigger = 0; uart_obj->mp_irq_obj = NULL; @@ -1141,6 +1147,9 @@ size_t uart_tx_data(machine_uart_obj_t *self, const void *src_in, size_t num_cha // timeout_char by FIFO size + 1. // STM32G4 has 8 words FIFO. timeout = (8 + 1) * self->timeout_char; + #elif defined(STM32H7) + // STM32H7 has 16 words FIFO. + timeout = (16 + 1) * self->timeout_char; #else // The timeout specified here is for waiting for the TX data register to // become empty (ie between chars), as well as for the final char to be diff --git a/ports/unix/README.md b/ports/unix/README.md index b7aa6e3fef..656d4303d3 100644 --- a/ports/unix/README.md +++ b/ports/unix/README.md @@ -155,3 +155,21 @@ 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. + +### Sanitizers + +Sanitizers are extra runtime checks supported by gcc and clang. The CI process +supports building with the "undefined behavior" (UBSan) or "address" (ASan) +sanitizers. The script `tools/ci.sh` is the source of truth about how to build +and run in these modes. + +Several classes of checks are disabled via compiler flags: + +* In the undefined behavior sanitizer, checks based on the presence of the + `non_null` attribute are disabled because the code makes technically incorrect + calls like `memset(NULL, 0, 0)`. A future C standard is likely to permit such + calls. +* In the address sanitizer, `detect_stack_use_after_return` is disabled. This + check is intended to make sure locals in a "returned from" stack frame are not + used. However, this mode interferes with various assumptions that + MicroPython's stack checking, NLR, and GC rely on. diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index b041141f0f..33e4208d92 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -582,12 +582,24 @@ static mp_obj_t extra_coverage(void) { fun_bc.context = &context; fun_bc.child_table = NULL; fun_bc.bytecode = (const byte *)"\x01"; // just needed for n_state + #if MICROPY_PY_SYS_SETTRACE + struct _mp_raw_code_t rc = {}; + fun_bc.rc = &rc; + #endif mp_code_state_t *code_state = m_new_obj_var(mp_code_state_t, state, mp_obj_t, 1); code_state->fun_bc = &fun_bc; code_state->ip = (const byte *)"\x00"; // just needed for an invalid opcode code_state->sp = &code_state->state[0]; code_state->exc_sp_idx = 0; code_state->old_globals = NULL; + #if MICROPY_STACKLESS + code_state->prev = NULL; + #endif + #if MICROPY_PY_SYS_SETTRACE + code_state->prev_state = NULL; + code_state->frame = NULL; + #endif + mp_vm_return_kind_t ret = mp_execute_bytecode(code_state, MP_OBJ_NULL); mp_printf(&mp_plat_print, "%d %d\n", ret, mp_obj_get_type(code_state->state[0]) == &mp_type_NotImplementedError); } diff --git a/ports/unix/variants/coverage/mpconfigvariant.h b/ports/unix/variants/coverage/mpconfigvariant.h index cfefeb4672..2f5d9683b3 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.h +++ b/ports/unix/variants/coverage/mpconfigvariant.h @@ -39,6 +39,7 @@ // Enable additional features. #define MICROPY_DEBUG_PARSE_RULE_NAME (1) +#define MICROPY_PY_SYS_SETTRACE (1) #define MICROPY_TRACKED_ALLOC (1) #define MICROPY_WARNINGS_CATEGORY (1) #undef MICROPY_VFS_ROM_IOCTL diff --git a/ports/webassembly/objpyproxy.js b/ports/webassembly/objpyproxy.js index 3b94f8aadc..0eafd0dec5 100644 --- a/ports/webassembly/objpyproxy.js +++ b/ports/webassembly/objpyproxy.js @@ -148,6 +148,12 @@ const py_proxy_handler = { }; }, has(target, prop) { + // avoid throwing on `Symbol() in proxy` checks + if (typeof prop !== "string") { + // returns true only on iterator because other + // symbols are not considered in the `get` trap + return prop === Symbol.iterator; + } return Module.ccall( "proxy_c_to_js_has_attr", "number", diff --git a/py/asmarm.c b/py/asmarm.c index be50a991b7..15bc73b61e 100644 --- a/py/asmarm.c +++ b/py/asmarm.c @@ -38,8 +38,6 @@ #define REG_TEMP ASM_ARM_REG_R8 -#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000) - // Insert word into instruction flow static void emit(asm_arm_t *as, uint op) { uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4); @@ -347,11 +345,6 @@ void asm_arm_ldr_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offse } } -void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn) { - // ldrh rd, [rn] - emit_al(as, 0x1d000b0 | (rn << 16) | (rd << 12)); -} - void asm_arm_ldrh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { // ldrh doesn't support scaled register index emit_al(as, 0x1a00080 | (REG_TEMP << 12) | rn); // mov temp, rn, lsl #1 @@ -370,16 +363,23 @@ void asm_arm_ldrh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offs } } -void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn) { - // ldrb rd, [rn] - emit_al(as, 0x5d00000 | (rn << 16) | (rd << 12)); -} - void asm_arm_ldrb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { // ldrb rd, [rm, rn] emit_al(as, 0x7d00000 | (rm << 16) | (rd << 12) | rn); } +void asm_arm_ldrb_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { + if (byte_offset < 0x1000) { + // ldrb rd, [rn, #off] + emit_al(as, 0x5d00000 | (rn << 16) | (rd << 12) | byte_offset); + } else { + // mov temp, #off + // ldrb rd, [rn, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x7d00000 | (rn << 16) | (rd << 12) | REG_TEMP); + } +} + void asm_arm_ldr_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { // ldr rd, [rm, rn, lsl #2] emit_al(as, 0x7900100 | (rm << 16) | (rd << 12) | rn); @@ -397,14 +397,28 @@ void asm_arm_str_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offse } } -void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm) { - // strh rd, [rm] - emit_al(as, 0x1c000b0 | (rm << 16) | (rd << 12)); +void asm_arm_strh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { + if (byte_offset < 0x100) { + // strh rd, [rn, #off] + emit_al(as, 0x1c000b0 | (rn << 16) | (rd << 12) | ((byte_offset & 0xf0) << 4) | (byte_offset & 0xf)); + } else { + // mov temp, #off + // strh rd, [rn, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x18000b0 | (rn << 16) | (rd << 12) | REG_TEMP); + } } -void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm) { - // strb rd, [rm] - emit_al(as, 0x5c00000 | (rm << 16) | (rd << 12)); +void asm_arm_strb_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset) { + if (byte_offset < 0x1000) { + // strb rd, [rm, #off] + emit_al(as, 0x5c00000 | (rm << 16) | (rd << 12) | byte_offset); + } else { + // mov temp, #off + // strb rd, [rm, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x7c00000 | (rm << 16) | (rd << 12) | REG_TEMP); + } } void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { @@ -430,7 +444,7 @@ void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label) { rel -= 8; // account for instruction prefetch, PC is 8 bytes ahead of this instruction rel >>= 2; // in ARM mode the branch target is 32-bit aligned, so the 2 LSB are omitted - if (SIGNED_FIT24(rel)) { + if (MP_FIT_SIGNED(24, rel)) { emit(as, cond | 0xa000000 | (rel & 0xffffff)); } else { printf("asm_arm_bcc: branch does not fit in 24 bits\n"); diff --git a/py/asmarm.h b/py/asmarm.h index 07ed425c98..405457d440 100644 --- a/py/asmarm.h +++ b/py/asmarm.h @@ -110,12 +110,11 @@ void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs); // memory void asm_arm_ldr_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset); -void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn); void asm_arm_ldrh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset); -void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn); +void asm_arm_ldrb_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset); void asm_arm_str_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset); -void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm); -void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm); +void asm_arm_strh_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset); +void asm_arm_strb_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset); // load from array void asm_arm_ldr_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); @@ -165,12 +164,12 @@ void asm_arm_bx_reg(asm_arm_t *as, uint reg_src); // Holds a pointer to mp_fun_table #define REG_FUN_TABLE ASM_ARM_REG_FUN_TABLE -#define ASM_T asm_arm_t -#define ASM_END_PASS asm_arm_end_pass -#define ASM_ENTRY asm_arm_entry -#define ASM_EXIT asm_arm_exit +#define ASM_T asm_arm_t +#define ASM_END_PASS asm_arm_end_pass +#define ASM_ENTRY(as, num_locals, name) asm_arm_entry((as), (num_locals)) +#define ASM_EXIT asm_arm_exit -#define ASM_JUMP asm_arm_b_label +#define ASM_JUMP asm_arm_b_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ do { \ asm_arm_cmp_reg_i8(as, reg, 0); \ @@ -209,16 +208,19 @@ void asm_arm_bx_reg(asm_arm_t *as, uint reg_src); #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_arm_mul_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_arm_ldrb_reg_reg((as), (reg_dest), (reg_base)) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_arm_ldrh_reg_reg((as), (reg_dest), (reg_base)) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_arm_ldrh_reg_reg_offset((as), (reg_dest), (reg_base), 2 * (uint16_offset)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg_offset((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_arm_ldrb_reg_reg_offset((as), (reg_dest), (reg_base), (byte_offset)) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, halfword_offset) asm_arm_ldrh_reg_reg_offset((as), (reg_dest), (reg_base), 2 * (halfword_offset)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) #define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_arm_ldr_reg_reg_offset((as), (reg_dest), (reg_base), 4 * (word_offset)) #define ASM_STORE_REG_REG_OFFSET(as, reg_value, reg_base, word_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_value), (reg_base), (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_value, reg_base) asm_arm_strb_reg_reg((as), (reg_value), (reg_base)) -#define ASM_STORE16_REG_REG(as, reg_value, reg_base) asm_arm_strh_reg_reg((as), (reg_value), (reg_base)) -#define ASM_STORE32_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg_offset((as), (reg_value), (reg_base), 0) +#define ASM_STORE8_REG_REG(as, reg_value, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_value), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_value, reg_base, byte_offset) asm_arm_strb_reg_reg_offset((as), (reg_value), (reg_base), (byte_offset)) +#define ASM_STORE16_REG_REG(as, reg_value, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_value), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_value, reg_base, halfword_offset) asm_arm_strh_reg_reg_offset((as), (reg_value), (reg_base), 2 * (halfword_offset)) +#define ASM_STORE32_REG_REG(as, reg_value, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_value), (reg_base), 0) #define ASM_STORE32_REG_REG_OFFSET(as, reg_value, reg_base, word_offset) asm_arm_str_reg_reg_offset((as), (reg_value), (reg_base), 4 * (word_offset)) #define ASM_LOAD8_REG_REG_REG(as, reg_dest, reg_base, reg_index) asm_arm_ldrb_reg_reg_reg((as), (reg_dest), (reg_base), (reg_index)) diff --git a/py/asmrv32.c b/py/asmrv32.c index c24d05a138..158b552191 100644 --- a/py/asmrv32.c +++ b/py/asmrv32.c @@ -450,18 +450,24 @@ void asm_rv32_emit_mov_reg_local_addr(asm_rv32_t *state, mp_uint_t rd, mp_uint_t 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); +static const uint8_t RV32_LOAD_OPCODE_TABLE[3] = { + 0x04, 0x05, 0x02 +}; - if (scaled_offset >= 0 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && FIT_UNSIGNED(scaled_offset, 6)) { +void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, int32_t offset, mp_uint_t operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); + + int32_t scaled_offset = offset << operation_size; + + if (scaled_offset >= 0 && operation_size == 2 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && MP_FIT_UNSIGNED(6, scaled_offset)) { // c.lw rd', offset(rs') asm_rv32_opcode_clw(state, RV32_MAP_IN_C_REGISTER_WINDOW(rd), RV32_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); + if (MP_FIT_SIGNED(12, scaled_offset)) { + // lbu|lhu|lw rd, offset(rs) + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x03, RV32_LOAD_OPCODE_TABLE[operation_size], rd, rs, scaled_offset)); return; } @@ -469,12 +475,12 @@ void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_ 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) + // lui rd, HI(offset) ; Or c.lui if possible + // c.add rd, rs + // lbu|lhu|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); + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x03, RV32_LOAD_OPCODE_TABLE[operation_size], rd, rd, lower)); } void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label) { @@ -497,12 +503,20 @@ void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label) { 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; +void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, int32_t offset, mp_uint_t operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); + + int32_t scaled_offset = offset << operation_size; - if (FIT_SIGNED(scaled_offset, 12)) { - // sw rd, offset(rs) - asm_rv32_opcode_sw(state, rd, rs, scaled_offset); + if (scaled_offset >= 0 && operation_size == 2 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && MP_FIT_UNSIGNED(6, scaled_offset)) { + // c.sw rd', offset(rs') + asm_rv32_opcode_csw(state, RV32_MAP_IN_C_REGISTER_WINDOW(rd), RV32_MAP_IN_C_REGISTER_WINDOW(rs), scaled_offset); + return; + } + + if (MP_FIT_SIGNED(12, scaled_offset)) { + // sb|sh|sw rd, offset(rs) + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_S(0x23, operation_size, rs, rd, scaled_offset)); return; } @@ -510,12 +524,12 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint 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) + // lui temporary, HI(offset) ; Or c.lui if possible + // c.add temporary, rs + // sb|sh|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); + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_S(0x23, operation_size, REG_TEMP2, rd, lower)); } void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t label) { @@ -530,27 +544,6 @@ void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t labe 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 diff --git a/py/asmrv32.h b/py/asmrv32.h index 4f986d7bbd..dac9c028b0 100644 --- a/py/asmrv32.h +++ b/py/asmrv32.h @@ -709,17 +709,16 @@ 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_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, int32_t offset, mp_uint_t operation_size); 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_addr(asm_rv32_t *state, mp_uint_t rd, mp_uint_t local); 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_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t label); 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); +void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_uint_t base, int32_t offset, mp_uint_t operation_size); #define ASM_T asm_rv32_t -#define ASM_ENTRY(state, labels) asm_rv32_entry(state, labels) +#define ASM_ENTRY(state, labels, name) asm_rv32_entry(state, labels) #define ASM_EXIT(state) asm_rv32_exit(state) #define ASM_END_PASS(state) asm_rv32_end_pass(state) @@ -733,11 +732,12 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_ #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_LOAD_REG_REG_OFFSET(state, rd, rs, offset) ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, offset) -#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_LOAD8_REG_REG(state, rd, rs) ASM_LOAD8_REG_REG_OFFSET(state, rd, rs, 0) +#define ASM_LOAD16_REG_REG(state, rd, rs) ASM_LOAD16_REG_REG_OFFSET(state, rd, rs, 0) #define ASM_LOAD32_REG_REG(state, rd, rs) ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, 0) -#define ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset) -#define ASM_LOAD8_REG_REG(state, rd, rs) asm_rv32_opcode_lbu(state, rd, rs, 0) +#define ASM_LOAD8_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset, 0) +#define ASM_LOAD16_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset, 1) +#define ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset, 2) #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) @@ -751,13 +751,20 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_ #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_STORE_REG_REG_OFFSET(state, rd, rs, offset) ASM_STORE32_REG_REG_OFFSET(state, rd, rs, offset) -#define ASM_STORE16_REG_REG(state, rs1, rs2) asm_rv32_opcode_sh(state, rs1, rs2, 0) +#define ASM_STORE8_REG_REG(state, rs1, rs2) ASM_STORE8_REG_REG_OFFSET(state, rs1, rs2, 0) +#define ASM_STORE16_REG_REG(state, rs1, rs2) ASM_STORE16_REG_REG_OFFSET(state, rs1, rs2, 0) #define ASM_STORE32_REG_REG(state, rs1, rs2) ASM_STORE32_REG_REG_OFFSET(state, rs1, rs2, 0) -#define ASM_STORE32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset) -#define ASM_STORE8_REG_REG(state, rs1, rs2) asm_rv32_opcode_sb(state, rs1, rs2, 0) +#define ASM_STORE8_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 0) +#define ASM_STORE16_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 1) +#define ASM_STORE32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 2) #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) #define ASM_CLR_REG(state, rd) +#define ASM_LOAD8_REG_REG_REG(state, rd, rs1, rs2) \ + do { \ + asm_rv32_opcode_cadd(state, rs1, rs2); \ + asm_rv32_opcode_lbu(state, rd, rs1, 0); \ + } while (0) #define ASM_LOAD16_REG_REG_REG(state, rd, rs1, rs2) \ do { \ asm_rv32_opcode_slli(state, rs2, rs2, 1); \ @@ -770,6 +777,11 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_ asm_rv32_opcode_cadd(state, rs1, rs2); \ asm_rv32_opcode_lw(state, rd, rs1, 0); \ } while (0) +#define ASM_STORE8_REG_REG_REG(state, rd, rs1, rs2) \ + do { \ + asm_rv32_opcode_cadd(state, rs1, rs2); \ + asm_rv32_opcode_sb(state, rd, rs1, 0); \ + } while (0) #define ASM_STORE16_REG_REG_REG(state, rd, rs1, rs2) \ do { \ asm_rv32_opcode_slli(state, rs2, rs2, 1); \ diff --git a/py/asmthumb.c b/py/asmthumb.c index fda0f52705..18c3db9e4e 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -37,10 +37,8 @@ #include "py/asmthumb.h" #include "py/misc.h" -#define UNSIGNED_FIT5(x) ((uint32_t)(x) < 32) #define UNSIGNED_FIT7(x) ((uint32_t)(x) < 128) #define UNSIGNED_FIT8(x) (((x) & 0xffffff00) == 0) -#define UNSIGNED_FIT12(x) (((x) & 0xfffff000) == 0) #define UNSIGNED_FIT16(x) (((x) & 0xffff0000) == 0) #define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80) #define SIGNED_FIT9(x) (((x) & 0xffffff00) == 0) || (((x) & 0xffffff00) == 0xffffff00) @@ -454,7 +452,7 @@ static void asm_thumb_add_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint re } } -#define OP_LDR_STR_W_HI(shift, reg) ((0xf880 | (shift) << 5) | (reg)) +#define OP_LDR_STR_W_HI(operation_size, reg) ((0xf880 | (operation_size) << 5) | (reg)) #define OP_LDR_STR_W_LO(reg, imm12) (((reg) << 12) | (imm12)) #define OP_LDR 0x01 @@ -467,31 +465,35 @@ static const uint8_t OP_LDR_STR_TABLE[3] = { 0x0E, 0x10, 0x0C }; -void asm_thumb_load_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint reg_base, uint offset, uint shift) { - if (UNSIGNED_FIT5(offset) && (reg_dest < ASM_THUMB_REG_R8) && (reg_base < ASM_THUMB_REG_R8)) { +void asm_thumb_load_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint reg_base, uint offset, uint operation_size) { + assert(operation_size <= 2 && "Operation size out of range."); + + if (MP_FIT_UNSIGNED(5, offset) && (reg_dest < ASM_THUMB_REG_R8) && (reg_base < ASM_THUMB_REG_R8)) { // Can use T1 encoding - asm_thumb_op16(as, ((OP_LDR_STR_TABLE[shift] | OP_LDR) << 11) | (offset << 6) | (reg_base << 3) | reg_dest); - } else if (asm_thumb_allow_armv7m(as) && UNSIGNED_FIT12(offset << shift)) { + asm_thumb_op16(as, ((OP_LDR_STR_TABLE[operation_size] | OP_LDR) << 11) | (offset << 6) | (reg_base << 3) | reg_dest); + } else if (asm_thumb_allow_armv7m(as) && MP_FIT_UNSIGNED(12, offset << operation_size)) { // Can use T3 encoding - asm_thumb_op32(as, (OP_LDR_STR_W_HI(shift, reg_base) | OP_LDR_W), OP_LDR_STR_W_LO(reg_dest, (offset << shift))); + asm_thumb_op32(as, (OP_LDR_STR_W_HI(operation_size, reg_base) | OP_LDR_W), OP_LDR_STR_W_LO(reg_dest, (offset << operation_size))); } else { // Must use the generic sequence - asm_thumb_add_reg_reg_offset(as, reg_dest, reg_base, offset - 31, shift); - asm_thumb_op16(as, ((OP_LDR_STR_TABLE[shift] | OP_LDR) << 11) | (31 << 6) | (reg_dest << 3) | (reg_dest)); + asm_thumb_add_reg_reg_offset(as, reg_dest, reg_base, offset - 31, operation_size); + asm_thumb_op16(as, ((OP_LDR_STR_TABLE[operation_size] | OP_LDR) << 11) | (31 << 6) | (reg_dest << 3) | (reg_dest)); } } -void asm_thumb_store_reg_reg_offset(asm_thumb_t *as, uint reg_src, uint reg_base, uint offset, uint shift) { - if (UNSIGNED_FIT5(offset) && (reg_src < ASM_THUMB_REG_R8) && (reg_base < ASM_THUMB_REG_R8)) { +void asm_thumb_store_reg_reg_offset(asm_thumb_t *as, uint reg_src, uint reg_base, uint offset, uint operation_size) { + assert(operation_size <= 2 && "Operation size out of range."); + + if (MP_FIT_UNSIGNED(5, offset) && (reg_src < ASM_THUMB_REG_R8) && (reg_base < ASM_THUMB_REG_R8)) { // Can use T1 encoding - asm_thumb_op16(as, ((OP_LDR_STR_TABLE[shift] | OP_STR) << 11) | (offset << 6) | (reg_base << 3) | reg_src); - } else if (asm_thumb_allow_armv7m(as) && UNSIGNED_FIT12(offset << shift)) { + asm_thumb_op16(as, ((OP_LDR_STR_TABLE[operation_size] | OP_STR) << 11) | (offset << 6) | (reg_base << 3) | reg_src); + } else if (asm_thumb_allow_armv7m(as) && MP_FIT_UNSIGNED(12, offset << operation_size)) { // Can use T3 encoding - asm_thumb_op32(as, (OP_LDR_STR_W_HI(shift, reg_base) | OP_STR_W), OP_LDR_STR_W_LO(reg_src, (offset << shift))); + asm_thumb_op32(as, (OP_LDR_STR_W_HI(operation_size, reg_base) | OP_STR_W), OP_LDR_STR_W_LO(reg_src, (offset << operation_size))); } else { // Must use the generic sequence - asm_thumb_add_reg_reg_offset(as, reg_base, reg_base, offset - 31, shift); - asm_thumb_op16(as, ((OP_LDR_STR_TABLE[shift] | OP_STR) << 11) | (31 << 6) | (reg_base << 3) | reg_src); + asm_thumb_add_reg_reg_offset(as, reg_base, reg_base, offset - 31, operation_size); + asm_thumb_op16(as, ((OP_LDR_STR_TABLE[operation_size] | OP_STR) << 11) | (31 << 6) | (reg_base << 3) | reg_src); } } diff --git a/py/asmthumb.h b/py/asmthumb.h index 6c83b583e2..5edf6573e1 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -317,24 +317,6 @@ static inline void asm_thumb_format_9_10(asm_thumb_t *as, uint op, uint rlo_dest asm_thumb_op16(as, ASM_THUMB_FORMAT_9_10_ENCODE(op, rlo_dest, rlo_base, offset)); } -static inline void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_src, rlo_base, word_offset); -} -static inline void asm_thumb_strb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_src, rlo_base, byte_offset); -} -static inline void asm_thumb_strh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint uint16_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_STRH, rlo_src, rlo_base, uint16_offset); -} -static inline void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_dest, rlo_base, word_offset); -} -static inline void asm_thumb_ldrb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_dest, rlo_base, byte_offset); -} -static inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint uint16_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_LDRH, rlo_dest, rlo_base, uint16_offset); -} static inline void asm_thumb_lsl_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_src, uint shift) { asm_thumb_format_1(as, ASM_THUMB_FORMAT_1_LSL, rlo_dest, rlo_src, shift); } @@ -383,9 +365,9 @@ void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num) void asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label); // Generate optimised load dest, [src, #offset] sequence -void asm_thumb_load_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint reg_base, uint offset, uint shift); +void asm_thumb_load_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint reg_base, uint offset, uint operation_size); // Generate optimised store src, [dest, #offset] sequence -void asm_thumb_store_reg_reg_offset(asm_thumb_t *as, uint reg_src, uint reg_base, uint offset, uint shift); +void asm_thumb_store_reg_reg_offset(asm_thumb_t *as, uint reg_src, uint reg_base, uint offset, uint operation_size); void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience: picks narrow or wide branch void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch @@ -421,12 +403,12 @@ void asm_thumb_b_rel12(asm_thumb_t *as, int rel); #define REG_FUN_TABLE ASM_THUMB_REG_FUN_TABLE -#define ASM_T asm_thumb_t -#define ASM_END_PASS asm_thumb_end_pass -#define ASM_ENTRY asm_thumb_entry -#define ASM_EXIT asm_thumb_exit +#define ASM_T asm_thumb_t +#define ASM_END_PASS asm_thumb_end_pass +#define ASM_ENTRY(as, num_locals, name) asm_thumb_entry((as), (num_locals)) +#define ASM_EXIT asm_thumb_exit -#define ASM_JUMP asm_thumb_b_label +#define ASM_JUMP asm_thumb_b_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ do { \ asm_thumb_cmp_rlo_i8(as, reg, 0); \ diff --git a/py/asmx64.h b/py/asmx64.h index 30c6efd6d0..d80c5dcc13 100644 --- a/py/asmx64.h +++ b/py/asmx64.h @@ -154,12 +154,12 @@ void asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r32); // Holds a pointer to mp_fun_table #define REG_FUN_TABLE ASM_X64_REG_FUN_TABLE -#define ASM_T asm_x64_t -#define ASM_END_PASS asm_x64_end_pass -#define ASM_ENTRY asm_x64_entry -#define ASM_EXIT asm_x64_exit +#define ASM_T asm_x64_t +#define ASM_END_PASS asm_x64_end_pass +#define ASM_ENTRY(as, num_locals, name) asm_x64_entry((as), (num_locals)) +#define ASM_EXIT asm_x64_exit -#define ASM_JUMP asm_x64_jmp_label +#define ASM_JUMP asm_x64_jmp_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ do { \ if (bool_test) { \ @@ -205,16 +205,21 @@ void asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r32); #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x64_sub_r64_r64((as), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_x64_mul_r64_r64((as), (reg_dest), (reg_src)) -#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x64_mov_mem64_to_r64((as), (reg_base), 8 * (word_offset), (reg_dest)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem8_to_r64zx((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 2 * (uint16_offset), (reg_dest)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem32_to_r64zx((as), (reg_base), 0, (reg_dest)) - -#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 8 * (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x64_mov_r8_to_mem8((as), (reg_src), (reg_base), 0) -#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x64_mov_r16_to_mem16((as), (reg_src), (reg_base), 0) -#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_x64_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, qword_offset) asm_x64_mov_mem64_to_r64((as), (reg_base), 8 * (qword_offset), (reg_dest)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_x64_mov_mem8_to_r64zx((as), (reg_base), (byte_offset), (reg_dest)) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 2 * (word_offset), (reg_dest)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, dword_offset) asm_x64_mov_mem32_to_r64zx((as), (reg_base), 4 * (dword_offset), (reg_dest)) + +#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, qword_offset) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 8 * (qword_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_src, reg_base, byte_offset) asm_x64_mov_r8_to_mem8((as), (reg_src), (reg_base), (byte_offset)) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x64_mov_r16_to_mem16((as), (reg_src), (reg_base), 2 * (word_offset)) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_src, reg_base, dword_offset) asm_x64_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (dword_offset)) #endif // GENERIC_ASM_API diff --git a/py/asmx86.h b/py/asmx86.h index 5011e56d0c..d2e078ad51 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -149,12 +149,12 @@ void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r // Holds a pointer to mp_fun_table #define REG_FUN_TABLE ASM_X86_REG_FUN_TABLE -#define ASM_T asm_x86_t -#define ASM_END_PASS asm_x86_end_pass -#define ASM_ENTRY asm_x86_entry -#define ASM_EXIT asm_x86_exit +#define ASM_T asm_x86_t +#define ASM_END_PASS asm_x86_end_pass +#define ASM_ENTRY(as, num_locals, name) asm_x86_entry((as), (num_locals)) +#define ASM_EXIT asm_x86_exit -#define ASM_JUMP asm_x86_jmp_label +#define ASM_JUMP asm_x86_jmp_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ do { \ if (bool_test) { \ @@ -200,18 +200,21 @@ void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x86_sub_r32_r32((as), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_x86_mul_r32_r32((as), (reg_dest), (reg_src)) -#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem8_to_r32zx((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 2 * (uint16_offset), (reg_dest)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x86_mov_mem32_to_r32((as), (reg_base), 4 * (word_offset), (reg_dest)) - -#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x86_mov_r8_to_mem8((as), (reg_src), (reg_base), 0) -#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x86_mov_r16_to_mem16((as), (reg_src), (reg_base), 0) -#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) -#define ASM_STORE32_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (word_offset)) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, dword_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (dword_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_x86_mov_mem8_to_r32zx((as), (reg_base), (byte_offset), (reg_dest)) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 2 * (word_offset), (reg_dest)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, dword_offset) asm_x86_mov_mem32_to_r32((as), (reg_base), 4 * (dword_offset), (reg_dest)) + +#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, dword_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), (dword_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_src, reg_base, byte_offset) asm_x86_mov_r8_to_mem8((as), (reg_src), (reg_base), (byte_offset)) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x86_mov_r16_to_mem16((as), (reg_src), (reg_base), 2 * (word_offset)) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_src, reg_base, dword_offset) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (dword_offset)) #endif // GENERIC_ASM_API diff --git a/py/asmxtensa.c b/py/asmxtensa.c index 85a8cfef55..bc3e717d9f 100644 --- a/py/asmxtensa.c +++ b/py/asmxtensa.c @@ -299,25 +299,47 @@ void asm_xtensa_l32i_optimised(asm_xtensa_t *as, uint reg_dest, uint reg_base, u } } -void asm_xtensa_s32i_optimised(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset) { - if (word_offset < 16) { - asm_xtensa_op_s32i_n(as, reg_src, reg_base, word_offset); - } else if (word_offset < 256) { - asm_xtensa_op_s32i(as, reg_src, reg_base, word_offset); +void asm_xtensa_load_reg_reg_offset(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint offset, uint operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); + + if (operation_size == 2 && MP_FIT_UNSIGNED(4, offset)) { + asm_xtensa_op_l32i_n(as, reg_dest, reg_base, offset); + return; + } + + if (MP_FIT_UNSIGNED(8, offset)) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, operation_size, reg_base, reg_dest, offset)); + return; + } + + asm_xtensa_mov_reg_i32_optimised(as, reg_dest, offset << operation_size); + asm_xtensa_op_add_n(as, reg_dest, reg_base, reg_dest); + if (operation_size == 2) { + asm_xtensa_op_l32i_n(as, reg_dest, reg_dest, 0); } else { - asm_xtensa_mov_reg_i32_optimised(as, REG_TEMP, word_offset * 4); - asm_xtensa_op_add_n(as, REG_TEMP, reg_base, REG_TEMP); - asm_xtensa_op_s32i_n(as, reg_src, REG_TEMP, 0); + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, operation_size, reg_dest, reg_dest, 0)); } } -void asm_xtensa_l16ui_optimised(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint halfword_offset) { - if (halfword_offset < 256) { - asm_xtensa_op_l16ui(as, reg_dest, reg_base, halfword_offset); +void asm_xtensa_store_reg_reg_offset(asm_xtensa_t *as, uint reg_src, uint reg_base, uint offset, uint operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); + + if (operation_size == 2 && MP_FIT_UNSIGNED(4, offset)) { + asm_xtensa_op_s32i_n(as, reg_src, reg_base, offset); + return; + } + + if (MP_FIT_UNSIGNED(8, offset)) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 0x04 | operation_size, reg_base, reg_src, offset)); + return; + } + + asm_xtensa_mov_reg_i32_optimised(as, REG_TEMP, offset << operation_size); + asm_xtensa_op_add_n(as, REG_TEMP, reg_base, REG_TEMP); + if (operation_size == 2) { + asm_xtensa_op_s32i_n(as, reg_src, REG_TEMP, 0); } else { - asm_xtensa_mov_reg_i32_optimised(as, reg_dest, halfword_offset * 2); - asm_xtensa_op_add_n(as, reg_dest, reg_base, reg_dest); - asm_xtensa_op_l16ui(as, reg_dest, reg_dest, 0); + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 0x04 | operation_size, REG_TEMP, reg_src, 0)); } } diff --git a/py/asmxtensa.h b/py/asmxtensa.h index d90aef3c53..559b3cacd5 100644 --- a/py/asmxtensa.h +++ b/py/asmxtensa.h @@ -293,9 +293,8 @@ void asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src); void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_pcrel(asm_xtensa_t *as, uint reg_dest, uint label); -void asm_xtensa_l32i_optimised(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint word_offset); -void asm_xtensa_s32i_optimised(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset); -void asm_xtensa_l16ui_optimised(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint halfword_offset); +void asm_xtensa_load_reg_reg_offset(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint offset, uint operation_size); +void asm_xtensa_store_reg_reg_offset(asm_xtensa_t *as, uint reg_src, uint reg_base, uint offset, uint operation_size); void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx); void asm_xtensa_bit_branch(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t bit, mp_uint_t label, mp_uint_t condition); @@ -341,9 +340,9 @@ void asm_xtensa_l32r(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t label); #define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED #define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE -#define ASM_ENTRY(as, nlocal) asm_xtensa_entry((as), (nlocal)) -#define ASM_EXIT(as) asm_xtensa_exit((as)) -#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) +#define ASM_ENTRY(as, nlocal, name) asm_xtensa_entry((as), (nlocal)) +#define ASM_EXIT(as) asm_xtensa_exit((as)) +#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) #else // Configuration for windowed calls with window size 8 @@ -371,9 +370,9 @@ void asm_xtensa_l32r(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t label); #define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED_WIN #define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE_WIN -#define ASM_ENTRY(as, nlocal) asm_xtensa_entry_win((as), (nlocal)) -#define ASM_EXIT(as) asm_xtensa_exit_win((as)) -#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind_win((as), (idx)) +#define ASM_ENTRY(as, nlocal, name) asm_xtensa_entry_win((as), (nlocal)) +#define ASM_EXIT(as) asm_xtensa_exit_win((as)) +#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind_win((as), (idx)) #endif @@ -420,16 +419,22 @@ void asm_xtensa_l32r(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t label); #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mull((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l8ui((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l16ui((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_xtensa_l16ui_optimised((as), (reg_dest), (reg_base), (uint16_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_xtensa_load_reg_reg_offset((as), (reg_dest), (reg_base), (byte_offset), 0) +#define ASM_LOAD8_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ + do { \ + asm_xtensa_op_add_n((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_l8ui((as), (reg_dest), (reg_base), 0); \ + } while (0) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, halfword_offset) asm_xtensa_load_reg_reg_offset((as), (reg_dest), (reg_base), (halfword_offset), 1) #define ASM_LOAD16_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ do { \ asm_xtensa_op_addx2((as), (reg_base), (reg_index), (reg_base)); \ asm_xtensa_op_l16ui((as), (reg_dest), (reg_base), 0); \ } while (0) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l32i_n((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_l32i_optimised((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_load_reg_reg_offset((as), (reg_dest), (reg_base), (word_offset), 2) #define ASM_LOAD32_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ do { \ asm_xtensa_op_addx4((as), (reg_base), (reg_index), (reg_base)); \ @@ -437,15 +442,22 @@ void asm_xtensa_l32r(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t label); } while (0) #define ASM_STORE_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s8i((as), (reg_src), (reg_base), 0) -#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s16i((as), (reg_src), (reg_base), 0) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_src, reg_base, byte_offset) asm_xtensa_store_reg_reg_offset((as), (reg_src), (reg_base), (byte_offset), 0) +#define ASM_STORE8_REG_REG_REG(as, reg_val, reg_base, reg_index) \ + do { \ + asm_xtensa_op_add_n((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_s8i((as), (reg_val), (reg_base), 0); \ + } while (0) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_src, reg_base, halfword_offset) asm_xtensa_store_reg_reg_offset((as), (reg_src), (reg_base), (halfword_offset), 1) #define ASM_STORE16_REG_REG_REG(as, reg_val, reg_base, reg_index) \ do { \ asm_xtensa_op_addx2((as), (reg_base), (reg_index), (reg_base)); \ asm_xtensa_op_s16i((as), (reg_val), (reg_base), 0); \ } while (0) -#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s32i_n((as), (reg_src), (reg_base), 0) -#define ASM_STORE32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_s32i_optimised((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_store_reg_reg_offset((as), (reg_dest), (reg_base), (word_offset), 2) #define ASM_STORE32_REG_REG_REG(as, reg_val, reg_base, reg_index) \ do { \ asm_xtensa_op_addx4((as), (reg_base), (reg_index), (reg_base)); \ diff --git a/py/emitnative.c b/py/emitnative.c index 7662de69e2..3aacf69a81 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -180,12 +180,6 @@ 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, @@ -425,6 +419,30 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->stack_info[i].vtype = VTYPE_UNBOUND; } + char *qualified_name = NULL; + + #if N_DEBUG + scope_t *current_scope = scope; + vstr_t *qualified_name_vstr = vstr_new(qstr_len(current_scope->simple_name)); + size_t fragment_length = 0; + const byte *fragment_pointer; + for (;;) { + fragment_pointer = qstr_data(current_scope->simple_name, &fragment_length); + vstr_hint_size(qualified_name_vstr, fragment_length); + memmove(qualified_name_vstr->buf + fragment_length, qualified_name_vstr->buf, qualified_name_vstr->len); + memcpy(qualified_name_vstr->buf, fragment_pointer, fragment_length); + qualified_name_vstr->len += fragment_length; + if (current_scope->parent == NULL || current_scope->parent->simple_name == MP_QSTR__lt_module_gt_) { + break; + } + vstr_ins_char(qualified_name_vstr, 0, '.'); + current_scope = current_scope->parent; + } + qualified_name = vstr_null_terminated_str(qualified_name_vstr); + #else + (void)qualified_name; + #endif + mp_asm_base_start_pass(&emit->as->base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); // generate code for entry to function @@ -471,7 +489,7 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop } // Entry to function - ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs); + ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs, qualified_name); #if N_X86 asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1); @@ -542,7 +560,7 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->start_offset); - ASM_ENTRY(emit->as, emit->code_state_start); + ASM_ENTRY(emit->as, emit->code_state_start, qualified_name); // Reset the state size for the state pointed to by REG_GENERATOR_STATE emit->code_state_start = 0; @@ -574,7 +592,7 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->stack_start = emit->code_state_start + SIZEOF_CODE_STATE; // Allocate space on C-stack for code_state structure, which includes state - ASM_ENTRY(emit->as, emit->stack_start + emit->n_state); + ASM_ENTRY(emit->as, emit->stack_start + emit->n_state, qualified_name); // Prepare incoming arguments for call to mp_setup_code_state @@ -640,6 +658,10 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop } } } + + #if N_DEBUG + vstr_free(qualified_name_vstr); + #endif } static inline void emit_native_write_code_info_byte(emit_t *emit, byte val) { @@ -1540,17 +1562,6 @@ static void emit_native_load_subscr(emit_t *emit) { #ifdef ASM_LOAD8_REG_REG_OFFSET ASM_LOAD8_REG_REG_OFFSET(emit->as, REG_RET, reg_base, index_value); #else - #if N_RV32 - if (FIT_SIGNED(index_value, 12)) { - asm_rv32_opcode_lbu(emit->as, REG_RET, reg_base, index_value); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value >= 0 && index_value < 256) { - asm_xtensa_op_l8ui(emit->as, REG_RET, reg_base, index_value); - break; - } - #endif if (index_value != 0) { // index is non-zero need_reg_single(emit, reg_index, 0); @@ -1787,24 +1798,9 @@ static void emit_native_store_subscr(emit_t *emit) { #ifdef ASM_STORE8_REG_REG_OFFSET ASM_STORE8_REG_REG_OFFSET(emit->as, reg_value, reg_base, index_value); #else - #if N_RV32 - if (FIT_SIGNED(index_value, 12)) { - asm_rv32_opcode_sb(emit->as, reg_value, reg_base, index_value); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value >= 0 && index_value < 256) { - asm_xtensa_op_s8i(emit->as, reg_value, reg_base, index_value); - break; - } - #endif if (index_value != 0) { // index is non-zero ASM_MOV_REG_IMM(emit->as, reg_index, index_value); - #if N_ARM - asm_arm_strb_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); - break; - #endif ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base reg_base = reg_index; } @@ -1817,17 +1813,6 @@ static void emit_native_store_subscr(emit_t *emit) { #ifdef ASM_STORE16_REG_REG_OFFSET ASM_STORE16_REG_REG_OFFSET(emit->as, reg_value, reg_base, index_value); #else - #if N_RV32 - if (FIT_SIGNED(index_value, 11)) { - asm_rv32_opcode_sh(emit->as, reg_value, reg_base, index_value << 1); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value >= 0 && index_value < 256) { - asm_xtensa_op_s16i(emit->as, reg_value, reg_base, index_value); - break; - } - #endif if (index_value != 0) { // index is a non-zero immediate ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); diff --git a/py/emitndebug.c b/py/emitndebug.c index c068a9a9a1..e49c5cdbff 100644 --- a/py/emitndebug.c +++ b/py/emitndebug.c @@ -108,8 +108,8 @@ 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_entry(asm_debug_t *as, int num_locals, char *name) { + asm_debug_printf(as, "ENTRY(%s, num_locals=%d)\n", name != NULL ? name : "?", num_locals); } static void asm_debug_exit(asm_debug_t *as) { @@ -195,8 +195,8 @@ static void asm_debug_setcc_reg_reg_reg(asm_debug_t *as, int op, int reg1, int r #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_ENTRY(as, num_locals, name) \ + asm_debug_entry(as, num_locals, name) #define ASM_EXIT(as) \ asm_debug_exit(as) @@ -390,11 +390,16 @@ static inline uint32_t mp_popcount(uint32_t x) { x = x - ((x >> 1) & 0x55555555); x = (x & 0x33333333) + ((x >> 2) & 0x33333333); x = (x + (x >> 4)) & 0x0F0F0F0F; - return x * 0x01010101; + return (x * 0x01010101) >> 24; } #endif #endif +#define MP_FIT_UNSIGNED(bits, value) (((value) & (~0U << (bits))) == 0) +#define MP_FIT_SIGNED(bits, value) \ + (MP_FIT_UNSIGNED(((bits) - 1), (value)) || \ + (((value) & (~0U << ((bits) - 1))) == (~0U << ((bits) - 1)))) + // 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__ diff --git a/py/mpconfig.h b/py/mpconfig.h index 94b8453003..cf0538cae4 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -426,6 +426,11 @@ #define MICROPY_EMIT_INLINE_RV32 (0) #endif +// Whether to enable the human-readable native instructions emitter +#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 || MICROPY_EMIT_RV32 || MICROPY_EMIT_NATIVE_DEBUG) diff --git a/py/objcode.h b/py/objcode.h index 8db9a34b6e..8f26bd9dbd 100644 --- a/py/objcode.h +++ b/py/objcode.h @@ -72,7 +72,7 @@ static inline const void *mp_code_get_proto_fun(mp_obj_code_t *self) { #include "py/emitglue.h" -#define MP_CODE_QSTR_MAP(context, idx) (context->constants.qstr_table[idx]) +#define MP_CODE_QSTR_MAP(context, idx) ((qstr)(context->constants.qstr_table[idx])) typedef struct _mp_obj_code_t { // TODO this was 4 words diff --git a/py/profile.c b/py/profile.c index 397d0291f9..b5a0c54728 100644 --- a/py/profile.c +++ b/py/profile.c @@ -80,7 +80,7 @@ static void frame_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t "<frame at 0x%p, file '%q', line %d, code %q>", frame, MP_CODE_QSTR_MAP(code->context, 0), - frame->lineno, + (int)frame->lineno, MP_CODE_QSTR_MAP(code->context, prelude->qstr_block_name_idx) ); } diff --git a/py/runtime.h b/py/runtime.h index a93488e2cd..f42039cab9 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -169,6 +169,12 @@ static inline void mp_thread_init_state(mp_state_thread_t *ts, size_t stack_size ts->nlr_jump_callback_top = NULL; ts->mp_pending_exception = MP_OBJ_NULL; + #if MICROPY_PY_SYS_SETTRACE + ts->prof_trace_callback = MP_OBJ_NULL; + ts->prof_callback_is_executing = false; + ts->current_code_state = NULL; + #endif + // If locals/globals are not given, inherit from main thread if (locals == NULL) { locals = mp_state_ctx.thread.dict_locals; diff --git a/tests/micropython/viper_ptr16_load_boundary.py b/tests/micropython/viper_ptr16_load_boundary.py index ccaaa0909a..0d4c3105b6 100644 --- a/tests/micropython/viper_ptr16_load_boundary.py +++ b/tests/micropython/viper_ptr16_load_boundary.py @@ -2,24 +2,38 @@ GET_TEMPLATE = """ @micropython.viper -def get{off}(src: ptr16) -> int: - return src[{off}] -print(b[{off} * 2:({off} + 1) * 2]) +def get{off}(src: ptr16) -> uint: + return uint(src[{off}]) +print(hex(get{off}(buffer))) """ +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 2 + + @micropython.viper def get_index(src: ptr16, i: int) -> int: return src[i] -b = bytearray(5000) -b[28:38] = b"0123456789" -b[252:262] = b"ABCDEFGHIJ" -b[4092:4102] = b"KLMNOPQRST" +def data(start, len): + output = bytearray(len) + for idx in range(len): + output[idx] = (start + idx) & 0xFF + return output + + +buffer = bytearray((((1 << max(BIT_THRESHOLDS)) + 1) // 1024) * 1024) +val = 0 +for bit in BIT_THRESHOLDS: + print("---", bit) + pre, idx, post = ((1 << bit) - (2 * SIZE), (1 << bit) - (1 * SIZE), 1 << bit) + buffer[pre:post] = data(val, 3 * SIZE) + val = val + (3 * SIZE) -for pre, idx, post in (15, 16, 17), (127, 128, 129), (2047, 2048, 2049): - print(get_index(b, pre), get_index(b, idx), get_index(b, post)) + pre, idx, post = pre // SIZE, idx // SIZE, post // SIZE + print(hex(get_index(buffer, pre)), hex(get_index(buffer, idx)), hex(get_index(buffer, post))) exec(GET_TEMPLATE.format(off=pre)) exec(GET_TEMPLATE.format(off=idx)) exec(GET_TEMPLATE.format(off=post)) diff --git a/tests/micropython/viper_ptr16_load_boundary.py.exp b/tests/micropython/viper_ptr16_load_boundary.py.exp index 4b8c184c13..56f1d32290 100644 --- a/tests/micropython/viper_ptr16_load_boundary.py.exp +++ b/tests/micropython/viper_ptr16_load_boundary.py.exp @@ -1,12 +1,20 @@ -13106 13620 14134 -bytearray(b'23') -bytearray(b'45') -bytearray(b'67') -17475 17989 18503 -bytearray(b'CD') -bytearray(b'EF') -bytearray(b'GH') -20045 20559 21073 -bytearray(b'MN') -bytearray(b'OP') -bytearray(b'QR') +--- 5 +0x100 0x302 0x504 +0x100 +0x302 +0x504 +--- 8 +0x706 0x908 0xb0a +0x706 +0x908 +0xb0a +--- 11 +0xd0c 0xf0e 0x1110 +0xd0c +0xf0e +0x1110 +--- 12 +0x1312 0x1514 0x1716 +0x1312 +0x1514 +0x1716 diff --git a/tests/micropython/viper_ptr16_store_boundary.py b/tests/micropython/viper_ptr16_store_boundary.py index e0a4f84557..1694c61ac0 100644 --- a/tests/micropython/viper_ptr16_store_boundary.py +++ b/tests/micropython/viper_ptr16_store_boundary.py @@ -4,38 +4,50 @@ SET_TEMPLATE = """ @micropython.viper def set{off}(dest: ptr16): dest[{off}] = {val} -set{off}(b) -print(b[{off} * 2:({off} + 1) * 2]) +set{off}(buffer) +print(hex(get_index(buffer, {off}))) """ -TEST_DATA = ( - (15, (0x4241, 0x4443, 0x4645)), - (127, (0x4847, 0x4A49, 0x4C4B)), - (2047, (0x4E4D, 0x504F, 0x5251)), -) +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 2 +MASK = (1 << (8 * SIZE)) - 1 @micropython.viper -def set_index(dest: ptr16, i: int, val: int): +def set_index(dest: ptr16, i: int, val: uint): dest[i] = val -@micropython.viper -def set_index(dest: ptr16, i: int, val: int): - dest[i] = val - - -b = bytearray(5000) -for start, vals in TEST_DATA: - for i, v in enumerate(vals): - set_index(b, start + i, v) - print(b[(start + i) * 2 : (start + i + 1) * 2]) - - -for i in range(len(b)): - b[i] = 0 - - -for start, vals in TEST_DATA: - for i, v in enumerate(vals): - exec(SET_TEMPLATE.format(off=start + i, val=v + 0x0101)) +def get_index(src, i): + return src[i * SIZE] + (src[(i * SIZE) + 1] << 8) + + +buffer = bytearray(((1 << max(BIT_THRESHOLDS) + 1) // 1024) * 1024) +next = 1 +val = 0 +for bit in BIT_THRESHOLDS: + print("---", bit) + pre, idx, post = ( + (((1 << bit) - (2 * SIZE)) // SIZE), + (((1 << bit) - (1 * SIZE)) // SIZE), + ((1 << bit) // SIZE), + ) + val = (val << 8) + next + next += 1 + set_index(buffer, pre, val & MASK) + val = (val << 8) + next + next += 1 + set_index(buffer, idx, val & MASK) + val = (val << 8) + next + next += 1 + set_index(buffer, post, val & MASK) + val = (val << 8) + next + next += 1 + print(hex(get_index(buffer, pre)), hex(get_index(buffer, idx)), hex(get_index(buffer, post))) + exec(SET_TEMPLATE.format(off=pre, val=val & MASK)) + val = (val << 8) + next + next += 1 + exec(SET_TEMPLATE.format(off=idx, val=val & MASK)) + val = (val << 8) + next + next += 1 + exec(SET_TEMPLATE.format(off=post, val=val & MASK)) diff --git a/tests/micropython/viper_ptr16_store_boundary.py.exp b/tests/micropython/viper_ptr16_store_boundary.py.exp index b56fe6695f..1c084da2d9 100644 --- a/tests/micropython/viper_ptr16_store_boundary.py.exp +++ b/tests/micropython/viper_ptr16_store_boundary.py.exp @@ -1,18 +1,20 @@ -bytearray(b'AB') -bytearray(b'CD') -bytearray(b'EF') -bytearray(b'GH') -bytearray(b'IJ') -bytearray(b'KL') -bytearray(b'MN') -bytearray(b'OP') -bytearray(b'QR') -bytearray(b'BC') -bytearray(b'DE') -bytearray(b'FG') -bytearray(b'HI') -bytearray(b'JK') -bytearray(b'LM') -bytearray(b'NO') -bytearray(b'PQ') -bytearray(b'RS') +--- 5 +0x1 0x102 0x203 +0x304 +0x405 +0x506 +--- 8 +0x607 0x708 0x809 +0x90a +0xa0b +0xb0c +--- 11 +0xc0d 0xd0e 0xe0f +0xf10 +0x1011 +0x1112 +--- 12 +0x1213 0x1314 0x1415 +0x1516 +0x1617 +0x1718 diff --git a/tests/micropython/viper_ptr32_load_boundary.py b/tests/micropython/viper_ptr32_load_boundary.py index 6954bd46b2..971d1113c4 100644 --- a/tests/micropython/viper_ptr32_load_boundary.py +++ b/tests/micropython/viper_ptr32_load_boundary.py @@ -2,24 +2,38 @@ GET_TEMPLATE = """ @micropython.viper -def get{off}(src: ptr32) -> int: - return src[{off}] -print(b[{off} * 4:({off} + 1) * 4]) +def get{off}(src: ptr32) -> uint: + return uint(src[{off}]) +print(hex(get{off}(buffer))) """ +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 4 + + @micropython.viper def get_index(src: ptr32, i: int) -> int: return src[i] -b = bytearray(5000) -b[24:43] = b"0123456789ABCDEFGHIJ" -b[248:268] = b"KLMNOPQRSTUVWXYZabcd" -b[4088:4108] = b"efghijklmnopqrstuvwx" +def data(start, len): + output = bytearray(len) + for idx in range(len): + output[idx] = (start + idx) & 0xFF + return output + + +buffer = bytearray((((1 << max(BIT_THRESHOLDS)) + 1) // 1024) * 1024) +val = 0 +for bit in BIT_THRESHOLDS: + print("---", bit) + pre, idx, post = (((1 << bit) - (2 * SIZE)), ((1 << bit) - (1 * SIZE)), (1 << bit)) + buffer[pre:post] = data(val, 3 * SIZE) + val = val + (3 * SIZE) -for pre, idx, post in (7, 8, 9), (63, 64, 65), (1023, 1024, 1025): - print(get_index(b, pre), get_index(b, idx), get_index(b, post)) + pre, idx, post = pre // SIZE, idx // SIZE, post // SIZE + print(hex(get_index(buffer, pre)), hex(get_index(buffer, idx)), hex(get_index(buffer, post))) exec(GET_TEMPLATE.format(off=pre)) exec(GET_TEMPLATE.format(off=idx)) exec(GET_TEMPLATE.format(off=post)) diff --git a/tests/micropython/viper_ptr32_load_boundary.py.exp b/tests/micropython/viper_ptr32_load_boundary.py.exp index a58e703f91..1e22a8b361 100644 --- a/tests/micropython/viper_ptr32_load_boundary.py.exp +++ b/tests/micropython/viper_ptr32_load_boundary.py.exp @@ -1,12 +1,20 @@ -926299444 1111570744 1178944579 -bytearray(b'4567') -bytearray(b'89AB') -bytearray(b'CDEF') -1381060687 1448432723 1515804759 -bytearray(b'OPQR') -bytearray(b'STUV') -bytearray(b'WXYZ') -1818978921 1886350957 1953722993 -bytearray(b'ijkl') -bytearray(b'mnop') -bytearray(b'qrst') +--- 5 +0x3020100 0x7060504 0xb0a0908 +0x3020100 +0x7060504 +0xb0a0908 +--- 8 +0xf0e0d0c 0x13121110 0x17161514 +0xf0e0d0c +0x13121110 +0x17161514 +--- 11 +0x1b1a1918 0x1f1e1d1c 0x23222120 +0x1b1a1918 +0x1f1e1d1c +0x23222120 +--- 12 +0x27262524 0x2b2a2928 0x2f2e2d2c +0x27262524 +0x2b2a2928 +0x2f2e2d2c diff --git a/tests/micropython/viper_ptr32_store_boundary.py b/tests/micropython/viper_ptr32_store_boundary.py index 243ff5cd9c..5109abb9dc 100644 --- a/tests/micropython/viper_ptr32_store_boundary.py +++ b/tests/micropython/viper_ptr32_store_boundary.py @@ -1,35 +1,58 @@ # Test boundary conditions for various architectures -TEST_DATA = ( - (3, (0x04030201, 0x08070605, 0x0C0B0A09)), - (63, (0x100F0E0D, 0x14131211, 0x18171615)), - (1023, (0x1C1B1A19, 0x201F1E1D, 0x24232221)), -) - SET_TEMPLATE = """ @micropython.viper def set{off}(dest: ptr32): - dest[{off}] = {val} & 0x3FFFFFFF -set{off}(b) -print(b[{off} * 4:({off} + 1) * 4]) + dest[{off}] = {val} +set{off}(buffer) +print(hex(get_index(buffer, {off}))) """ +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 4 +MASK = (1 << (8 * SIZE)) - 1 + @micropython.viper -def set_index(dest: ptr32, i: int, val: int): +def set_index(dest: ptr32, i: int, val: uint): dest[i] = val -b = bytearray(5000) -for start, vals in TEST_DATA: - for i, v in enumerate(vals): - set_index(b, start + i, v) - print(b[(start + i) * 4 : (start + i + 1) * 4]) - -for i in range(len(b)): - b[i] = 0 - - -for start, vals in TEST_DATA: - for i, v in enumerate(vals): - exec(SET_TEMPLATE.format(off=start + i, val=v + 0x01010101)) +def get_index(src, i): + return ( + src[i * SIZE] + + (src[(i * SIZE) + 1] << 8) + + (src[(i * SIZE) + 2] << 16) + + (src[(i * SIZE) + 3] << 24) + ) + + +buffer = bytearray(((1 << max(BIT_THRESHOLDS) + 1) // 1024) * 1024) +next = 1 +val = 0 +for bit in BIT_THRESHOLDS: + print("---", bit) + pre, idx, post = ( + (((1 << bit) - (2 * SIZE)) // SIZE), + (((1 << bit) - (1 * SIZE)) // SIZE), + ((1 << bit) // SIZE), + ) + val = (val << 8) + next + next += 1 + set_index(buffer, pre, val & MASK) + val = (val << 8) + next + next += 1 + set_index(buffer, idx, val & MASK) + val = (val << 8) + next + next += 1 + set_index(buffer, post, val & MASK) + val = (val << 8) + next + next += 1 + print(hex(get_index(buffer, pre)), hex(get_index(buffer, idx)), hex(get_index(buffer, post))) + exec(SET_TEMPLATE.format(off=pre, val=val & MASK)) + val = (val << 8) + next + next += 1 + exec(SET_TEMPLATE.format(off=idx, val=val & MASK)) + val = (val << 8) + next + next += 1 + exec(SET_TEMPLATE.format(off=post, val=val & MASK)) diff --git a/tests/micropython/viper_ptr32_store_boundary.py.exp b/tests/micropython/viper_ptr32_store_boundary.py.exp index 89f09fbc7a..67b114d335 100644 --- a/tests/micropython/viper_ptr32_store_boundary.py.exp +++ b/tests/micropython/viper_ptr32_store_boundary.py.exp @@ -1,18 +1,20 @@ -bytearray(b'\x01\x02\x03\x04') -bytearray(b'\x05\x06\x07\x08') -bytearray(b'\t\n\x0b\x0c') -bytearray(b'\r\x0e\x0f\x10') -bytearray(b'\x11\x12\x13\x14') -bytearray(b'\x15\x16\x17\x18') -bytearray(b'\x19\x1a\x1b\x1c') -bytearray(b'\x1d\x1e\x1f ') -bytearray(b'!"#$') -bytearray(b'\x02\x03\x04\x05') -bytearray(b'\x06\x07\x08\t') -bytearray(b'\n\x0b\x0c\r') -bytearray(b'\x0e\x0f\x10\x11') -bytearray(b'\x12\x13\x14\x15') -bytearray(b'\x16\x17\x18\x19') -bytearray(b'\x1a\x1b\x1c\x1d') -bytearray(b'\x1e\x1f !') -bytearray(b'"#$%') +--- 5 +0x1 0x102 0x10203 +0x1020304 +0x2030405 +0x3040506 +--- 8 +0x4050607 0x5060708 0x6070809 +0x708090a +0x8090a0b +0x90a0b0c +--- 11 +0xa0b0c0d 0xb0c0d0e 0xc0d0e0f +0xd0e0f10 +0xe0f1011 +0xf101112 +--- 12 +0x10111213 0x11121314 0x12131415 +0x13141516 +0x14151617 +0x15161718 diff --git a/tests/micropython/viper_ptr8_load_boundary.py b/tests/micropython/viper_ptr8_load_boundary.py index bcb17a1e1f..57e06da570 100644 --- a/tests/micropython/viper_ptr8_load_boundary.py +++ b/tests/micropython/viper_ptr8_load_boundary.py @@ -2,24 +2,37 @@ GET_TEMPLATE = """ @micropython.viper -def get{off}(src: ptr8) -> int: - return src[{off}] -print(get{off}(b)) +def get{off}(src: ptr8) -> uint: + return uint(src[{off}]) +print(hex(get{off}(buffer))) """ +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 1 + + @micropython.viper def get_index(src: ptr8, i: int) -> int: return src[i] -b = bytearray(5000) -b[30:32] = b"123" -b[254:256] = b"456" -b[4094:4096] = b"789" +def data(start, len): + output = bytearray(len) + for idx in range(len): + output[idx] = (start + idx) & 0xFF + return output + + +buffer = bytearray((((1 << max(BIT_THRESHOLDS)) + 1) // 1024) * 1024) +val = 0 +for bit in BIT_THRESHOLDS: + print("---", bit) + pre, idx, post = (((1 << bit) - (2 * SIZE)), ((1 << bit) - (1 * SIZE)), (1 << bit)) + buffer[pre:post] = data(val, 3 * SIZE) + val = val + (3 * SIZE) -for pre, idx, post in (30, 31, 32), (254, 255, 256), (4094, 4095, 4096): - print(get_index(b, pre), get_index(b, idx), get_index(b, post)) + print(hex(get_index(buffer, pre)), hex(get_index(buffer, idx)), hex(get_index(buffer, post))) exec(GET_TEMPLATE.format(off=pre)) exec(GET_TEMPLATE.format(off=idx)) exec(GET_TEMPLATE.format(off=post)) diff --git a/tests/micropython/viper_ptr8_load_boundary.py.exp b/tests/micropython/viper_ptr8_load_boundary.py.exp index 7cbd1ac78c..a0e423686b 100644 --- a/tests/micropython/viper_ptr8_load_boundary.py.exp +++ b/tests/micropython/viper_ptr8_load_boundary.py.exp @@ -1,12 +1,20 @@ -49 50 51 -49 -50 -51 -52 53 54 -52 -53 -54 -55 56 57 -55 -56 -57 +--- 5 +0x0 0x1 0x2 +0x0 +0x1 +0x2 +--- 8 +0x3 0x4 0x5 +0x3 +0x4 +0x5 +--- 11 +0x6 0x7 0x8 +0x6 +0x7 +0x8 +--- 12 +0x9 0xa 0xb +0x9 +0xa +0xb diff --git a/tests/micropython/viper_ptr8_store_boundary.py b/tests/micropython/viper_ptr8_store_boundary.py index ad51268454..e1fe6dcae3 100644 --- a/tests/micropython/viper_ptr8_store_boundary.py +++ b/tests/micropython/viper_ptr8_store_boundary.py @@ -1,30 +1,49 @@ # Test boundary conditions for various architectures -TEST_DATA = ((49, 30, 3), (52, 254, 3), (55, 4094, 3)) - SET_TEMPLATE = """ @micropython.viper def set{off}(dest: ptr8): dest[{off}] = {val} -set{off}(b) -print(b[{off}]) +set{off}(buffer) +print(hex(get_index(buffer, {off}))) """ +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 1 +MASK = (1 << (8 * SIZE)) - 1 + @micropython.viper -def set_index(dest: ptr8, i: int, val: int): +def set_index(dest: ptr8, i: int, val: uint): dest[i] = val -b = bytearray(5000) -for val, start, count in TEST_DATA: - for i in range(count): - set_index(b, start + i, val + i) - print(b[start : start + count]) - -for i in range(len(b)): - b[i] = 0 - -for val, start, count in TEST_DATA: - for i in range(count): - exec(SET_TEMPLATE.format(off=start + i, val=val + i + 16)) +def get_index(src: ptr8, i: int): + return src[i] + + +buffer = bytearray(((1 << max(BIT_THRESHOLDS) + 1) // 1024) * 1024) +next = 1 +val = 0 +for bit in BIT_THRESHOLDS: + print("---", bit) + pre, idx, post = (((1 << bit) - (2 * SIZE)), ((1 << bit) - (1 * SIZE)), (1 << bit)) + val = (val << 8) + next + next += 1 + set_index(buffer, pre, val & MASK) + val = (val << 8) + next + next += 1 + set_index(buffer, idx, val & MASK) + val = (val << 8) + next + next += 1 + set_index(buffer, post, val & MASK) + val = (val << 8) + next + next += 1 + print(hex(get_index(buffer, pre)), hex(get_index(buffer, idx)), hex(get_index(buffer, post))) + exec(SET_TEMPLATE.format(off=pre, val=val & MASK)) + val = (val << 8) + next + next += 1 + exec(SET_TEMPLATE.format(off=idx, val=val & MASK)) + val = (val << 8) + next + next += 1 + exec(SET_TEMPLATE.format(off=post, val=val & MASK)) diff --git a/tests/micropython/viper_ptr8_store_boundary.py.exp b/tests/micropython/viper_ptr8_store_boundary.py.exp index a35cb3ac9e..6b0f7ce13e 100644 --- a/tests/micropython/viper_ptr8_store_boundary.py.exp +++ b/tests/micropython/viper_ptr8_store_boundary.py.exp @@ -1,12 +1,20 @@ -bytearray(b'123') -bytearray(b'456') -bytearray(b'789') -65 -66 -67 -68 -69 -70 -71 -72 -73 +--- 5 +0x1 0x2 0x3 +0x4 +0x5 +0x6 +--- 8 +0x7 0x8 0x9 +0xa +0xb +0xc +--- 11 +0xd 0xe 0xf +0x10 +0x11 +0x12 +--- 12 +0x13 0x14 0x15 +0x16 +0x17 +0x18 diff --git a/tests/misc/sys_settrace_cov.py b/tests/misc/sys_settrace_cov.py new file mode 100644 index 0000000000..579c8a4a25 --- /dev/null +++ b/tests/misc/sys_settrace_cov.py @@ -0,0 +1,23 @@ +import sys + +try: + sys.settrace +except AttributeError: + print("SKIP") + raise SystemExit + + +def trace_tick_handler(frame, event, arg): + print("FRAME", frame) + print("LASTI", frame.f_lasti) + return None + + +def f(): + x = 3 + return x + + +sys.settrace(trace_tick_handler) +f() +sys.settrace(None) diff --git a/tests/misc/sys_settrace_cov.py.exp b/tests/misc/sys_settrace_cov.py.exp new file mode 100644 index 0000000000..423d78ec42 --- /dev/null +++ b/tests/misc/sys_settrace_cov.py.exp @@ -0,0 +1,2 @@ +FRAME <frame at 0x\[0-9a-f\]\+, file '\.\*/sys_settrace_cov.py', line \\d\+, code f> +LASTI \\d\+ diff --git a/tests/multi_net/tcp_accept_recv.py b/tests/multi_net/tcp_accept_recv.py index dee14e3b97..4108a6f8a3 100644 --- a/tests/multi_net/tcp_accept_recv.py +++ b/tests/multi_net/tcp_accept_recv.py @@ -1,30 +1,73 @@ -# Test recv on socket that just accepted a connection +# Test recv on listening socket after accept(), with various listen() arguments import socket PORT = 8000 +# Test cases for listen() function +LISTEN_ARGS = [None, 0, 1, 2] # None means no argument + # Server def instance0(): multitest.globals(IP=multitest.get_network_ip()) - s = socket.socket() - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - s.bind(socket.getaddrinfo("0.0.0.0", PORT)[0][-1]) - s.listen(1) multitest.next() - s.accept() - try: - print("recv", s.recv(10)) # should raise Errno 107 ENOTCONN - except OSError as er: - print(er.errno in (107, 128)) - s.close() + + test_num = 0 + for blocking_mode in [True, False]: + for listen_arg in LISTEN_ARGS: + test_num += 1 + s = socket.socket() + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind(socket.getaddrinfo("0.0.0.0", PORT)[0][-1]) + + # Call listen with or without argument based on test case + if listen_arg is None: + print(f"Test case {test_num}/8: listen() blocking={blocking_mode}") + s.listen() + else: + print(f"Test case {test_num}/8: listen({listen_arg}) blocking={blocking_mode}") + s.listen(listen_arg) + + # Signal client that server is ready + multitest.broadcast(f"server_ready_{test_num}") + + # Wait for client connection + c, _ = s.accept() + + # Set blocking mode after accept + s.setblocking(blocking_mode) + + try: + print("recv", s.recv(10)) # should raise Errno 107 ENOTCONN + except OSError as er: + # Verify the error code is either 107 (ENOTCONN) or 128 (ENOTCONN on Windows) + print(er.errno in (107, 128)) + + # Cleanup + c.close() + s.close() + + # Signal client we're done with this test case + multitest.broadcast(f"server_done_{test_num}") # Client def instance1(): multitest.next() - s = socket.socket() - s.connect(socket.getaddrinfo(IP, PORT)[0][-1]) - s.send(b"GET / HTTP/1.0\r\n\r\n") - s.close() + + test_num = 0 + for blocking_mode in [True, False]: + for _ in LISTEN_ARGS: + test_num += 1 + # Wait for server to be ready + multitest.wait(f"server_ready_{test_num}") + + # Connect to server + s = socket.socket() + s.connect(socket.getaddrinfo(IP, PORT)[0][-1]) + s.send(b"GET / HTTP/1.0\r\n\r\n") + s.close() + + # Wait for server to finish this test case + multitest.wait(f"server_done_{test_num}") diff --git a/tests/ports/unix/extra_coverage.py.exp b/tests/ports/unix/extra_coverage.py.exp index ac64edde69..ed21ced242 100644 --- a/tests/ports/unix/extra_coverage.py.exp +++ b/tests/ports/unix/extra_coverage.py.exp @@ -69,8 +69,8 @@ argv atexit byteorder exc_info executable exit getsizeof implementation intern maxsize modules path platform print_exception ps1 -ps2 stderr stdin stdout -tracebacklimit version version_info +ps2 settrace stderr stdin +stdout tracebacklimit version version_info ementation # attrtuple (start=1, stop=2, step=3) diff --git a/tests/ports/webassembly/py_proxy_has.mjs b/tests/ports/webassembly/py_proxy_has.mjs index 8881776fdb..37df0ae179 100644 --- a/tests/ports/webassembly/py_proxy_has.mjs +++ b/tests/ports/webassembly/py_proxy_has.mjs @@ -9,3 +9,5 @@ x = [] const x = mp.globals.get("x"); console.log("no_exist" in x); console.log("sort" in x); +console.log(Symbol.toStringTag in x); +console.log(Symbol.iterator in x); diff --git a/tests/ports/webassembly/py_proxy_has.mjs.exp b/tests/ports/webassembly/py_proxy_has.mjs.exp index 1d474d5255..7565230c01 100644 --- a/tests/ports/webassembly/py_proxy_has.mjs.exp +++ b/tests/ports/webassembly/py_proxy_has.mjs.exp @@ -1,2 +1,4 @@ false true +false +true diff --git a/tests/run-tests.py b/tests/run-tests.py index 628fde9d30..faf1d2e3b4 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -16,7 +16,7 @@ import threading import tempfile # Maximum time to run a PC-based test, in seconds. -TEST_TIMEOUT = 30 +TEST_TIMEOUT = float(os.environ.get('MICROPY_TEST_TIMEOUT', 30)) # See stackoverflow.com/questions/2632199: __file__ nor sys.argv[0] # are guaranteed to always work, this one should though. @@ -95,6 +95,7 @@ class __FS: return __File() vfs.mount(__FS(), '/__vfstest') os.chdir('/__vfstest') +{import_prologue} __import__('__injected_test') """ @@ -353,6 +354,7 @@ special_tests = [ "micropython/meminfo.py", "basics/bytes_compare3.py", "basics/builtin_help.py", + "misc/sys_settrace_cov.py", "thread/thread_exc2.py", "ports/esp32/partition_ota.py", ) @@ -1130,6 +1132,8 @@ class append_filter(argparse.Action): def main(): + global injected_import_hook_code + cmd_parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description="""Run and manage tests for MicroPython. @@ -1239,8 +1243,20 @@ the last matching regex is used: action="store_true", help="re-run only the failed tests", ) + cmd_parser.add_argument( + "--begin", + metavar="PROLOGUE", + default=None, + help="prologue python file to execute before module import", + ) args = cmd_parser.parse_args() + prologue = "" + if args.begin: + with open(args.begin, "rt") as source: + prologue = source.read() + injected_import_hook_code = injected_import_hook_code.replace("{import_prologue}", prologue) + if args.print_failures: for out in glob(os.path.join(args.result_dir, "*.out")): testbase = out[:-4] diff --git a/tools/autobuild/autobuild.sh b/tools/autobuild/autobuild.sh index 7854945bbe..7073152df7 100755 --- a/tools/autobuild/autobuild.sh +++ b/tools/autobuild/autobuild.sh @@ -69,7 +69,9 @@ fi FW_TAG="-$FW_DATE-$FW_SEMVER" # build new firmware -cd ports/cc3200 +cd ports/alif +build_alif_boards ${FW_TAG} ${LOCAL_FIRMWARE} +cd ../cc3200 build_cc3200_boards ${FW_TAG} ${LOCAL_FIRMWARE} cd ../esp8266 build_esp8266_boards ${FW_TAG} ${LOCAL_FIRMWARE} diff --git a/tools/autobuild/build-boards.sh b/tools/autobuild/build-boards.sh index bd6828cb40..165743cab5 100755 --- a/tools/autobuild/build-boards.sh +++ b/tools/autobuild/build-boards.sh @@ -86,6 +86,10 @@ function build_boards { done } +function build_alif_boards { + build_boards modalif.c $1 $2 zip +} + function build_cc3200_boards { build_boards hal/cc3200_hal.c $1 $2 zip } diff --git a/tools/ci.sh b/tools/ci.sh index b0e59509ad..4007dfebfc 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -480,13 +480,6 @@ function ci_stm32_misc_build { ######################################################################################## # ports/unix -CI_UNIX_OPTS_SYS_SETTRACE=( - MICROPY_PY_BTREE=0 - MICROPY_PY_FFI=0 - MICROPY_PY_SSL=0 - CFLAGS_EXTRA="-DMICROPY_PY_SYS_SETTRACE=1" -) - CI_UNIX_OPTS_SYS_SETTRACE_STACKLESS=( MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 @@ -514,8 +507,8 @@ CI_UNIX_OPTS_QEMU_RISCV64=( CI_UNIX_OPTS_SANITIZE_ADDRESS=( VARIANT=coverage - CFLAGS_EXTRA="-fsanitize=address" - LDFLAGS_EXTRA="-fsanitize=address" + CFLAGS_EXTRA="-fsanitize=address --param asan-use-after-return=0" + LDFLAGS_EXTRA="-fsanitize=address --param asan-use-after-return=0" ) CI_UNIX_OPTS_SANITIZE_UNDEFINED=( @@ -619,9 +612,9 @@ function ci_unix_standard_v2_run_tests { } function ci_unix_coverage_setup { - sudo pip3 install setuptools - sudo pip3 install pyelftools - sudo pip3 install ar + pip3 install setuptools + pip3 install pyelftools + pip3 install ar gcc --version python3 --version } @@ -632,7 +625,7 @@ function ci_unix_coverage_build { } function ci_unix_coverage_run_tests { - ci_unix_run_tests_full_helper coverage + MICROPY_TEST_TIMEOUT=60 ci_unix_run_tests_full_helper coverage } function ci_unix_coverage_run_mpy_merge_tests { @@ -734,16 +727,6 @@ function ci_unix_float_clang_run_tests { ci_unix_run_tests_helper CC=clang } -function ci_unix_settrace_build { - make ${MAKEOPTS} -C mpy-cross - make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix "${CI_UNIX_OPTS_SYS_SETTRACE[@]}" -} - -function ci_unix_settrace_run_tests { - ci_unix_run_tests_full_helper standard "${CI_UNIX_OPTS_SYS_SETTRACE[@]}" -} - function ci_unix_settrace_stackless_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/unix submodules @@ -762,7 +745,7 @@ function ci_unix_sanitize_undefined_build { } function ci_unix_sanitize_undefined_run_tests { - ci_unix_run_tests_full_helper coverage "${CI_UNIX_OPTS_SANITIZE_UNDEFINED[@]}" + MICROPY_TEST_TIMEOUT=60 ci_unix_run_tests_full_helper coverage "${CI_UNIX_OPTS_SANITIZE_UNDEFINED[@]}" } function ci_unix_sanitize_address_build { @@ -773,7 +756,7 @@ function ci_unix_sanitize_address_build { } function ci_unix_sanitize_address_run_tests { - ci_unix_run_tests_full_helper coverage "${CI_UNIX_OPTS_SANITIZE_ADDRESS[@]}" + MICROPY_TEST_TIMEOUT=60 ci_unix_run_tests_full_helper coverage "${CI_UNIX_OPTS_SANITIZE_ADDRESS[@]}" } function ci_unix_macos_build { diff --git a/tools/mpremote/mpremote/main.py b/tools/mpremote/mpremote/main.py index d122e93c0f..0441857fab 100644 --- a/tools/mpremote/mpremote/main.py +++ b/tools/mpremote/mpremote/main.py @@ -620,7 +620,11 @@ def main(): # If no commands were "actions" then implicitly finish with the REPL # using default args. if state.run_repl_on_completion(): - do_repl(state, argparse_repl().parse_args([])) + disconnected = do_repl(state, argparse_repl().parse_args([])) + + # Handle disconnection message + if disconnected: + print("\ndevice disconnected") return 0 except CommandError as e: diff --git a/tools/mpremote/mpremote/repl.py b/tools/mpremote/mpremote/repl.py index d24a7774ac..4fda04a2e2 100644 --- a/tools/mpremote/mpremote/repl.py +++ b/tools/mpremote/mpremote/repl.py @@ -7,51 +7,53 @@ def do_repl_main_loop( state, console_in, console_out_write, *, escape_non_printable, code_to_inject, file_to_inject ): while True: - console_in.waitchar(state.transport.serial) - c = console_in.readchar() - if c: - if c in (b"\x1d", b"\x18"): # ctrl-] or ctrl-x, quit - break - elif c == b"\x04": # ctrl-D - # special handling needed for ctrl-D if filesystem is mounted - state.transport.write_ctrl_d(console_out_write) - elif c == b"\x0a" and code_to_inject is not None: # ctrl-j, inject code - state.transport.serial.write(code_to_inject) - elif c == b"\x0b" and file_to_inject is not None: # ctrl-k, inject script - console_out_write(bytes("Injecting %s\r\n" % file_to_inject, "utf8")) - state.transport.enter_raw_repl(soft_reset=False) - with open(file_to_inject, "rb") as f: - pyfile = f.read() - try: - state.transport.exec_raw_no_follow(pyfile) - except TransportError as er: - console_out_write(b"Error:\r\n") - console_out_write(er) - state.transport.exit_raw_repl() - else: - state.transport.serial.write(c) - try: + console_in.waitchar(state.transport.serial) + c = console_in.readchar() + if c: + if c in (b"\x1d", b"\x18"): # ctrl-] or ctrl-x, quit + break + elif c == b"\x04": # ctrl-D + # special handling needed for ctrl-D if filesystem is mounted + state.transport.write_ctrl_d(console_out_write) + elif c == b"\x0a" and code_to_inject is not None: # ctrl-j, inject code + state.transport.serial.write(code_to_inject) + elif c == b"\x0b" and file_to_inject is not None: # ctrl-k, inject script + console_out_write(bytes("Injecting %s\r\n" % file_to_inject, "utf8")) + state.transport.enter_raw_repl(soft_reset=False) + with open(file_to_inject, "rb") as f: + pyfile = f.read() + try: + state.transport.exec_raw_no_follow(pyfile) + except TransportError as er: + console_out_write(b"Error:\r\n") + console_out_write(er) + state.transport.exit_raw_repl() + else: + state.transport.serial.write(c) + n = state.transport.serial.inWaiting() - except OSError as er: - if er.args[0] == 5: # IO error, device disappeared - print("device disconnected") - break + if n > 0: + dev_data_in = state.transport.serial.read(n) + if dev_data_in is not None: + if escape_non_printable: + # Pass data through to the console, with escaping of non-printables. + console_data_out = bytearray() + for c in dev_data_in: + if c in (8, 9, 10, 13, 27) or 32 <= c <= 126: + console_data_out.append(c) + else: + console_data_out.extend(b"[%02x]" % c) + else: + console_data_out = dev_data_in + console_out_write(console_data_out) - if n > 0: - dev_data_in = state.transport.serial.read(n) - if dev_data_in is not None: - if escape_non_printable: - # Pass data through to the console, with escaping of non-printables. - console_data_out = bytearray() - for c in dev_data_in: - if c in (8, 9, 10, 13, 27) or 32 <= c <= 126: - console_data_out.append(c) - else: - console_data_out.extend(b"[%02x]" % c) - else: - console_data_out = dev_data_in - console_out_write(console_data_out) + except OSError as er: + if _is_disconnect_exception(er): + return True + else: + raise + return False def do_repl(state, args): @@ -86,7 +88,7 @@ def do_repl(state, args): capture_file.flush() try: - do_repl_main_loop( + return do_repl_main_loop( state, console, console_out_write, @@ -98,3 +100,22 @@ def do_repl(state, args): console.exit() if capture_file is not None: capture_file.close() + + +def _is_disconnect_exception(exception): + """ + Check if an exception indicates device disconnect. + + Returns True if the exception indicates the device has disconnected, + False otherwise. + """ + if isinstance(exception, OSError): + if hasattr(exception, 'args') and len(exception.args) > 0: + # IO error, device disappeared + if exception.args[0] == 5: + return True + # Check for common disconnect messages in the exception string + exception_str = str(exception) + disconnect_indicators = ["Write timeout", "Device disconnected", "ClearCommError failed"] + return any(indicator in exception_str for indicator in disconnect_indicators) + return False |