summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ports_unix.yml52
-rw-r--r--extmod/modlwip.c6
-rw-r--r--ports/alif/Makefile15
-rw-r--r--ports/alif/README.md58
-rw-r--r--ports/alif/alif.mk1
-rw-r--r--ports/alif/boards/ALIF_ENSEMBLE/board.json17
-rw-r--r--ports/alif/boards/ALIF_ENSEMBLE/deploy.md37
-rw-r--r--ports/alif/irq.h1
-rw-r--r--ports/alif/machine_pin.c197
-rw-r--r--ports/alif/machine_spi.c60
-rw-r--r--ports/alif/main.c2
-rw-r--r--ports/alif/mphalport.h3
-rw-r--r--ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/board.json23
-rw-r--r--ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/mpconfigboard.cmake7
-rw-r--r--ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/mpconfigboard.h10
-rw-r--r--ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/pins.csv13
-rw-r--r--ports/esp32/boards/GARATRONIC_PYBSTICK26_ESP32C3/sdkconfig.board4
-rw-r--r--ports/esp32/panichandler.c11
-rw-r--r--ports/stm32/Makefile6
-rw-r--r--ports/stm32/boards/ARDUINO_GIGA/mpconfigboard.h1
-rw-r--r--ports/stm32/boards/ARDUINO_GIGA/stm32h747.ld25
-rw-r--r--ports/stm32/boards/ARDUINO_PORTENTA_H7/mpconfigboard.h1
-rw-r--r--ports/stm32/boards/stm32h7xx_hal_conf_base.h1
-rw-r--r--ports/stm32/main.c17
-rw-r--r--ports/stm32/uart.c11
-rw-r--r--ports/unix/README.md18
-rw-r--r--ports/unix/coverage.c12
-rw-r--r--ports/unix/variants/coverage/mpconfigvariant.h1
-rw-r--r--ports/webassembly/objpyproxy.js6
-rw-r--r--py/asmarm.c52
-rw-r--r--py/asmarm.h34
-rw-r--r--py/asmrv32.c73
-rw-r--r--py/asmrv32.h34
-rw-r--r--py/asmthumb.c36
-rw-r--r--py/asmthumb.h32
-rw-r--r--py/asmx64.h35
-rw-r--r--py/asmx86.h37
-rw-r--r--py/asmxtensa.c50
-rw-r--r--py/asmxtensa.h48
-rw-r--r--py/emitnative.c77
-rw-r--r--py/emitndebug.c8
-rw-r--r--py/misc.h7
-rw-r--r--py/mpconfig.h5
-rw-r--r--py/objcode.h2
-rw-r--r--py/profile.c2
-rw-r--r--py/runtime.h6
-rw-r--r--tests/micropython/viper_ptr16_load_boundary.py32
-rw-r--r--tests/micropython/viper_ptr16_load_boundary.py.exp32
-rw-r--r--tests/micropython/viper_ptr16_store_boundary.py66
-rw-r--r--tests/micropython/viper_ptr16_store_boundary.py.exp38
-rw-r--r--tests/micropython/viper_ptr32_load_boundary.py32
-rw-r--r--tests/micropython/viper_ptr32_load_boundary.py.exp32
-rw-r--r--tests/micropython/viper_ptr32_store_boundary.py69
-rw-r--r--tests/micropython/viper_ptr32_store_boundary.py.exp38
-rw-r--r--tests/micropython/viper_ptr8_load_boundary.py31
-rw-r--r--tests/micropython/viper_ptr8_load_boundary.py.exp32
-rw-r--r--tests/micropython/viper_ptr8_store_boundary.py53
-rw-r--r--tests/micropython/viper_ptr8_store_boundary.py.exp32
-rw-r--r--tests/misc/sys_settrace_cov.py23
-rw-r--r--tests/misc/sys_settrace_cov.py.exp2
-rw-r--r--tests/multi_net/tcp_accept_recv.py73
-rw-r--r--tests/ports/unix/extra_coverage.py.exp4
-rw-r--r--tests/ports/webassembly/py_proxy_has.mjs2
-rw-r--r--tests/ports/webassembly/py_proxy_has.mjs.exp2
-rwxr-xr-xtests/run-tests.py18
-rwxr-xr-xtools/autobuild/autobuild.sh4
-rwxr-xr-xtools/autobuild/build-boards.sh4
-rwxr-xr-xtools/ci.sh33
-rw-r--r--tools/mpremote/mpremote/main.py6
-rw-r--r--tools/mpremote/mpremote/repl.py107
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)
diff --git a/py/misc.h b/py/misc.h
index 49f2f87111..5d0893bbdd 100644
--- a/py/misc.h
+++ b/py/misc.h
@@ -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