Merge pull request #7724 from tannewt/get_perfbench_running
Improve iMX RT performance
This commit is contained in:
commit
67e0a49a1f
@ -366,7 +366,7 @@ all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2
|
||||
$(BUILD)/firmware.elf: $(OBJ) $(GENERATED_LD_FILE)
|
||||
$(STEPECHO) "LINK $@"
|
||||
$(Q)echo $(OBJ) > $(BUILD)/firmware.objs
|
||||
$(Q)$(CC) -o $@ $(LDFLAGS) @$(BUILD)/firmware.objs -Wl,--start-group $(LIBS) -Wl,--end-group
|
||||
$(Q)$(CC) -o $@ $(LDFLAGS) @$(BUILD)/firmware.objs -Wl,--print-memory-usage -Wl,--start-group $(LIBS) -Wl,--end-group
|
||||
$(Q)$(SIZE) $@ | $(PYTHON) $(TOP)/tools/build_memory_info.py $(GENERATED_LD_FILE) $(BUILD)
|
||||
|
||||
$(BUILD)/firmware.bin: $(BUILD)/firmware.elf
|
||||
|
@ -49,7 +49,12 @@ INC += \
|
||||
CFLAGS += -ftree-vrp -DNDEBUG
|
||||
|
||||
# TinyUSB defines
|
||||
CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_MIMXRT10XX -DCFG_TUD_MIDI_RX_BUFSIZE=512 -DCFG_TUD_CDC_RX_BUFSIZE=512 -DCFG_TUD_MIDI_TX_BUFSIZE=512 -DCFG_TUD_CDC_TX_BUFSIZE=512 -DCFG_TUD_MSC_BUFSIZE=1024
|
||||
CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_MIMXRT10XX -DCFG_TUD_CDC_RX_BUFSIZE=512 -DCFG_TUD_CDC_TX_BUFSIZE=512
|
||||
ifeq ($(CHIP_FAMILY), MIMXRT1011)
|
||||
CFLAGS += -DCFG_TUD_MIDI_RX_BUFSIZE=64 -DCFG_TUD_MIDI_TX_BUFSIZE=64 -DCFG_TUD_MSC_BUFSIZE=512
|
||||
else
|
||||
CFLAGS += -DCFG_TUD_MIDI_RX_BUFSIZE=512 -DCFG_TUD_MIDI_TX_BUFSIZE=512 -DCFG_TUD_MSC_BUFSIZE=1024
|
||||
endif
|
||||
|
||||
#Debugging/Optimization
|
||||
# Never set -fno-inline because we use inline to move small functions into routines that must be
|
||||
@ -76,11 +81,15 @@ CFLAGS += \
|
||||
-g3 -Wno-unused-parameter \
|
||||
-ffunction-sections -fdata-sections -fstack-usage
|
||||
|
||||
OPTIMIZATION_FLAGS ?= -O2 -fno-inline-functions
|
||||
OPTIMIZATION_FLAGS ?= -O2
|
||||
|
||||
# option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk
|
||||
CFLAGS += $(OPTIMIZATION_FLAGS)
|
||||
|
||||
ifeq ($(CIRCUITPY_SWO_TRACE), 1)
|
||||
CFLAGS += -finstrument-functions -finstrument-functions-exclude-file-list=tinyusb -finstrument-functions-exclude-function-list='USB_OTG1_IRQHandler,usb_irq_handler,nlr_push,CLOCK_EnableClock,CLOCK_SetDiv,CLOCK_SetMux,__DMB,__ISB,__DSB,SCB_EnableICache,SCB_EnableDCache,ARM_MPU_Disable,ARM_MPU_Enable,SCB_DisableDCache,SCB_DisableICache,__enable_irq,__disable_irq,__set_MSP,port_get_raw_ticks,supervisor_ticks_ms64'
|
||||
endif
|
||||
|
||||
LD_FILES = $(wildcard boards/$(BOARD)/*.ld) $(addprefix linking/, flash/$(FLASH).ld chip_family/$(CHIP_FAMILY).ld common.ld)
|
||||
|
||||
LD_SCRIPT_FLAG := -Wl,-T,
|
||||
@ -171,20 +180,22 @@ all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2 $(BUILD)/firmware.hex
|
||||
|
||||
$(BUILD)/firmware.elf: $(OBJ) $(LD_FILES)
|
||||
$(STEPECHO) "LINK $@"
|
||||
$(Q)$(CC) -o $@ $(LDFLAGS) $(filter-out %.ld, $^) -Wl,--start-group $(LIBS) -Wl,--end-group
|
||||
$(Q)$(CC) -o $@ $(LDFLAGS) $(filter-out %.ld, $^) -Wl,--print-memory-usage -Wl,--start-group $(LIBS) -Wl,--end-group
|
||||
|
||||
# -R excludes sections from the output files.
|
||||
$(BUILD)/firmware.bin: $(BUILD)/firmware.elf
|
||||
$(STEPECHO) "Create $@"
|
||||
$(Q)$(OBJCOPY) -O binary -j .flash_config -j .ivt -j .text -j .ARM.exidx -j .data -j .itcm -j .dtcm_data $^ $@
|
||||
$(Q)$(OBJCOPY) -O binary -R .stack -R .dtcm_bss $^ $@
|
||||
|
||||
$(BUILD)/firmware.uf2: $(BUILD)/firmware.elf
|
||||
$(STEPECHO) "Create $@"
|
||||
$(Q)$(OBJCOPY) -O binary -j .text -j .ARM.exidx -j .data -j .itcm -j .dtcm_data $^ $@-binpart
|
||||
$(Q)$(OBJCOPY) -O binary -R .stack -R .dtcm_bss -R .ivt -R .flash_config $^ $@-binpart
|
||||
$(Q)$(PYTHON) $(TOP)/tools/uf2/utils/uf2conv.py -b $(BOOTLOADER_SIZE) -f MIMXRT10XX -c -o $@ $@-binpart
|
||||
$(Q)rm $@-binpart
|
||||
|
||||
# $(Q)rm $@-binpart
|
||||
|
||||
$(BUILD)/firmware.hex: $(BUILD)/firmware.elf
|
||||
$(Q)$(OBJCOPY) -O ihex -j .flash_config -j .ivt -j .text -j .ARM.exidx -j .data -j .itcm -j .dtcm_data $< $@
|
||||
$(Q)$(OBJCOPY) -O ihex -R .stack -R .dtcm_bss $< $@
|
||||
|
||||
include $(TOP)/py/mkrules.mk
|
||||
|
||||
|
@ -27,7 +27,11 @@
|
||||
|
||||
#include "supervisor/port.h"
|
||||
|
||||
void port_background_task(void) {
|
||||
#include "supervisor/linker.h"
|
||||
|
||||
#include "fsl_common.h"
|
||||
|
||||
void PLACE_IN_ITCM(port_background_task)(void) {
|
||||
}
|
||||
|
||||
void port_background_tick(void) {
|
||||
@ -38,5 +42,6 @@ void port_background_tick(void) {
|
||||
|
||||
void port_start_background_task(void) {
|
||||
}
|
||||
|
||||
void port_finish_background_task(void) {
|
||||
}
|
||||
|
@ -16,3 +16,8 @@
|
||||
|
||||
#define DEFAULT_UART_BUS_RX (&pin_GPIO_09)
|
||||
#define DEFAULT_UART_BUS_TX (&pin_GPIO_10)
|
||||
|
||||
#define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO_09)
|
||||
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO_10)
|
||||
|
||||
#define MICROPY_HW_LED_STATUS (&pin_GPIO_11)
|
||||
|
@ -47,3 +47,18 @@ const mcu_pin_obj_t *mimxrt10xx_reset_forbidden_pins[] = {
|
||||
};
|
||||
|
||||
// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here.
|
||||
|
||||
bool mimxrt10xx_board_reset_pin_number(const mcu_pin_obj_t *pin) {
|
||||
#if CIRCUITPY_SWO_TRACE
|
||||
if (pin == &pin_GPIO_AD_09) {
|
||||
IOMUXC_SetPinMux( /* Add these lines*/
|
||||
IOMUXC_GPIO_AD_09_ARM_TRACE_SWO,
|
||||
0U);
|
||||
IOMUXC_SetPinConfig( /* Add these lines*/
|
||||
IOMUXC_GPIO_AD_09_ARM_TRACE_SWO,
|
||||
0x00F9U);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "fsl_flexspi_nor_boot.h"
|
||||
|
||||
|
||||
__attribute__((section(".boot_hdr.ivt")))
|
||||
__attribute__((section(".boot_hdr.ivt"),used))
|
||||
/*************************************
|
||||
* IVT Data
|
||||
*************************************/
|
||||
@ -25,7 +25,7 @@ const ivt image_vector_table = {
|
||||
IVT_RSVD /* Reserved = 0 */
|
||||
};
|
||||
|
||||
__attribute__((section(".boot_hdr.boot_data")))
|
||||
__attribute__((section(".boot_hdr.boot_data"),used))
|
||||
/*************************************
|
||||
* Boot Data
|
||||
*************************************/
|
||||
|
@ -118,7 +118,12 @@ digitalio_direction_t common_hal_digitalio_digitalinout_get_direction(
|
||||
|
||||
void common_hal_digitalio_digitalinout_set_value(
|
||||
digitalio_digitalinout_obj_t *self, bool value) {
|
||||
GPIO_PinWrite(self->pin->gpio, self->pin->number, value);
|
||||
GPIO_Type *gpio = self->pin->gpio;
|
||||
if (value) {
|
||||
gpio->DR_SET = 1 << self->pin->number;
|
||||
} else {
|
||||
gpio->DR_CLEAR = 1 << self->pin->number;
|
||||
}
|
||||
}
|
||||
|
||||
bool common_hal_digitalio_digitalinout_get_value(
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "shared-bindings/microcontroller/__init__.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "shared-bindings/microcontroller/Processor.h"
|
||||
#include "supervisor/linker.h"
|
||||
#include "supervisor/shared/safe_mode.h"
|
||||
#include "supervisor/shared/translate/translate.h"
|
||||
|
||||
@ -43,14 +44,14 @@ void common_hal_mcu_delay_us(uint32_t delay) {
|
||||
mp_hal_delay_us(delay);
|
||||
}
|
||||
|
||||
volatile uint32_t nesting_count = 0;
|
||||
void common_hal_mcu_disable_interrupts(void) {
|
||||
volatile uint32_t PLACE_IN_DTCM_BSS(nesting_count) = 0;
|
||||
void PLACE_IN_ITCM(common_hal_mcu_disable_interrupts)(void) {
|
||||
__disable_irq();
|
||||
__DMB();
|
||||
nesting_count++;
|
||||
}
|
||||
|
||||
void common_hal_mcu_enable_interrupts(void) {
|
||||
void PLACE_IN_ITCM(common_hal_mcu_enable_interrupts)(void) {
|
||||
if (nesting_count == 0) {
|
||||
// This is very very bad because it means there was mismatched disable/enables
|
||||
reset_into_safe_mode(SAFE_MODE_INTERRUPT_ERROR);
|
||||
|
@ -64,9 +64,7 @@ void PLACE_IN_ITCM(common_hal_neopixel_write)(const digitalio_digitalinout_obj_t
|
||||
const uint32_t pin = digitalinout->pin->number;
|
||||
|
||||
__disable_irq();
|
||||
// Enable DWT in debug core. Useable when interrupts disabled, as opposed to Systick->VAL
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
||||
// Use DWT in debug core. Useable when interrupts disabled, as opposed to Systick->VAL
|
||||
DWT->CYCCNT = 0;
|
||||
|
||||
for (;;) {
|
||||
@ -88,12 +86,12 @@ void PLACE_IN_ITCM(common_hal_neopixel_write)(const digitalio_digitalinout_obj_t
|
||||
mask = 0x80;
|
||||
}
|
||||
}
|
||||
// Enable interrupts again
|
||||
__enable_irq();
|
||||
|
||||
// Update the next start.
|
||||
next_start_raw_ticks = port_get_raw_ticks(NULL) + 4;
|
||||
|
||||
// Enable interrupts again
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
@ -6,7 +6,7 @@ Boards can setup reserved flash with _ld_reserved_flash_size in board.ld. */
|
||||
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
code_size = 1M;
|
||||
code_size = _ld_flash_size >= 4M ? 2M : 1M;
|
||||
_ld_default_stack_size = 20K;
|
||||
|
||||
/* Default reserved flash to nothing. */
|
||||
@ -22,9 +22,9 @@ MEMORY
|
||||
FLASH_IVT (rx) : ORIGIN = 0x60001000, LENGTH = 4K
|
||||
/* Place the ISRs 48k in to leave room for the bootloader when it is available. */
|
||||
FLASH_FIRMWARE (rx) : ORIGIN = 0x6000C000, LENGTH = code_size - 48K
|
||||
FLASH_FATFS (r) : ORIGIN = 0x60100000, LENGTH = _ld_flash_size - code_size - _ld_reserved_flash_size
|
||||
FLASH_FATFS (r) : ORIGIN = 0x60000000 + code_size, LENGTH = _ld_flash_size - code_size - _ld_reserved_flash_size
|
||||
/* Teensy uses the last bit of flash for recovery. */
|
||||
RESERVED_FLASH : ORIGIN = 0x60100000 + _ld_flash_size - _ld_reserved_flash_size, LENGTH = _ld_reserved_flash_size
|
||||
RESERVED_FLASH : ORIGIN = 0x60000000 + code_size + _ld_flash_size - _ld_reserved_flash_size, LENGTH = _ld_reserved_flash_size
|
||||
OCRAM (rwx) : ORIGIN = 0x20200000, LENGTH = ram_size - 64K
|
||||
DTCM (x) : ORIGIN = 0x20000000, LENGTH = 32K
|
||||
ITCM (x) : ORIGIN = 0x00000000, LENGTH = 32K
|
||||
@ -52,24 +52,59 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
} > FLASH_IVT
|
||||
|
||||
/* Align for 256 ISR entries and place first in flash. Otherwise the UF2
|
||||
bootloader can't find it because it uses its own flash_config and ivt. */
|
||||
.isr_vector : ALIGN(4 * 256)
|
||||
{
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.isr_vector)) /* Startup code */
|
||||
. = ALIGN(4);
|
||||
} > ITCM AT> FLASH_FIRMWARE
|
||||
_ld_isr_destination = ADDR(.isr_vector);
|
||||
_ld_isr_flash_copy = LOADADDR(.isr_vector);
|
||||
_ld_isr_size = SIZEOF(.isr_vector);
|
||||
/* Used by the bootloader to start user code. */
|
||||
__VECTOR_TABLE = LOADADDR(.isr_vector);
|
||||
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__VECTOR_TABLE = .;
|
||||
__VECTOR_RAM = .;
|
||||
_ld_isr_table = .;
|
||||
|
||||
KEEP(*(.isr_vector)) /* Startup code */
|
||||
*(EXCLUDE_FILE(
|
||||
*fsl_flexspi.o
|
||||
*dcd_ci_hs.o
|
||||
*tusb_fifo.o
|
||||
*usbd.o
|
||||
*string0.o
|
||||
*py/nlr*.o
|
||||
*py/obj.o
|
||||
*py/gc.o
|
||||
*py/map.o
|
||||
*py/runtime.o
|
||||
*py/objboundmeth.o
|
||||
*py/objtype.o
|
||||
) .text*) /* .text* sections (code) */
|
||||
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
|
||||
/* Keep USB processing functions out of RAM because we don't know which will be used.
|
||||
We try to only keep USB interrupt related functions. */
|
||||
*dcd_ci_hs.o(.text.process_*_request .text.dcd_edpt* .text.dcd_init .text.dcd_set_address)
|
||||
*usbd.o(.text.process_*_request .text.process_[gs]et* .text.tud_* .text.usbd_* .text.configuration_reset .text.invoke_*)
|
||||
|
||||
/* Anything marked cold/unlikely should be in flash. */
|
||||
*(.text.unlikely.*)
|
||||
|
||||
*(EXCLUDE_FILE(
|
||||
*dcd_ci_hs.o
|
||||
*py/objboundmeth.o
|
||||
*py/objtype.o
|
||||
) .rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
. = ALIGN(4);
|
||||
} > FLASH_FIRMWARE
|
||||
|
||||
.ARM.exidx :
|
||||
{
|
||||
__exidx_start = .;
|
||||
*(.ARM.exidx*)
|
||||
__exidx_end = .;
|
||||
*(.gnu.linkonce.armexidx.*)
|
||||
_etext = .; /* define a global symbol at end of code */
|
||||
__etext = .; /* define a global symbol at end of code */
|
||||
@ -81,7 +116,6 @@ SECTIONS
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.data*) /* .data* sections */
|
||||
*fsl_flexspi.o(.text*)
|
||||
. = ALIGN(4);
|
||||
} > OCRAM AT> FLASH_FIRMWARE
|
||||
_ld_ocram_data_destination = ADDR(.data);
|
||||
@ -93,7 +127,7 @@ SECTIONS
|
||||
{
|
||||
. = ALIGN(4);
|
||||
|
||||
*(.bss*)
|
||||
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.bss*)))
|
||||
*(COMMON)
|
||||
|
||||
. = ALIGN(4);
|
||||
@ -103,11 +137,23 @@ SECTIONS
|
||||
_ld_heap_start = _ld_ocram_bss_start + _ld_ocram_bss_size;
|
||||
_ld_heap_end = ORIGIN(OCRAM) + LENGTH(OCRAM);
|
||||
|
||||
.itcm :
|
||||
|
||||
.itcm : ALIGN(4)
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.itcm.*)
|
||||
|
||||
*fsl_flexspi.o(.text*)
|
||||
*dcd_ci_hs.o(.text*)
|
||||
*tusb_fifo.o(.text*)
|
||||
*py/objboundmeth.o(.text*)
|
||||
*py/objtype.o(.text*)
|
||||
*py/obj.o(.text*)
|
||||
*py/gc.o(.text*)
|
||||
*py/map.o(.text*)
|
||||
*py/nlr*.o(.text*)
|
||||
*py/runtime.o(.text*)
|
||||
*(.text.process_*_isr .text.dcd_event_* .text.osal_queue*)
|
||||
*string0.o(.text*)
|
||||
. = ALIGN(4);
|
||||
} > ITCM AT> FLASH_FIRMWARE
|
||||
_ld_itcm_destination = ADDR(.itcm);
|
||||
@ -119,6 +165,9 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
|
||||
*(.dtcm_data.*)
|
||||
*dcd_ci_hs.o(.rodata*)
|
||||
*py/objboundmeth.o(.rodata*)
|
||||
*py/objtype.o(.rodata*)
|
||||
|
||||
. = ALIGN(4);
|
||||
} > DTCM AT> FLASH_FIRMWARE
|
||||
@ -139,7 +188,7 @@ SECTIONS
|
||||
_ld_dtcm_bss_start = ADDR(.dtcm_bss);
|
||||
_ld_dtcm_bss_size = SIZEOF(.dtcm_bss);
|
||||
|
||||
.stack :
|
||||
.stack (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(8);
|
||||
_ld_stack_bottom = .;
|
||||
|
@ -6,6 +6,8 @@ USB_HIGHSPEED = 1
|
||||
|
||||
# Number of USB endpoint pairs.
|
||||
USB_NUM_ENDPOINT_PAIRS = 8
|
||||
# Align buffers on the cache boundary so we don't inadvertently load them early.
|
||||
CIRCUITPY_TUSB_MEM_ALIGN = 32
|
||||
|
||||
INTERNAL_FLASH_FILESYSTEM = 1
|
||||
|
||||
|
@ -26,10 +26,11 @@
|
||||
|
||||
#include "reset.h"
|
||||
#include "supervisor/filesystem.h"
|
||||
#include "supervisor/linker.h"
|
||||
|
||||
#include "fsl_common.h"
|
||||
|
||||
void reset(void) {
|
||||
void PLACE_IN_ITCM(reset)(void) {
|
||||
filesystem_flush();
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
@ -13,6 +13,17 @@
|
||||
#include "supervisor/internal_flash.h"
|
||||
#include "supervisor/linker.h"
|
||||
|
||||
STATIC uint8_t _busy_bit_shift;
|
||||
STATIC bool _busy_bit_polarity;
|
||||
STATIC bool _inited = false;
|
||||
|
||||
void flexspi_nor_init(void) {
|
||||
// Copy busy bit info into RAM so we can use if when flash isn't available.
|
||||
_busy_bit_shift = qspiflash_config.memConfig.busyOffset;
|
||||
_busy_bit_polarity = qspiflash_config.memConfig.busyBitPolarity;
|
||||
_inited = true;
|
||||
}
|
||||
|
||||
STATIC status_t PLACE_IN_ITCM(flexspi_nor_write_enable)(FLEXSPI_Type * base, uint32_t baseAddr)
|
||||
{
|
||||
flexspi_transfer_t flashXfer;
|
||||
@ -53,9 +64,8 @@ STATIC status_t PLACE_IN_ITCM(flexspi_nor_wait_bus_busy)(FLEXSPI_Type * base)
|
||||
if (status != kStatus_Success) {
|
||||
return status;
|
||||
}
|
||||
size_t busyBit = readValue & (1U << qspiflash_config.memConfig.busyOffset);
|
||||
isBusy = (qspiflash_config.memConfig.busyBitPolarity == 0 && busyBit != 0) ||
|
||||
(qspiflash_config.memConfig.busyBitPolarity == 1 && busyBit == 0);
|
||||
bool busyBit = (readValue >> _busy_bit_shift) & 0x1;
|
||||
isBusy = busyBit != _busy_bit_polarity;
|
||||
} while (isBusy);
|
||||
|
||||
return status;
|
||||
|
@ -53,8 +53,15 @@ uint8_t _flash_cache[SECTOR_SIZE] __attribute__((aligned(4)));
|
||||
uint32_t _flash_page_addr = NO_CACHE;
|
||||
|
||||
void PLACE_IN_ITCM(supervisor_flash_init)(void) {
|
||||
// Update the LUT to make sure all entries are available.
|
||||
FLEXSPI_UpdateLUT(FLEXSPI, 0, (const uint32_t *)&qspiflash_config.memConfig.lookupTable, 64);
|
||||
// Update the LUT to make sure all entries are available. Copy the values to
|
||||
// memory first so that we don't read from the flash as we update the LUT.
|
||||
uint32_t lut_copy[64];
|
||||
memcpy(lut_copy, (const uint32_t *)&qspiflash_config.memConfig.lookupTable, 64 * sizeof(uint32_t));
|
||||
FLEXSPI_UpdateLUT(FLEXSPI, 0, lut_copy, 64);
|
||||
// Make sure everything is flushed after updating the LUT.
|
||||
__DSB();
|
||||
__ISB();
|
||||
flexspi_nor_init();
|
||||
}
|
||||
|
||||
static inline uint32_t lba2addr(uint32_t block) {
|
||||
@ -79,20 +86,21 @@ void PLACE_IN_ITCM(port_internal_flash_flush)(void) {
|
||||
if (memcmp(_flash_cache, (void *)_flash_page_addr, SECTOR_SIZE) != 0) {
|
||||
volatile uint32_t sector_addr = (_flash_page_addr - FlexSPI_AMBA_BASE);
|
||||
|
||||
__disable_irq();
|
||||
// Disable interrupts of priority 8+. They likely use code in flash
|
||||
// itself. Higher priority interrupts (<8) should ensure all of their
|
||||
// code is in RAM.
|
||||
__set_BASEPRI(8 << (8 - __NVIC_PRIO_BITS));
|
||||
status = flexspi_nor_flash_erase_sector(FLEXSPI, sector_addr);
|
||||
__enable_irq();
|
||||
__set_BASEPRI(0U);
|
||||
if (status != kStatus_Success) {
|
||||
printf("Page erase failure %ld!\r\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < SECTOR_SIZE / FLASH_PAGE_SIZE; ++i) {
|
||||
__disable_irq();
|
||||
__set_BASEPRI(8 << (8 - __NVIC_PRIO_BITS));
|
||||
status = flexspi_nor_flash_page_program(FLEXSPI, sector_addr + i * FLASH_PAGE_SIZE, (void *)_flash_cache + i * FLASH_PAGE_SIZE);
|
||||
__enable_irq();
|
||||
__set_BASEPRI(0U);
|
||||
if (status != kStatus_Success) {
|
||||
printf("Page program failure %ld!\r\n", status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -103,11 +111,17 @@ void PLACE_IN_ITCM(port_internal_flash_flush)(void) {
|
||||
}
|
||||
|
||||
mp_uint_t supervisor_flash_read_blocks(uint8_t *dest, uint32_t block, uint32_t num_blocks) {
|
||||
// Must write out anything in cache before trying to read.
|
||||
supervisor_flash_flush();
|
||||
for (size_t i = 0; i < num_blocks; i++) {
|
||||
uint32_t src = lba2addr(block + i);
|
||||
uint32_t page_addr = src & ~(SECTOR_SIZE - 1);
|
||||
// Copy from the cache if our page matches the cached one.
|
||||
if (page_addr == _flash_page_addr) {
|
||||
src = ((uint32_t)&_flash_cache) + (src - page_addr);
|
||||
}
|
||||
|
||||
memcpy(dest + FILESYSTEM_BLOCK_SIZE * i, (uint8_t *)src, FILESYSTEM_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
uint32_t src = lba2addr(block);
|
||||
memcpy(dest, (uint8_t *)src, FILESYSTEM_BLOCK_SIZE * num_blocks);
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
@ -141,5 +155,5 @@ mp_uint_t supervisor_flash_write_blocks(const uint8_t *src, uint32_t lba, uint32
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
void supervisor_flash_release_cache(void) {
|
||||
void PLACE_IN_ITCM(supervisor_flash_release_cache)(void) {
|
||||
}
|
||||
|
@ -42,6 +42,7 @@
|
||||
#define ROM_INDEX_PAGEPROGRAM 9
|
||||
#define ROM_INDEX_READSTATUSREG 1
|
||||
|
||||
extern void flexspi_nor_init(void);
|
||||
extern status_t flexspi_nor_flash_erase_sector(FLEXSPI_Type *base, uint32_t address);
|
||||
extern status_t flexspi_nor_flash_page_program(FLEXSPI_Type *base, uint32_t dstAddr, const uint32_t *src);
|
||||
extern status_t flexspi_nor_enable_quad_mode(FLEXSPI_Type *base);
|
||||
|
@ -42,13 +42,14 @@
|
||||
#include "common-hal/busio/SPI.h"
|
||||
#include "shared-bindings/microcontroller/__init__.h"
|
||||
|
||||
#include "reset.h"
|
||||
|
||||
#include "supervisor/background_callback.h"
|
||||
|
||||
#if CIRCUITPY_PEW
|
||||
#include "shared-module/_pew/PewPew.h"
|
||||
#endif
|
||||
|
||||
#include "reset.h"
|
||||
|
||||
#include "supervisor/background_callback.h"
|
||||
#include "supervisor/linker.h"
|
||||
#include "supervisor/shared/tick.h"
|
||||
|
||||
#include "clocks.h"
|
||||
@ -97,16 +98,25 @@ extern uint32_t _ld_dtcm_data_flash_copy;
|
||||
extern uint32_t _ld_itcm_destination;
|
||||
extern uint32_t _ld_itcm_size;
|
||||
extern uint32_t _ld_itcm_flash_copy;
|
||||
extern uint32_t _ld_isr_destination;
|
||||
extern uint32_t _ld_isr_size;
|
||||
extern uint32_t _ld_isr_flash_copy;
|
||||
|
||||
extern void main(void);
|
||||
|
||||
// This replaces the Reset_Handler in startup_*.S and SystemInit in system_*.c.
|
||||
// Turn off optimize("no-tree-loop-distribute-patterns") so that this isn't replaced
|
||||
// by calls to memcpy because we're copying it over now.
|
||||
void Reset_Handler(void);
|
||||
__attribute__((used, naked)) void Reset_Handler(void) {
|
||||
__attribute__((used, naked, no_instrument_function, optimize("no-tree-loop-distribute-patterns"))) void Reset_Handler(void) {
|
||||
__disable_irq();
|
||||
SCB->VTOR = (uint32_t)&__isr_vector;
|
||||
// Set the VTOR to the flash copy since we haven't copied it into RAM.
|
||||
SCB->VTOR = (uint32_t)&_ld_isr_flash_copy;
|
||||
__set_MSP((uint32_t)&_ld_stack_top);
|
||||
|
||||
// Turn off any residual ITM outputs.
|
||||
ITM->TER = 0;
|
||||
|
||||
/* Disable I cache and D cache */
|
||||
SCB_DisableICache();
|
||||
SCB_DisableDCache();
|
||||
@ -128,6 +138,11 @@ __attribute__((used, naked)) void Reset_Handler(void) {
|
||||
current_gpr14 |= IOMUXC_GPR_GPR14_CM7_CFGITCMSZ(0x6);
|
||||
IOMUXC_GPR->GPR14 = current_gpr14;
|
||||
|
||||
// Enable FlexRAM interrupts on invalid access.
|
||||
FLEXRAM->INT_STAT_EN = FLEXRAM_INT_STAT_EN_ITCM_ERR_STAT_EN(1) |
|
||||
FLEXRAM_INT_STAT_EN_DTCM_ERR_STAT_EN(1) |
|
||||
FLEXRAM_INT_STAT_EN_OCRAM_ERR_STAT_EN(1);
|
||||
|
||||
#if ((__FPU_PRESENT == 1) && (__FPU_USED == 1))
|
||||
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10, CP11 Full Access */
|
||||
#endif /* ((__FPU_PRESENT == 1) && (__FPU_USED == 1)) */
|
||||
@ -157,6 +172,13 @@ __attribute__((used, naked)) void Reset_Handler(void) {
|
||||
(&_ld_itcm_destination)[i] = (&_ld_itcm_flash_copy)[i];
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < ((size_t)&_ld_isr_size) / 4; i++) {
|
||||
(&_ld_isr_destination)[i] = (&_ld_isr_flash_copy)[i];
|
||||
}
|
||||
|
||||
// Now that we've copied the ISR table over, use that VTOR.
|
||||
SCB->VTOR = (uint32_t)&_ld_isr_destination;
|
||||
|
||||
// The first number in RBAR is the region number. When searching for a policy, the region with
|
||||
// the highest number wins. If none match, then the default policy set at enable applies.
|
||||
|
||||
@ -170,14 +192,19 @@ __attribute__((used, naked)) void Reset_Handler(void) {
|
||||
|
||||
// FlexSPI2 is 0x70000000
|
||||
|
||||
// This the first 1MB of flash is the bootloader and CircuitPython read-only data.
|
||||
MPU->RBAR = ARM_MPU_RBAR(10, 0x60000000U);
|
||||
MPU->RASR = ARM_MPU_RASR(EXECUTION, ARM_MPU_AP_FULL, NORMAL, NOT_SHAREABLE, CACHEABLE, BUFFERABLE, NO_SUBREGIONS, ARM_MPU_REGION_SIZE_1MB);
|
||||
// This the first portion (1MB, 2MB or 4MB) of flash is the bootloader and CircuitPython read-only data.
|
||||
MPU->RBAR = ARM_MPU_RBAR(10, FlexSPI_AMBA_BASE);
|
||||
uint32_t region_size = ARM_MPU_REGION_SIZE_32B;
|
||||
uint32_t code_size = ((uint32_t)&_ld_filesystem_start) - FlexSPI_AMBA_BASE;
|
||||
while (code_size > (1u << (region_size + 1))) {
|
||||
region_size += 1;
|
||||
}
|
||||
MPU->RASR = ARM_MPU_RASR(EXECUTION, ARM_MPU_AP_FULL, NORMAL, NOT_SHAREABLE, CACHEABLE, BUFFERABLE, NO_SUBREGIONS, region_size);
|
||||
|
||||
// The remainder of flash is the fat filesystem which could have code on it too. Make sure that
|
||||
// we set the region to the minimal size so that bad data doesn't get speculatively fetched.
|
||||
// Thanks to Damien for the tip!
|
||||
uint32_t region_size = ARM_MPU_REGION_SIZE_32B;
|
||||
region_size = ARM_MPU_REGION_SIZE_32B;
|
||||
uint32_t filesystem_size = &_ld_filesystem_end - &_ld_filesystem_start;
|
||||
while (filesystem_size > (1u << (region_size + 1))) {
|
||||
region_size += 1;
|
||||
@ -189,7 +216,7 @@ __attribute__((used, naked)) void Reset_Handler(void) {
|
||||
uint32_t subregion_size = (1u << (region_size + 1)) / 8;
|
||||
uint8_t subregion_mask = (0xff00 >> (remainder / subregion_size)) & 0xff;
|
||||
|
||||
MPU->RBAR = ARM_MPU_RBAR(11, 0x60100000U);
|
||||
MPU->RBAR = ARM_MPU_RBAR(11, (size_t)&_ld_filesystem_start);
|
||||
MPU->RASR = ARM_MPU_RASR(EXECUTION, ARM_MPU_AP_FULL, NORMAL, NOT_SHAREABLE, CACHEABLE, BUFFERABLE, subregion_mask, region_size);
|
||||
|
||||
// This the ITCM. Set it to read-only because we've loaded everything already and it's easy to
|
||||
@ -205,9 +232,10 @@ __attribute__((used, naked)) void Reset_Handler(void) {
|
||||
// cost of 1/4 speed OCRAM accesses. It will leave more room for caching data from the flash
|
||||
// too which might be a net win.
|
||||
MPU->RBAR = ARM_MPU_RBAR(14, 0x20200000U);
|
||||
MPU->RASR = ARM_MPU_RASR(EXECUTION, ARM_MPU_AP_FULL, NORMAL, SHAREABLE, CACHEABLE, BUFFERABLE, NO_SUBREGIONS, ARM_MPU_REGION_SIZE_512KB);
|
||||
MPU->RASR = ARM_MPU_RASR(NO_EXECUTION, ARM_MPU_AP_FULL, NORMAL, NOT_SHAREABLE, CACHEABLE, BUFFERABLE, NO_SUBREGIONS, ARM_MPU_REGION_SIZE_512KB);
|
||||
|
||||
// We steal 64k from FlexRAM for ITCM and DTCM so disable those memory regions here.
|
||||
// We use 64k from FlexRAM for ITCM and DTCM so disable those memory regions here.
|
||||
MPU->RBAR = ARM_MPU_RBAR(15, 0x20280000U);
|
||||
MPU->RASR = ARM_MPU_RASR(EXECUTION, ARM_MPU_AP_FULL, NORMAL, NOT_SHAREABLE, CACHEABLE, BUFFERABLE, 0x80, ARM_MPU_REGION_SIZE_512KB);
|
||||
|
||||
@ -239,14 +267,97 @@ __attribute__((used, naked)) void Reset_Handler(void) {
|
||||
}
|
||||
|
||||
__enable_irq();
|
||||
|
||||
main();
|
||||
}
|
||||
|
||||
void __attribute__((no_instrument_function,section(".itcm.profile_enter"),long_call)) __cyg_profile_func_enter(void *this_fn,
|
||||
void *call_site) {
|
||||
if ((ITM->TER & (1 << 3)) == 0) {
|
||||
return;
|
||||
}
|
||||
uint32_t addr = (uint32_t)this_fn;
|
||||
while (ITM->PORT[3U].u32 == 0UL) {
|
||||
// addr |= 1;
|
||||
}
|
||||
ITM->PORT[3].u32 = addr;
|
||||
}
|
||||
|
||||
void __attribute__((no_instrument_function,section(".itcm.profile_exit"),long_call)) __cyg_profile_func_exit(void *this_fn,
|
||||
void *call_site) {
|
||||
if ((ITM->TER & (1 << 4)) == 0) {
|
||||
return;
|
||||
}
|
||||
uint32_t addr = (uint32_t)this_fn;
|
||||
while (ITM->PORT[4U].u32 == 0UL) {
|
||||
// addr |= 1;
|
||||
}
|
||||
ITM->PORT[4].u32 = addr;
|
||||
}
|
||||
|
||||
safe_mode_t port_init(void) {
|
||||
CLOCK_SetMode(kCLOCK_ModeRun);
|
||||
|
||||
clocks_init();
|
||||
|
||||
// Turn on the DWT so that neopixel_write can use CYCCNT for timing.
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
DWT->CTRL = 0x2 << DWT_CTRL_SYNCTAP_Pos | DWT_CTRL_CYCCNTENA_Msk;
|
||||
|
||||
// Enable SWO if needed.
|
||||
#if CIRCUITPY_SWO_TRACE
|
||||
|
||||
// Turn on the 528 MHz clock to the TPIU.
|
||||
CLOCK_EnableClock(kCLOCK_Trace); /* Make these edits*/
|
||||
/* Set TRACE_PODF. */
|
||||
CLOCK_SetDiv(kCLOCK_TraceDiv, 0); /* Make these edits*/
|
||||
/* Set Trace clock source. */
|
||||
CLOCK_SetMux(kCLOCK_TraceMux, 0); /* Make these edits*/
|
||||
|
||||
ITM->TCR = ITM_TCR_TSENA_Msk | ITM_TCR_ITMENA_Msk | ITM_TCR_SYNCENA_Msk | ITM_TCR_DWTENA_Msk;
|
||||
|
||||
// Run at 2.75 mbaud. CP2102N says it can do up to 3.
|
||||
// Base clock is 528 mhz (not 500 like the core).
|
||||
// TPI->ACPR = 191;
|
||||
// Run at 1 mbaud so that USB isn't bottlenecked.
|
||||
TPI->ACPR = 527;
|
||||
TPI->SPPR = 0x2; // NRZ aka UART
|
||||
TPI->FFCR = 0;
|
||||
|
||||
IOMUXC_SetPinMux( /* Add these lines*/
|
||||
IOMUXC_GPIO_AD_09_ARM_TRACE_SWO,
|
||||
0U);
|
||||
IOMUXC_SetPinConfig( /* Add these lines*/
|
||||
IOMUXC_GPIO_AD_09_ARM_TRACE_SWO,
|
||||
0x00F9U);
|
||||
|
||||
// Enable ports 0-4:
|
||||
// * 0 is serial output
|
||||
// *
|
||||
// * 3 is addresses of functions beginning.
|
||||
// * 4 is addresses of functions ending.
|
||||
ITM->TER |= 0x1f;
|
||||
ITM->PORT[0].u8 = 'C';
|
||||
ITM->PORT[0].u8 = 'P';
|
||||
ITM->PORT[0].u8 = '\n';
|
||||
#endif
|
||||
|
||||
// Set all peripheral interrupt priorities to the lowest priority by default.
|
||||
for (uint16_t i = 0; i < NUMBER_OF_INT_VECTORS; i++) {
|
||||
NVIC_SetPriority(i, (1UL << __NVIC_PRIO_BITS) - 1UL);
|
||||
}
|
||||
NVIC_SetPriority(USB_OTG1_IRQn, 1);
|
||||
#ifdef USBPHY2
|
||||
NVIC_SetPriority(USB_OTG2_IRQn, 1);
|
||||
#endif
|
||||
|
||||
NVIC_SetPriority(FLEXRAM_IRQn, 0);
|
||||
NVIC_EnableIRQ(FLEXRAM_IRQn);
|
||||
|
||||
// Priorities 8+ will be disabled during flash operations. To run during
|
||||
// flash operations, ensure all code is in RAM (not flash) and set the
|
||||
// priority < 8.
|
||||
|
||||
#if CIRCUITPY_RTC
|
||||
rtc_init();
|
||||
#endif
|
||||
@ -305,7 +416,7 @@ void reset_to_bootloader(void) {
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset_cpu(void) {
|
||||
void PLACE_IN_ITCM(reset_cpu)(void) {
|
||||
reset();
|
||||
}
|
||||
|
||||
@ -332,7 +443,7 @@ uint32_t *port_heap_get_top(void) {
|
||||
}
|
||||
|
||||
// Place the word into the low power section of the SNVS.
|
||||
void port_set_saved_word(uint32_t value) {
|
||||
void PLACE_IN_ITCM(port_set_saved_word)(uint32_t value) {
|
||||
SNVS->LPGPR[1] = value;
|
||||
}
|
||||
|
||||
@ -355,7 +466,7 @@ uint64_t port_get_raw_ticks(uint8_t *subticks) {
|
||||
|
||||
void SNVS_HP_WRAPPER_IRQHandler(void);
|
||||
__attribute__((used))
|
||||
void SNVS_HP_WRAPPER_IRQHandler(void) {
|
||||
void PLACE_IN_ITCM(SNVS_HP_WRAPPER_IRQHandler)(void) {
|
||||
if ((SNVS->HPSR & SNVS_HPSR_PI_MASK) != 0) {
|
||||
supervisor_tick();
|
||||
SNVS->HPSR = SNVS_HPSR_PI_MASK;
|
||||
@ -414,44 +525,43 @@ void port_idle_until_interrupt(void) {
|
||||
common_hal_mcu_enable_interrupts();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Default interrupt handler for unused IRQs.
|
||||
*/
|
||||
// Catch faults where the memory access violates MPU settings.
|
||||
void MemManage_Handler(void);
|
||||
__attribute__((used)) void MemManage_Handler(void) {
|
||||
__attribute__((used)) void PLACE_IN_ITCM(MemManage_Handler)(void) {
|
||||
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
|
||||
while (true) {
|
||||
asm ("nop;");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Default interrupt handler for unused IRQs.
|
||||
*/
|
||||
void BusFault_Handler(void);
|
||||
__attribute__((used)) void BusFault_Handler(void) {
|
||||
__attribute__((used)) void PLACE_IN_ITCM(BusFault_Handler)(void) {
|
||||
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
|
||||
while (true) {
|
||||
asm ("nop;");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Default interrupt handler for unused IRQs.
|
||||
*/
|
||||
void UsageFault_Handler(void);
|
||||
__attribute__((used)) void UsageFault_Handler(void) {
|
||||
__attribute__((used)) void PLACE_IN_ITCM(UsageFault_Handler)(void) {
|
||||
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
|
||||
while (true) {
|
||||
asm ("nop;");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Default interrupt handler for unused IRQs.
|
||||
*/
|
||||
// Default fault handler.
|
||||
void HardFault_Handler(void);
|
||||
__attribute__((used)) void HardFault_Handler(void) {
|
||||
__attribute__((used)) void PLACE_IN_ITCM(HardFault_Handler)(void) {
|
||||
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
|
||||
while (true) {
|
||||
asm ("nop;");
|
||||
}
|
||||
}
|
||||
|
||||
// Catch access errors to FlexRAM (if the MPU didn't catch it first.)
|
||||
void FLEXRAM_IRQHandler(void);
|
||||
__attribute__((used)) void PLACE_IN_ITCM(FLEXRAM_IRQHandler)(void) {
|
||||
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
|
||||
while (true) {
|
||||
asm ("nop;");
|
||||
|
@ -1,90 +0,0 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries
|
||||
* Copyright (c) 2019 Lucian Copeland for Adafruit Industries
|
||||
* Copyright (c) 2019 Artur Pacholec
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "supervisor/serial.h"
|
||||
#include "py/mphal.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "fsl_clock.h"
|
||||
#include "fsl_lpuart.h"
|
||||
|
||||
#if defined(CIRCUITPY_CONSOLE_UART)
|
||||
// static LPUART_Type *uart_instance = LPUART1; // evk
|
||||
static LPUART_Type *uart_instance = LPUART4; // feather 1011
|
||||
// static LPUART_Type *uart_instance = LPUART2; // feather 1062
|
||||
static uint32_t UartSrcFreq(void) {
|
||||
uint32_t freq;
|
||||
|
||||
/* To make it simple, we assume default PLL and divider settings, and the only
|
||||
variable from application is use PLL3 source or OSC source */
|
||||
/* PLL3 div6 80M */
|
||||
if (CLOCK_GetMux(kCLOCK_UartMux) == 0) {
|
||||
freq = (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / 6U) /
|
||||
(CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
|
||||
} else {
|
||||
freq = CLOCK_GetOscFreq() / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
|
||||
}
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
void port_serial_init(void) {
|
||||
lpuart_config_t config;
|
||||
|
||||
LPUART_GetDefaultConfig(&config);
|
||||
config.baudRate_Bps = 115200;
|
||||
config.enableTx = true;
|
||||
config.enableRx = true;
|
||||
|
||||
LPUART_Init(uart_instance, &config, UartSrcFreq());
|
||||
}
|
||||
|
||||
bool port_serial_connected(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char port_serial_read(void) {
|
||||
uint8_t data;
|
||||
|
||||
LPUART_ReadBlocking(uart_instance, &data, sizeof(data));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool port_serial_bytes_available(void) {
|
||||
return LPUART_GetStatusFlags(uart_instance) & kLPUART_RxDataRegFullFlag;
|
||||
}
|
||||
|
||||
void port_serial_write_substring(const char *text, uint32_t len) {
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
LPUART_WriteBlocking(uart_instance, (uint8_t *)text, len);
|
||||
}
|
||||
#endif // CIRCUITPY_CONSOLE_UART
|
@ -27,6 +27,8 @@
|
||||
|
||||
#include "fsl_clock.h"
|
||||
#include "tusb.h"
|
||||
|
||||
#include "supervisor/linker.h"
|
||||
#include "supervisor/usb.h"
|
||||
|
||||
STATIC void init_usb_instance(mp_int_t instance) {
|
||||
@ -78,13 +80,13 @@ STATIC void init_usb_instance(mp_int_t instance) {
|
||||
// Provide the prototypes for the interrupt handlers. The iMX RT SDK doesn't.
|
||||
// The SDK only links to them from assembly.
|
||||
void USB_OTG1_IRQHandler(void);
|
||||
void USB_OTG1_IRQHandler(void) {
|
||||
void PLACE_IN_ITCM(USB_OTG1_IRQHandler)(void) {
|
||||
usb_irq_handler(0);
|
||||
}
|
||||
|
||||
#ifdef USBPHY2
|
||||
void USB_OTG2_IRQHandler(void);
|
||||
void USB_OTG2_IRQHandler(void) {
|
||||
void PLACE_IN_ITCM(USB_OTG2_IRQHandler)(void) {
|
||||
usb_irq_handler(1);
|
||||
}
|
||||
#endif
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
#include "supervisor/shared/translate/translate.h"
|
||||
|
||||
void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig) {
|
||||
void PLACE_IN_ITCM(mp_arg_check_num_sig)(size_t n_args, size_t n_kw, uint32_t sig) {
|
||||
// TODO maybe take the function name as an argument so we can print nicer error messages
|
||||
|
||||
// The reverse of MP_OBJ_FUN_MAKE_SIG
|
||||
|
2
py/bc.c
2
py/bc.c
@ -111,7 +111,7 @@ STATIC void dump_args(const mp_obj_t *a, size_t sz) {
|
||||
// - code_state->fun_bc should contain a pointer to the function object
|
||||
// - code_state->ip should contain the offset in bytes from the pointer
|
||||
// code_state->fun_bc->bytecode to the entry n_state (0 for bytecode, non-zero for native)
|
||||
void mp_setup_code_state(mp_code_state_t *code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
void PLACE_IN_ITCM(mp_setup_code_state)(mp_code_state_t * code_state, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
// This function is pretty complicated. It's main aim is to be efficient in speed and RAM
|
||||
// usage for the common case of positional only args.
|
||||
|
||||
|
@ -587,6 +587,18 @@ void supervisor_run_background_tasks_if_tick(void);
|
||||
#define MICROPY_WRAP_MP_EXECUTE_BYTECODE PLACE_IN_ITCM
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_LOAD_GLOBAL
|
||||
#define MICROPY_WRAP_MP_LOAD_GLOBAL PLACE_IN_ITCM
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_LOAD_NAME
|
||||
#define MICROPY_WRAP_MP_LOAD_NAME PLACE_IN_ITCM
|
||||
#endif
|
||||
|
||||
#ifndef MICROPY_WRAP_MP_OBJ_GET_TYPE
|
||||
#define MICROPY_WRAP_MP_OBJ_GET_TYPE PLACE_IN_ITCM
|
||||
#endif
|
||||
|
||||
#ifndef CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY
|
||||
#define CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY (0)
|
||||
#endif
|
||||
|
@ -560,6 +560,10 @@ CFLAGS += -DCIRCUITPY_TUSB_MEM_ALIGN=$(CIRCUITPY_TUSB_MEM_ALIGN)
|
||||
CIRCUITPY_TUSB_ATTR_USBRAM ?= ".bss.usbram"
|
||||
CFLAGS += -DCIRCUITPY_TUSB_ATTR_USBRAM=$(CIRCUITPY_TUSB_ATTR_USBRAM)
|
||||
|
||||
# Output function trace information from the ARM ITM.
|
||||
CIRCUITPY_SWO_TRACE ?= 0
|
||||
CFLAGS += -DCIRCUITPY_SWO_TRACE=$(CIRCUITPY_SWO_TRACE)
|
||||
|
||||
# Define an equivalent for MICROPY_LONGINT_IMPL, to pass to $(MPY-TOOL) in py/mkrules.mk
|
||||
# $(MPY-TOOL) needs to know what kind of longint to use (if any) to freeze long integers.
|
||||
# This should correspond to the MICROPY_LONGINT_IMPL definition in mpconfigport.h.
|
||||
|
8
py/gc.c
8
py/gc.c
@ -231,7 +231,9 @@ bool gc_is_locked(void) {
|
||||
// children: mark the unmarked child blocks and put those newly marked
|
||||
// blocks on the stack. When all children have been checked, pop off the
|
||||
// topmost block on the stack and repeat with that one.
|
||||
STATIC void gc_mark_subtree(size_t block) {
|
||||
// We don't instrument these functions because they occur a lot during GC and
|
||||
// fill up the output buffer quickly.
|
||||
STATIC void MP_NO_INSTRUMENT PLACE_IN_ITCM(gc_mark_subtree)(size_t block) {
|
||||
// Start with the block passed in the argument.
|
||||
size_t sp = 0;
|
||||
for (;;) {
|
||||
@ -350,7 +352,7 @@ STATIC void gc_sweep(void) {
|
||||
}
|
||||
|
||||
// Mark can handle NULL pointers because it verifies the pointer is within the heap bounds.
|
||||
STATIC void gc_mark(void *ptr) {
|
||||
STATIC void MP_NO_INSTRUMENT PLACE_IN_ITCM(gc_mark)(void *ptr) {
|
||||
if (VERIFY_PTR(ptr)) {
|
||||
size_t block = BLOCK_FROM_PTR(ptr);
|
||||
if (ATB_GET_KIND(block) == AT_HEAD) {
|
||||
@ -397,7 +399,7 @@ void gc_collect_ptr(void *ptr) {
|
||||
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
|
||||
__attribute__((no_sanitize_address))
|
||||
#endif
|
||||
static void *gc_get_ptr(void **ptrs, int i) {
|
||||
static void *MP_NO_INSTRUMENT PLACE_IN_ITCM(gc_get_ptr)(void **ptrs, int i) {
|
||||
#if MICROPY_DEBUG_VALGRIND
|
||||
if (!VALGRIND_CHECK_MEM_IS_ADDRESSABLE(&ptrs[i], sizeof(*ptrs))) {
|
||||
return NULL;
|
||||
|
@ -1827,6 +1827,17 @@ typedef double mp_float_t;
|
||||
#define MP_WEAK __attribute__((weak))
|
||||
#endif
|
||||
|
||||
// Modifier for functions which should not be instrumented when tracing with
|
||||
// -finstrument-functions
|
||||
#ifndef MP_NO_INSTRUMENT
|
||||
#define MP_NO_INSTRUMENT __attribute__((no_instrument_function))
|
||||
#endif
|
||||
|
||||
// Modifier for functions which should ideally inlined
|
||||
#ifndef MP_INLINE
|
||||
#define MP_INLINE inline MP_NO_INSTRUMENT
|
||||
#endif
|
||||
|
||||
// Modifier for functions which should be never inlined
|
||||
#ifndef MP_NOINLINE
|
||||
#define MP_NOINLINE __attribute__((noinline))
|
||||
@ -1847,6 +1858,12 @@ typedef double mp_float_t;
|
||||
#define MP_UNLIKELY(x) __builtin_expect((x), 0)
|
||||
#endif
|
||||
|
||||
// Modifier for functions which aren't often used. Calls will also be considered
|
||||
// unlikely. Section names are `.text.unlikely` for use in linker scripts.
|
||||
#ifndef MP_COLD
|
||||
#define MP_COLD __attribute__((cold))
|
||||
#endif
|
||||
|
||||
// To annotate that code is unreachable
|
||||
#ifndef MP_UNREACHABLE
|
||||
#if defined(__GNUC__)
|
||||
|
74
py/obj.h
74
py/obj.h
@ -86,19 +86,19 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
|
||||
|
||||
#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A
|
||||
|
||||
static inline bool mp_obj_is_small_int(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_small_int(mp_const_obj_t o) {
|
||||
return (((mp_int_t)(o)) & 1) != 0;
|
||||
}
|
||||
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
|
||||
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1))
|
||||
|
||||
static inline bool mp_obj_is_qstr(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_qstr(mp_const_obj_t o) {
|
||||
return (((mp_int_t)(o)) & 7) == 2;
|
||||
}
|
||||
#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3)
|
||||
#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 2))
|
||||
|
||||
static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
|
||||
return (((mp_int_t)(o)) & 7) == 6;
|
||||
}
|
||||
#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) (((mp_uint_t)(o)) >> 3)
|
||||
@ -115,25 +115,25 @@ mp_float_t mp_obj_float_get(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_new_float(mp_float_t value);
|
||||
#endif
|
||||
|
||||
static inline bool mp_obj_is_obj(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_obj(mp_const_obj_t o) {
|
||||
return (((mp_int_t)(o)) & 3) == 0;
|
||||
}
|
||||
|
||||
#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B
|
||||
|
||||
static inline bool mp_obj_is_small_int(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_small_int(mp_const_obj_t o) {
|
||||
return (((mp_int_t)(o)) & 3) == 1;
|
||||
}
|
||||
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 2)
|
||||
#define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 2) | 1))
|
||||
|
||||
static inline bool mp_obj_is_qstr(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_qstr(mp_const_obj_t o) {
|
||||
return (((mp_int_t)(o)) & 7) == 3;
|
||||
}
|
||||
#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 3)
|
||||
#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 3) | 3))
|
||||
|
||||
static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
|
||||
return (((mp_int_t)(o)) & 7) == 7;
|
||||
}
|
||||
#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) (((mp_uint_t)(o)) >> 3)
|
||||
@ -150,13 +150,13 @@ mp_float_t mp_obj_float_get(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_new_float(mp_float_t value);
|
||||
#endif
|
||||
|
||||
static inline bool mp_obj_is_obj(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_obj(mp_const_obj_t o) {
|
||||
return (((mp_int_t)(o)) & 1) == 0;
|
||||
}
|
||||
|
||||
#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
|
||||
|
||||
static inline bool mp_obj_is_small_int(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_small_int(mp_const_obj_t o) {
|
||||
return (((mp_int_t)(o)) & 1) != 0;
|
||||
}
|
||||
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)(o)) >> 1)
|
||||
@ -166,17 +166,17 @@ static inline bool mp_obj_is_small_int(mp_const_obj_t o) {
|
||||
#define mp_const_float_e MP_ROM_PTR((mp_obj_t)(((0x402df854 & ~3) | 2) + 0x80800000))
|
||||
#define mp_const_float_pi MP_ROM_PTR((mp_obj_t)(((0x40490fdb & ~3) | 2) + 0x80800000))
|
||||
|
||||
static inline bool mp_obj_is_float(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_float(mp_const_obj_t o) {
|
||||
return (((mp_uint_t)(o)) & 3) == 2 && (((mp_uint_t)(o)) & 0xff800007) != 0x00000006;
|
||||
}
|
||||
static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) {
|
||||
static MP_INLINE mp_float_t mp_obj_float_get(mp_const_obj_t o) {
|
||||
union {
|
||||
mp_float_t f;
|
||||
mp_uint_t u;
|
||||
} num = {.u = ((mp_uint_t)o - 0x80800000) & ~3};
|
||||
return num.f;
|
||||
}
|
||||
static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
|
||||
static MP_INLINE mp_obj_t mp_obj_new_float(mp_float_t f) {
|
||||
union {
|
||||
mp_float_t f;
|
||||
mp_uint_t u;
|
||||
@ -185,37 +185,37 @@ static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool mp_obj_is_qstr(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_qstr(mp_const_obj_t o) {
|
||||
return (((mp_uint_t)(o)) & 0xff80000f) == 0x00000006;
|
||||
}
|
||||
#define MP_OBJ_QSTR_VALUE(o) (((mp_uint_t)(o)) >> 4)
|
||||
#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)((((mp_uint_t)(qst)) << 4) | 0x00000006))
|
||||
|
||||
static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
|
||||
return (((mp_uint_t)(o)) & 0xff80000f) == 0x0000000e;
|
||||
}
|
||||
#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) (((mp_uint_t)(o)) >> 4)
|
||||
#define MP_OBJ_NEW_IMMEDIATE_OBJ(val) ((mp_obj_t)(((val) << 4) | 0xe))
|
||||
|
||||
static inline bool mp_obj_is_obj(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_obj(mp_const_obj_t o) {
|
||||
return (((mp_int_t)(o)) & 3) == 0;
|
||||
}
|
||||
|
||||
#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
|
||||
|
||||
static inline bool mp_obj_is_small_int(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_small_int(mp_const_obj_t o) {
|
||||
return (((uint64_t)(o)) & 0xffff000000000000) == 0x0001000000000000;
|
||||
}
|
||||
#define MP_OBJ_SMALL_INT_VALUE(o) (((mp_int_t)((o) << 16)) >> 17)
|
||||
#define MP_OBJ_NEW_SMALL_INT(small_int) (((((uint64_t)(small_int)) & 0x7fffffffffff) << 1) | 0x0001000000000001)
|
||||
|
||||
static inline bool mp_obj_is_qstr(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_qstr(mp_const_obj_t o) {
|
||||
return (((uint64_t)(o)) & 0xffff000000000000) == 0x0002000000000000;
|
||||
}
|
||||
#define MP_OBJ_QSTR_VALUE(o) ((((uint32_t)(o)) >> 1) & 0xffffffff)
|
||||
#define MP_OBJ_NEW_QSTR(qst) ((mp_obj_t)(((uint64_t)(((uint32_t)(qst)) << 1)) | 0x0002000000000001))
|
||||
|
||||
static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
|
||||
return (((uint64_t)(o)) & 0xffff000000000000) == 0x0003000000000000;
|
||||
}
|
||||
#define MP_OBJ_IMMEDIATE_OBJ_VALUE(o) ((((uint32_t)(o)) >> 46) & 3)
|
||||
@ -230,17 +230,17 @@ static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) {
|
||||
#define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b145769 + 0x8004000000000000))}
|
||||
#define mp_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))}
|
||||
|
||||
static inline bool mp_obj_is_float(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_float(mp_const_obj_t o) {
|
||||
return ((uint64_t)(o) & 0xfffc000000000000) != 0;
|
||||
}
|
||||
static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) {
|
||||
static MP_INLINE mp_float_t mp_obj_float_get(mp_const_obj_t o) {
|
||||
union {
|
||||
mp_float_t f;
|
||||
uint64_t r;
|
||||
} num = {.r = o - 0x8004000000000000};
|
||||
return num.f;
|
||||
}
|
||||
static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
|
||||
static MP_INLINE mp_obj_t mp_obj_new_float(mp_float_t f) {
|
||||
union {
|
||||
mp_float_t f;
|
||||
uint64_t r;
|
||||
@ -249,7 +249,7 @@ static inline mp_obj_t mp_obj_new_float(mp_float_t f) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool mp_obj_is_obj(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_obj(mp_const_obj_t o) {
|
||||
return (((uint64_t)(o)) & 0xffff000000000000) == 0x0000000000000000;
|
||||
}
|
||||
#define MP_OBJ_TO_PTR(o) ((void *)(uintptr_t)(o))
|
||||
@ -454,7 +454,7 @@ typedef enum _mp_map_lookup_kind_t {
|
||||
MP_MAP_LOOKUP_ADD_IF_NOT_FOUND_OR_REMOVE_IF_FOUND = 3, // only valid for mp_set_lookup
|
||||
} mp_map_lookup_kind_t;
|
||||
|
||||
static inline bool mp_map_slot_is_filled(const mp_map_t *map, size_t pos) {
|
||||
static MP_INLINE bool mp_map_slot_is_filled(const mp_map_t *map, size_t pos) {
|
||||
assert(pos < map->alloc);
|
||||
return (map)->table[pos].key != MP_OBJ_NULL && (map)->table[pos].key != MP_OBJ_SENTINEL;
|
||||
}
|
||||
@ -476,7 +476,7 @@ typedef struct _mp_set_t {
|
||||
mp_obj_t *table;
|
||||
} mp_set_t;
|
||||
|
||||
static inline bool mp_set_slot_is_filled(const mp_set_t *set, size_t pos) {
|
||||
static MP_INLINE bool mp_set_slot_is_filled(const mp_set_t *set, size_t pos) {
|
||||
return (set)->table[pos] != MP_OBJ_NULL && (set)->table[pos] != MP_OBJ_SENTINEL;
|
||||
}
|
||||
|
||||
@ -821,7 +821,7 @@ extern const struct _mp_obj_exception_t mp_static_GeneratorExit_obj;
|
||||
#define mp_obj_is_tuple_compatible(o) (mp_type_get_getiter_slot(mp_obj_get_type(o)) == mp_obj_tuple_getiter)
|
||||
|
||||
mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict);
|
||||
static inline mp_obj_t mp_obj_new_bool(mp_int_t x) {
|
||||
static MP_INLINE mp_obj_t mp_obj_new_bool(mp_int_t x) {
|
||||
return x ? mp_const_true : mp_const_false;
|
||||
}
|
||||
mp_obj_t mp_obj_new_cell(mp_obj_t obj);
|
||||
@ -893,7 +893,7 @@ mp_obj_t mp_obj_equal_not_equal(mp_binary_op_t op, mp_obj_t o1, mp_obj_t o2);
|
||||
bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2);
|
||||
|
||||
// returns true if o is bool, small int or long int
|
||||
static inline bool mp_obj_is_integer(mp_const_obj_t o) {
|
||||
static MP_INLINE bool mp_obj_is_integer(mp_const_obj_t o) {
|
||||
return mp_obj_is_int(o) || mp_obj_is_bool(o);
|
||||
}
|
||||
|
||||
@ -940,7 +940,7 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args);
|
||||
mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in);
|
||||
void mp_init_emergency_exception_buf(void);
|
||||
static inline mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) {
|
||||
static MP_INLINE mp_obj_t mp_obj_new_exception_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) {
|
||||
assert(exc_type->make_new == mp_obj_exception_make_new);
|
||||
return mp_obj_exception_make_new(exc_type, 1, 0, &arg);
|
||||
}
|
||||
@ -957,42 +957,42 @@ void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t s
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
// float
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
static inline float mp_obj_get_float_to_f(mp_obj_t o) {
|
||||
static MP_INLINE float mp_obj_get_float_to_f(mp_obj_t o) {
|
||||
return mp_obj_get_float(o);
|
||||
}
|
||||
|
||||
static inline double mp_obj_get_float_to_d(mp_obj_t o) {
|
||||
static MP_INLINE double mp_obj_get_float_to_d(mp_obj_t o) {
|
||||
return (double)mp_obj_get_float(o);
|
||||
}
|
||||
|
||||
static inline mp_obj_t mp_obj_new_float_from_f(float o) {
|
||||
static MP_INLINE mp_obj_t mp_obj_new_float_from_f(float o) {
|
||||
return mp_obj_new_float(o);
|
||||
}
|
||||
|
||||
static inline mp_obj_t mp_obj_new_float_from_d(double o) {
|
||||
static MP_INLINE mp_obj_t mp_obj_new_float_from_d(double o) {
|
||||
return mp_obj_new_float((mp_float_t)o);
|
||||
}
|
||||
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
|
||||
static inline float mp_obj_get_float_to_f(mp_obj_t o) {
|
||||
static MP_INLINE float mp_obj_get_float_to_f(mp_obj_t o) {
|
||||
return (float)mp_obj_get_float(o);
|
||||
}
|
||||
|
||||
static inline double mp_obj_get_float_to_d(mp_obj_t o) {
|
||||
static MP_INLINE double mp_obj_get_float_to_d(mp_obj_t o) {
|
||||
return mp_obj_get_float(o);
|
||||
}
|
||||
|
||||
static inline mp_obj_t mp_obj_new_float_from_f(float o) {
|
||||
static MP_INLINE mp_obj_t mp_obj_new_float_from_f(float o) {
|
||||
return mp_obj_new_float((mp_float_t)o);
|
||||
}
|
||||
|
||||
static inline mp_obj_t mp_obj_new_float_from_d(double o) {
|
||||
static MP_INLINE mp_obj_t mp_obj_new_float_from_d(double o) {
|
||||
return mp_obj_new_float(o);
|
||||
}
|
||||
#endif
|
||||
#if MICROPY_FLOAT_HIGH_QUALITY_HASH
|
||||
mp_int_t mp_float_hash(mp_float_t val);
|
||||
#else
|
||||
static inline mp_int_t mp_float_hash(mp_float_t val) {
|
||||
static MP_INLINE mp_int_t mp_float_hash(mp_float_t val) {
|
||||
return (mp_int_t)val;
|
||||
}
|
||||
#endif
|
||||
@ -1031,7 +1031,7 @@ mp_obj_t mp_obj_dict_get(mp_obj_t self_in, mp_obj_t index);
|
||||
mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);
|
||||
mp_obj_t mp_obj_dict_delete(mp_obj_t self_in, mp_obj_t key);
|
||||
mp_obj_t mp_obj_dict_copy(mp_obj_t self_in);
|
||||
static inline mp_map_t *mp_obj_dict_get_map(mp_obj_t dict) {
|
||||
static MP_INLINE mp_map_t *mp_obj_dict_get_map(mp_obj_t dict) {
|
||||
return &((mp_obj_dict_t *)MP_OBJ_TO_PTR(dict))->map;
|
||||
}
|
||||
|
||||
|
@ -229,7 +229,7 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
|
||||
/******************************************************************************/
|
||||
/* dict methods */
|
||||
|
||||
STATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) {
|
||||
STATIC void PLACE_IN_ITCM(mp_ensure_not_fixed)(const mp_obj_dict_t * dict) {
|
||||
if (dict->map.is_fixed) {
|
||||
mp_raise_TypeError(NULL);
|
||||
}
|
||||
@ -643,7 +643,7 @@ size_t mp_obj_dict_len(mp_obj_t self_in) {
|
||||
return self->map.used;
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
|
||||
mp_obj_t PLACE_IN_ITCM(mp_obj_dict_store)(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
|
||||
mp_check_self(mp_obj_is_dict_or_ordereddict(self_in));
|
||||
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_ensure_not_fixed(self);
|
||||
|
14
py/objfun.c
14
py/objfun.c
@ -50,7 +50,7 @@
|
||||
/******************************************************************************/
|
||||
/* builtin functions */
|
||||
|
||||
STATIC mp_obj_t fun_builtin_0_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t PLACE_IN_ITCM(fun_builtin_0_call)(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
(void)args;
|
||||
assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_0));
|
||||
mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
@ -68,7 +68,7 @@ const mp_obj_type_t mp_type_fun_builtin_0 = {
|
||||
),
|
||||
};
|
||||
|
||||
STATIC mp_obj_t fun_builtin_1_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t PLACE_IN_ITCM(fun_builtin_1_call)(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_1));
|
||||
mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_arg_check_num(n_args, n_kw, 1, 1, false);
|
||||
@ -85,7 +85,7 @@ const mp_obj_type_t mp_type_fun_builtin_1 = {
|
||||
),
|
||||
};
|
||||
|
||||
STATIC mp_obj_t fun_builtin_2_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t PLACE_IN_ITCM(fun_builtin_2_call)(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_2));
|
||||
mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_arg_check_num(n_args, n_kw, 2, 2, false);
|
||||
@ -102,7 +102,7 @@ const mp_obj_type_t mp_type_fun_builtin_2 = {
|
||||
),
|
||||
};
|
||||
|
||||
STATIC mp_obj_t fun_builtin_3_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t PLACE_IN_ITCM(fun_builtin_3_call)(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_3));
|
||||
mp_obj_fun_builtin_fixed_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_arg_check_num(n_args, n_kw, 3, 3, false);
|
||||
@ -119,7 +119,7 @@ const mp_obj_type_t mp_type_fun_builtin_3 = {
|
||||
),
|
||||
};
|
||||
|
||||
STATIC mp_obj_t fun_builtin_var_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t PLACE_IN_ITCM(fun_builtin_var_call)(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
assert(mp_obj_is_type(self_in, &mp_type_fun_builtin_var));
|
||||
mp_obj_fun_builtin_var_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
|
||||
@ -418,7 +418,7 @@ mp_obj_t mp_obj_new_fun_bc(mp_obj_t def_args_in, mp_obj_t def_kw_args, const byt
|
||||
|
||||
#if MICROPY_EMIT_NATIVE
|
||||
|
||||
STATIC mp_obj_t fun_native_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t PLACE_IN_ITCM(fun_native_call)(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
MP_STACK_CHECK();
|
||||
mp_obj_fun_bc_t *self = self_in;
|
||||
mp_call_fun_t fun = MICROPY_MAKE_POINTER_CALLABLE((void *)self->bytecode);
|
||||
@ -505,7 +505,7 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) {
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t fun_asm_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
STATIC mp_obj_t PLACE_IN_ITCM(fun_asm_call)(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_obj_fun_asm_t *self = self_in;
|
||||
|
||||
mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
|
||||
|
@ -99,7 +99,7 @@ const mp_obj_type_t mp_type_property = {
|
||||
extern const mp_obj_property_t __property_getter_start, __property_getter_end, __property_getset_start, __property_getset_end;
|
||||
#endif
|
||||
|
||||
const mp_obj_t *mp_obj_property_get(mp_obj_t self_in, size_t *n_proxy) {
|
||||
const mp_obj_t *PLACE_IN_ITCM(mp_obj_property_get)(mp_obj_t self_in, size_t *n_proxy) {
|
||||
mp_check_self(mp_obj_is_type(self_in, &mp_type_property));
|
||||
mp_obj_property_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
#if MICROPY_PY_OPTIMIZE_PROPERTY_FLASH_SIZE
|
||||
|
@ -36,7 +36,7 @@ void mp_pystack_init(void *start, void *end) {
|
||||
MP_STATE_THREAD(pystack_cur) = start;
|
||||
}
|
||||
|
||||
void *mp_pystack_alloc(size_t n_bytes) {
|
||||
void *PLACE_IN_ITCM(mp_pystack_alloc)(size_t n_bytes) {
|
||||
n_bytes = (n_bytes + (MICROPY_PYSTACK_ALIGN - 1)) & ~(MICROPY_PYSTACK_ALIGN - 1);
|
||||
#if MP_PYSTACK_DEBUG
|
||||
n_bytes += MICROPY_PYSTACK_ALIGN;
|
||||
|
26
py/pystack.h
26
py/pystack.h
@ -41,7 +41,7 @@ void *mp_pystack_alloc(size_t n_bytes);
|
||||
// This function can free multiple continuous blocks at once: just pass the
|
||||
// pointer to the block that was allocated first and it and all subsequently
|
||||
// allocated blocks will be freed.
|
||||
static inline void mp_pystack_free(void *ptr) {
|
||||
static MP_INLINE void mp_pystack_free(void *ptr) {
|
||||
assert((uint8_t *)ptr >= MP_STATE_THREAD(pystack_start));
|
||||
assert((uint8_t *)ptr <= MP_STATE_THREAD(pystack_cur));
|
||||
#if MP_PYSTACK_DEBUG
|
||||
@ -59,16 +59,16 @@ static inline void mp_pystack_free(void *ptr) {
|
||||
MP_STATE_THREAD(pystack_cur) = (uint8_t *)ptr;
|
||||
}
|
||||
|
||||
static inline void mp_pystack_realloc(void *ptr, size_t n_bytes) {
|
||||
static MP_INLINE void mp_pystack_realloc(void *ptr, size_t n_bytes) {
|
||||
mp_pystack_free(ptr);
|
||||
mp_pystack_alloc(n_bytes);
|
||||
}
|
||||
|
||||
static inline size_t mp_pystack_usage(void) {
|
||||
static MP_INLINE size_t mp_pystack_usage(void) {
|
||||
return MP_STATE_THREAD(pystack_cur) - MP_STATE_THREAD(pystack_start);
|
||||
}
|
||||
|
||||
static inline size_t mp_pystack_limit(void) {
|
||||
static MP_INLINE size_t mp_pystack_limit(void) {
|
||||
return MP_STATE_THREAD(pystack_end) - MP_STATE_THREAD(pystack_start);
|
||||
}
|
||||
|
||||
@ -78,43 +78,43 @@ static inline size_t mp_pystack_limit(void) {
|
||||
|
||||
#define mp_local_alloc(n_bytes) alloca(n_bytes)
|
||||
|
||||
static inline void mp_local_free(void *ptr) {
|
||||
static MP_INLINE void mp_local_free(void *ptr) {
|
||||
(void)ptr;
|
||||
}
|
||||
|
||||
static inline void *mp_nonlocal_alloc(size_t n_bytes) {
|
||||
static MP_INLINE void *mp_nonlocal_alloc(size_t n_bytes) {
|
||||
return m_new(uint8_t, n_bytes);
|
||||
}
|
||||
|
||||
static inline void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) {
|
||||
static MP_INLINE void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) {
|
||||
return m_renew(uint8_t, ptr, old_n_bytes, new_n_bytes);
|
||||
}
|
||||
|
||||
static inline void mp_nonlocal_free(void *ptr, size_t n_bytes) {
|
||||
static MP_INLINE void mp_nonlocal_free(void *ptr, size_t n_bytes) {
|
||||
m_del(uint8_t, ptr, n_bytes);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline void *mp_local_alloc(size_t n_bytes) {
|
||||
static MP_INLINE void *mp_local_alloc(size_t n_bytes) {
|
||||
return mp_pystack_alloc(n_bytes);
|
||||
}
|
||||
|
||||
static inline void mp_local_free(void *ptr) {
|
||||
static MP_INLINE void mp_local_free(void *ptr) {
|
||||
mp_pystack_free(ptr);
|
||||
}
|
||||
|
||||
static inline void *mp_nonlocal_alloc(size_t n_bytes) {
|
||||
static MP_INLINE void *mp_nonlocal_alloc(size_t n_bytes) {
|
||||
return mp_pystack_alloc(n_bytes);
|
||||
}
|
||||
|
||||
static inline void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) {
|
||||
static MP_INLINE void *mp_nonlocal_realloc(void *ptr, size_t old_n_bytes, size_t new_n_bytes) {
|
||||
(void)old_n_bytes;
|
||||
mp_pystack_realloc(ptr, new_n_bytes);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline void mp_nonlocal_free(void *ptr, size_t n_bytes) {
|
||||
static MP_INLINE void mp_nonlocal_free(void *ptr, size_t n_bytes) {
|
||||
(void)n_bytes;
|
||||
mp_pystack_free(ptr);
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ void qstr_init(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC const char *find_qstr(qstr q, qstr_attr_t *attr) {
|
||||
STATIC const char *PLACE_IN_ITCM(find_qstr)(qstr q, qstr_attr_t *attr) {
|
||||
// search pool for this qstr
|
||||
// total_prev_len==0 in the final pool, so the loop will always terminate
|
||||
const qstr_pool_t *pool = MP_STATE_VM(last_pool);
|
||||
|
61
py/runtime.c
61
py/runtime.c
@ -1588,7 +1588,7 @@ mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_i
|
||||
|
||||
#endif // MICROPY_ENABLE_COMPILER
|
||||
|
||||
NORETURN void m_malloc_fail(size_t num_bytes) {
|
||||
NORETURN MP_COLD void m_malloc_fail(size_t num_bytes) {
|
||||
DEBUG_printf("memory allocation failed, allocating %u bytes\n", (uint)num_bytes);
|
||||
#if MICROPY_ENABLE_GC
|
||||
if (gc_is_locked()) {
|
||||
@ -1601,25 +1601,25 @@ NORETURN void m_malloc_fail(size_t num_bytes) {
|
||||
|
||||
#if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE
|
||||
|
||||
NORETURN void mp_raise_type(const mp_obj_type_t *exc_type) {
|
||||
NORETURN MP_COLD void mp_raise_type(const mp_obj_type_t *exc_type) {
|
||||
nlr_raise(mp_obj_new_exception(exc_type));
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_ValueError_no_msg(void) {
|
||||
NORETURN MP_COLD void mp_raise_ValueError_no_msg(void) {
|
||||
mp_raise_type(&mp_type_ValueError);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_TypeError_no_msg(void) {
|
||||
NORETURN MP_COLD void mp_raise_TypeError_no_msg(void) {
|
||||
mp_raise_type(&mp_type_TypeError);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_NotImplementedError_no_msg(void) {
|
||||
NORETURN MP_COLD void mp_raise_NotImplementedError_no_msg(void) {
|
||||
mp_raise_type(&mp_type_NotImplementedError);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg) {
|
||||
NORETURN MP_COLD void mp_raise_msg(const mp_obj_type_t *exc_type, const compressed_string_t *msg) {
|
||||
if (msg == NULL) {
|
||||
nlr_raise(mp_obj_new_exception(exc_type));
|
||||
} else {
|
||||
@ -1627,19 +1627,19 @@ NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const compressed_strin
|
||||
}
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_msg_vlist(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, va_list argptr) {
|
||||
NORETURN MP_COLD void mp_raise_msg_vlist(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, va_list argptr) {
|
||||
mp_obj_t exception = mp_obj_new_exception_msg_vlist(exc_type, fmt, argptr);
|
||||
nlr_raise(exception);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, ...) {
|
||||
NORETURN MP_COLD void mp_raise_msg_varg(const mp_obj_type_t *exc_type, const compressed_string_t *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr,fmt);
|
||||
mp_raise_msg_vlist(exc_type, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char *msg) {
|
||||
NORETURN MP_COLD void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char *msg) {
|
||||
if (msg == NULL) {
|
||||
nlr_raise(mp_obj_new_exception(exc_type));
|
||||
} else {
|
||||
@ -1647,56 +1647,56 @@ NORETURN void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char *msg) {
|
||||
}
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_AttributeError(const compressed_string_t *msg) {
|
||||
NORETURN MP_COLD void mp_raise_AttributeError(const compressed_string_t *msg) {
|
||||
mp_raise_msg(&mp_type_AttributeError, msg);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_RuntimeError(const compressed_string_t *msg) {
|
||||
NORETURN MP_COLD void mp_raise_RuntimeError(const compressed_string_t *msg) {
|
||||
mp_raise_msg(&mp_type_RuntimeError, msg);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_ImportError(const compressed_string_t *msg) {
|
||||
NORETURN MP_COLD void mp_raise_ImportError(const compressed_string_t *msg) {
|
||||
mp_raise_msg(&mp_type_ImportError, msg);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_IndexError(const compressed_string_t *msg) {
|
||||
NORETURN MP_COLD void mp_raise_IndexError(const compressed_string_t *msg) {
|
||||
mp_raise_msg(&mp_type_IndexError, msg);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_IndexError_varg(const compressed_string_t *fmt, ...) {
|
||||
NORETURN MP_COLD void mp_raise_IndexError_varg(const compressed_string_t *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr,fmt);
|
||||
mp_raise_msg_vlist(&mp_type_IndexError, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_ValueError(const compressed_string_t *msg) {
|
||||
NORETURN MP_COLD void mp_raise_ValueError(const compressed_string_t *msg) {
|
||||
mp_raise_msg(&mp_type_ValueError, msg);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_ValueError_varg(const compressed_string_t *fmt, ...) {
|
||||
NORETURN MP_COLD void mp_raise_ValueError_varg(const compressed_string_t *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr,fmt);
|
||||
mp_raise_msg_vlist(&mp_type_ValueError, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_TypeError(const compressed_string_t *msg) {
|
||||
NORETURN MP_COLD void mp_raise_TypeError(const compressed_string_t *msg) {
|
||||
mp_raise_msg(&mp_type_TypeError, msg);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_TypeError_varg(const compressed_string_t *fmt, ...) {
|
||||
NORETURN MP_COLD void mp_raise_TypeError_varg(const compressed_string_t *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr,fmt);
|
||||
mp_raise_msg_vlist(&mp_type_TypeError, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_OSError_msg(const compressed_string_t *msg) {
|
||||
NORETURN MP_COLD void mp_raise_OSError_msg(const compressed_string_t *msg) {
|
||||
mp_raise_msg(&mp_type_OSError, msg);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str) {
|
||||
NORETURN MP_COLD void mp_raise_OSError_errno_str(int errno_, mp_obj_t str) {
|
||||
mp_obj_t args[2] = {
|
||||
MP_OBJ_NEW_SMALL_INT(errno_),
|
||||
str,
|
||||
@ -1704,26 +1704,26 @@ NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str) {
|
||||
nlr_raise(mp_obj_new_exception_args(&mp_type_OSError, 2, args));
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_OSError_msg_varg(const compressed_string_t *fmt, ...) {
|
||||
NORETURN MP_COLD void mp_raise_OSError_msg_varg(const compressed_string_t *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr,fmt);
|
||||
mp_raise_msg_vlist(&mp_type_OSError, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_ConnectionError(const compressed_string_t *msg) {
|
||||
NORETURN MP_COLD void mp_raise_ConnectionError(const compressed_string_t *msg) {
|
||||
mp_raise_msg(&mp_type_ConnectionError, msg);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_BrokenPipeError(void) {
|
||||
NORETURN MP_COLD void mp_raise_BrokenPipeError(void) {
|
||||
mp_raise_type_arg(&mp_type_BrokenPipeError, MP_OBJ_NEW_SMALL_INT(MP_EPIPE));
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_NotImplementedError(const compressed_string_t *msg) {
|
||||
NORETURN MP_COLD void mp_raise_NotImplementedError(const compressed_string_t *msg) {
|
||||
mp_raise_msg(&mp_type_NotImplementedError, msg);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_NotImplementedError_varg(const compressed_string_t *fmt, ...) {
|
||||
NORETURN MP_COLD void mp_raise_NotImplementedError_varg(const compressed_string_t *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr,fmt);
|
||||
mp_raise_msg_vlist(&mp_type_NotImplementedError, fmt, argptr);
|
||||
@ -1731,17 +1731,18 @@ NORETURN void mp_raise_NotImplementedError_varg(const compressed_string_t *fmt,
|
||||
}
|
||||
|
||||
|
||||
NORETURN void mp_raise_OverflowError_varg(const compressed_string_t *fmt, ...) {
|
||||
NORETURN MP_COLD void mp_raise_OverflowError_varg(const compressed_string_t *fmt, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr,fmt);
|
||||
mp_raise_msg_vlist(&mp_type_OverflowError, fmt, argptr);
|
||||
va_end(argptr);
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg) {
|
||||
NORETURN MP_COLD void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg) {
|
||||
nlr_raise(mp_obj_new_exception_arg1(exc_type, arg));
|
||||
}
|
||||
|
||||
// Leave this as not COLD because it is used by iterators in normal execution.
|
||||
NORETURN void mp_raise_StopIteration(mp_obj_t arg) {
|
||||
if (arg == MP_OBJ_NULL) {
|
||||
mp_raise_type(&mp_type_StopIteration);
|
||||
@ -1750,18 +1751,18 @@ NORETURN void mp_raise_StopIteration(mp_obj_t arg) {
|
||||
}
|
||||
}
|
||||
|
||||
NORETURN void mp_raise_OSError(int errno_) {
|
||||
NORETURN MP_COLD void mp_raise_OSError(int errno_) {
|
||||
mp_raise_type_arg(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK
|
||||
NORETURN void mp_raise_recursion_depth(void) {
|
||||
NORETURN MP_COLD void mp_raise_recursion_depth(void) {
|
||||
mp_raise_RuntimeError(MP_ERROR_TEXT("maximum recursion depth exceeded"));
|
||||
}
|
||||
#endif
|
||||
|
||||
NORETURN void mp_raise_ZeroDivisionError(void) {
|
||||
NORETURN MP_COLD void mp_raise_ZeroDivisionError(void) {
|
||||
mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("division by zero"));
|
||||
}
|
||||
|
12
py/runtime.h
12
py/runtime.h
@ -86,7 +86,7 @@ bool mp_sched_schedule(mp_obj_t function, mp_obj_t arg);
|
||||
int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec);
|
||||
|
||||
void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig);
|
||||
static inline void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw) {
|
||||
static MP_INLINE void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw) {
|
||||
mp_arg_check_num_sig(n_args, n_kw, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, takes_kw));
|
||||
}
|
||||
void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals);
|
||||
@ -115,16 +115,16 @@ mp_obj_t mp_arg_validate_type_or_none(mp_obj_t obj, const mp_obj_type_t *type, q
|
||||
mp_int_t mp_arg_validate_type_int(mp_obj_t obj, qstr arg_name);
|
||||
mp_obj_t mp_arg_validate_type_string(mp_obj_t obj, qstr arg_name);
|
||||
|
||||
static inline mp_obj_dict_t *PLACE_IN_ITCM(mp_locals_get)(void) {
|
||||
static MP_INLINE mp_obj_dict_t *mp_locals_get(void) {
|
||||
return MP_STATE_THREAD(dict_locals);
|
||||
}
|
||||
static inline void PLACE_IN_ITCM(mp_locals_set)(mp_obj_dict_t * d) {
|
||||
static MP_INLINE void mp_locals_set(mp_obj_dict_t *d) {
|
||||
MP_STATE_THREAD(dict_locals) = d;
|
||||
}
|
||||
static inline mp_obj_dict_t *PLACE_IN_ITCM(mp_globals_get)(void) {
|
||||
static MP_INLINE mp_obj_dict_t *mp_globals_get(void) {
|
||||
return MP_STATE_THREAD(dict_globals);
|
||||
}
|
||||
static inline void PLACE_IN_ITCM(mp_globals_set)(mp_obj_dict_t * d) {
|
||||
static MP_INLINE void mp_globals_set(mp_obj_dict_t *d) {
|
||||
MP_STATE_THREAD(dict_globals) = d;
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ mp_obj_t mp_iternext_allow_raise(mp_obj_t o); // may return MP_OBJ_STOP_ITERATIO
|
||||
mp_obj_t mp_iternext(mp_obj_t o); // will always return MP_OBJ_STOP_ITERATION instead of raising StopIteration(...)
|
||||
mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val);
|
||||
|
||||
static inline mp_obj_t mp_make_stop_iteration(mp_obj_t o) {
|
||||
static MP_INLINE mp_obj_t mp_make_stop_iteration(mp_obj_t o) {
|
||||
MP_STATE_THREAD(stop_iteration_arg) = o;
|
||||
return MP_OBJ_STOP_ITERATION;
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ void mp_stack_set_top(void *top) {
|
||||
MP_STATE_THREAD(stack_top) = top;
|
||||
}
|
||||
|
||||
mp_uint_t mp_stack_usage(void) {
|
||||
mp_uint_t PLACE_IN_ITCM(mp_stack_usage)(void) {
|
||||
// Assumes descending stack
|
||||
// Force routine to not be inlined. Better guarantee than MP_NOINLINE for -flto.
|
||||
__asm volatile ("");
|
||||
@ -52,7 +52,7 @@ void mp_stack_set_limit(mp_uint_t limit) {
|
||||
MP_STATE_THREAD(stack_limit) = limit;
|
||||
}
|
||||
|
||||
void mp_stack_check(void) {
|
||||
void PLACE_IN_ITCM(mp_stack_check)(void) {
|
||||
if (mp_stack_usage() >= MP_STATE_THREAD(stack_limit)) {
|
||||
mp_raise_recursion_depth();
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ STATIC mp_obj_t digitalio_digitalinout_obj___exit__(size_t n_args, const mp_obj_
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(digitalio_digitalinout_obj___exit___obj, 4, 4, digitalio_digitalinout_obj___exit__);
|
||||
|
||||
STATIC void check_for_deinit(digitalio_digitalinout_obj_t *self) {
|
||||
STATIC inline void check_for_deinit(digitalio_digitalinout_obj_t *self) {
|
||||
if (common_hal_digitalio_digitalinout_deinited(self)) {
|
||||
raise_deinited_error();
|
||||
}
|
||||
|
@ -127,6 +127,7 @@ static bool usb_drive_set_enabled(bool enabled) {
|
||||
if (tud_connected()) {
|
||||
return false;
|
||||
}
|
||||
filesystem_set_internal_writable_by_usb(enabled);
|
||||
storage_usb_is_enabled = enabled;
|
||||
return true;
|
||||
}
|
||||
|
@ -32,7 +32,8 @@
|
||||
#if defined(IMXRT10XX) || defined(FOMU) || defined(STM32H7) || defined(RASPBERRYPI)
|
||||
#define PLACE_IN_DTCM_DATA(name) name __attribute__((section(".dtcm_data." #name)))
|
||||
#define PLACE_IN_DTCM_BSS(name) name __attribute__((section(".dtcm_bss." #name)))
|
||||
#define PLACE_IN_ITCM(name) __attribute__((section(".itcm." #name))) name
|
||||
// Don't inline ITCM functions because that may pull them out of ITCM into other sections.
|
||||
#define PLACE_IN_ITCM(name) __attribute__((section(".itcm." #name),noinline,aligned(4))) name
|
||||
#else
|
||||
#define PLACE_IN_DTCM_DATA(name) name
|
||||
#define PLACE_IN_DTCM_BSS(name) name
|
||||
|
@ -42,7 +42,7 @@ STATIC volatile background_callback_t *volatile callback_head, *volatile callbac
|
||||
MP_WEAK void port_wake_main_task(void) {
|
||||
}
|
||||
|
||||
void background_callback_add_core(background_callback_t *cb) {
|
||||
void PLACE_IN_ITCM(background_callback_add_core)(background_callback_t * cb) {
|
||||
CALLBACK_CRITICAL_BEGIN;
|
||||
if (cb->prev || callback_head == cb) {
|
||||
CALLBACK_CRITICAL_END;
|
||||
@ -62,13 +62,13 @@ void background_callback_add_core(background_callback_t *cb) {
|
||||
port_wake_main_task();
|
||||
}
|
||||
|
||||
void background_callback_add(background_callback_t *cb, background_callback_fun fun, void *data) {
|
||||
void PLACE_IN_ITCM(background_callback_add)(background_callback_t * cb, background_callback_fun fun, void *data) {
|
||||
cb->fun = fun;
|
||||
cb->data = data;
|
||||
background_callback_add_core(cb);
|
||||
}
|
||||
|
||||
bool PLACE_IN_ITCM(background_callback_pending)(void) {
|
||||
bool inline background_callback_pending(void) {
|
||||
return callback_head != NULL;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "py/mpstate.h"
|
||||
|
||||
#include "supervisor/flash.h"
|
||||
#include "supervisor/linker.h"
|
||||
|
||||
static mp_vfs_mount_t _mp_vfs;
|
||||
static fs_user_mount_t _internal_vfs;
|
||||
@ -165,7 +166,7 @@ bool filesystem_init(bool create_allowed, bool force_create) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void filesystem_flush(void) {
|
||||
void PLACE_IN_ITCM(filesystem_flush)(void) {
|
||||
// Reset interval before next flush.
|
||||
filesystem_flush_interval_ms = CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS;
|
||||
supervisor_flash_flush();
|
||||
|
@ -132,7 +132,7 @@ static mp_uint_t flash_write_blocks(const uint8_t *src, uint32_t block_num, uint
|
||||
}
|
||||
}
|
||||
|
||||
void supervisor_flash_flush(void) {
|
||||
void PLACE_IN_ITCM(supervisor_flash_flush)(void) {
|
||||
#if INTERNAL_FLASH_FILESYSTEM
|
||||
port_internal_flash_flush();
|
||||
#else
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "shared-bindings/microcontroller/Processor.h"
|
||||
#include "shared-bindings/microcontroller/ResetReason.h"
|
||||
|
||||
#include "supervisor/linker.h"
|
||||
#include "supervisor/serial.h"
|
||||
#include "supervisor/shared/rgb_led_colors.h"
|
||||
#include "supervisor/shared/status_leds.h"
|
||||
@ -121,12 +122,12 @@ safe_mode_t wait_for_safe_mode_reset(void) {
|
||||
return SAFE_MODE_NONE;
|
||||
}
|
||||
|
||||
void safe_mode_on_next_reset(safe_mode_t reason) {
|
||||
void PLACE_IN_ITCM(safe_mode_on_next_reset)(safe_mode_t reason) {
|
||||
port_set_saved_word(SAFE_MODE_DATA_GUARD | (reason << 8));
|
||||
}
|
||||
|
||||
// Don't inline this so it's easy to break on it from GDB.
|
||||
void __attribute__((noinline,)) reset_into_safe_mode(safe_mode_t reason) {
|
||||
void __attribute__((noinline,)) PLACE_IN_ITCM(reset_into_safe_mode)(safe_mode_t reason) {
|
||||
if (_safe_mode > SAFE_MODE_BROWNOUT && reason > SAFE_MODE_BROWNOUT) {
|
||||
while (true) {
|
||||
// This very bad because it means running in safe mode didn't save us. Only ignore brownout
|
||||
|
@ -78,8 +78,8 @@ void supervisor_status_bar_update(void) {
|
||||
!shared_module_supervisor_status_bar_get_display(&shared_module_supervisor_status_bar_obj);
|
||||
|
||||
// Suppress writes to console and/or display if status bar is not enabled for either or both.
|
||||
bool prev_console_disable;
|
||||
bool prev_display_disable;
|
||||
bool prev_console_disable = false;
|
||||
bool prev_display_disable = false;
|
||||
|
||||
if (disable_console_writes) {
|
||||
prev_console_disable = serial_console_write_disable(true);
|
||||
|
@ -48,7 +48,9 @@ inline
|
||||
#if !CIRCUITPY_LTO || CIRCUITPY_DEBUG < 1
|
||||
__attribute__((always_inline))
|
||||
#endif
|
||||
const compressed_string_t *translate(const char *original) {
|
||||
// Prevent instrumenting this because that disables the inlining we rely of for code size
|
||||
// optimization.
|
||||
__attribute__((no_instrument_function)) const compressed_string_t *translate(const char *original) {
|
||||
#ifndef NO_QSTR
|
||||
#define QDEF(id, hash, len, str)
|
||||
#define TRANSLATION(english_id, number) if (strcmp(original, english_id) == 0) { return &translation##number; } else
|
||||
|
@ -220,11 +220,11 @@ static void usb_background_do(void *unused) {
|
||||
usb_background();
|
||||
}
|
||||
|
||||
void usb_background_schedule(void) {
|
||||
void PLACE_IN_ITCM(usb_background_schedule)(void) {
|
||||
background_callback_add(&usb_callback, usb_background_do, NULL);
|
||||
}
|
||||
|
||||
void usb_irq_handler(int instance) {
|
||||
void PLACE_IN_ITCM(usb_irq_handler)(int instance) {
|
||||
#if CFG_TUSB_MCU != OPT_MCU_RP2040
|
||||
// For rp2040, IRQ handler is already installed and invoked automatically
|
||||
if (instance == CIRCUITPY_USB_DEVICE_INSTANCE) {
|
||||
|
@ -4,7 +4,7 @@ def bm_run(N, M):
|
||||
except ImportError:
|
||||
import time
|
||||
|
||||
ticks_us = lambda: int(time.perf_counter() * 1000000)
|
||||
ticks_us = lambda: int(time.monotonic_ns() // 1000)
|
||||
ticks_diff = lambda a, b: a - b
|
||||
|
||||
# Pick sensible parameters given N, M
|
||||
|
@ -7,8 +7,12 @@
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import argparse
|
||||
from glob import glob
|
||||
from rich.live import Live
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
sys.path.append("../tools")
|
||||
import pyboard
|
||||
@ -37,7 +41,7 @@ def compute_stats(lst):
|
||||
return avg, var**0.5
|
||||
|
||||
|
||||
def run_script_on_target(target, script):
|
||||
def run_script_on_target(target, script, run_command=None):
|
||||
output = b""
|
||||
err = None
|
||||
|
||||
@ -45,50 +49,72 @@ def run_script_on_target(target, script):
|
||||
# Run via pyboard interface
|
||||
try:
|
||||
target.enter_raw_repl()
|
||||
start_ts = time.monotonic_ns()
|
||||
output = target.exec_(script)
|
||||
if run_command:
|
||||
start_ts = time.monotonic_ns()
|
||||
output = target.exec_(run_command)
|
||||
end_ts = time.monotonic_ns()
|
||||
except pyboard.PyboardError as er:
|
||||
end_ts = time.monotonic_ns()
|
||||
err = er
|
||||
finally:
|
||||
target.exit_raw_repl()
|
||||
else:
|
||||
# Run local executable
|
||||
try:
|
||||
if run_command:
|
||||
script += run_command
|
||||
start_ts = time.monotonic_ns()
|
||||
p = subprocess.run(
|
||||
target, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, input=script
|
||||
)
|
||||
end_ts = time.monotonic_ns()
|
||||
output = p.stdout
|
||||
except subprocess.CalledProcessError as er:
|
||||
end_ts = time.monotonic_ns()
|
||||
err = er
|
||||
|
||||
return str(output.strip(), "ascii"), err
|
||||
return str(output.strip(), "ascii"), err, (end_ts - start_ts) // 1000
|
||||
|
||||
|
||||
def run_feature_test(target, test):
|
||||
with open("feature_check/" + test + ".py", "rb") as f:
|
||||
script = f.read()
|
||||
output, err = run_script_on_target(target, script)
|
||||
output, err, _ = run_script_on_target(target, script)
|
||||
if err is None:
|
||||
return output
|
||||
else:
|
||||
return "CRASH: %r" % err
|
||||
|
||||
|
||||
def run_benchmark_on_target(target, script):
|
||||
output, err = run_script_on_target(target, script)
|
||||
def run_benchmark_on_target(target, script, run_command=None):
|
||||
output, err, runtime_us = run_script_on_target(target, script, run_command)
|
||||
if err is None:
|
||||
time, norm, result = output.split(None, 2)
|
||||
try:
|
||||
return int(time), int(norm), result
|
||||
return int(time), int(norm), result, runtime_us
|
||||
except ValueError:
|
||||
return -1, -1, "CRASH: %r" % output
|
||||
return -1, -1, "CRASH: %r" % output, runtime_us
|
||||
else:
|
||||
return -1, -1, "CRASH: %r" % err
|
||||
return -1, -1, "CRASH: %r" % err, runtime_us
|
||||
|
||||
|
||||
def run_benchmarks(target, param_n, param_m, n_average, test_list):
|
||||
def run_benchmarks(console, target, param_n, param_m, n_average, test_list):
|
||||
skip_complex = run_feature_test(target, "complex") != "complex"
|
||||
skip_native = run_feature_test(target, "native_check") != "native"
|
||||
|
||||
table = Table(show_header=True)
|
||||
table.add_column("Test")
|
||||
table.add_column("Time", justify="right")
|
||||
table.add_column("Score", justify="right")
|
||||
table.add_column("Ref Time", justify="right")
|
||||
|
||||
live = Live(table, console=console)
|
||||
live.start()
|
||||
|
||||
for test_file in sorted(test_list):
|
||||
print(test_file + ": ", end="")
|
||||
# print(test_file + ": ", end="")
|
||||
|
||||
# Check if test should be skipped
|
||||
skip = (
|
||||
@ -99,6 +125,7 @@ def run_benchmarks(target, param_n, param_m, n_average, test_list):
|
||||
)
|
||||
if skip:
|
||||
print("skip")
|
||||
table.add_row(test_file, *(["skip"] * 6))
|
||||
continue
|
||||
|
||||
# Create test script
|
||||
@ -106,7 +133,7 @@ def run_benchmarks(target, param_n, param_m, n_average, test_list):
|
||||
test_script = f.read()
|
||||
with open(BENCH_SCRIPT_DIR + "benchrun.py", "rb") as f:
|
||||
test_script += f.read()
|
||||
test_script += b"bm_run(%u, %u)\n" % (param_n, param_m)
|
||||
bm_run = b"bm_run(%u, %u)\n" % (param_n, param_m)
|
||||
|
||||
# Write full test script if needed
|
||||
if 0:
|
||||
@ -115,12 +142,15 @@ def run_benchmarks(target, param_n, param_m, n_average, test_list):
|
||||
|
||||
# Run MicroPython a given number of times
|
||||
times = []
|
||||
runtimes = []
|
||||
scores = []
|
||||
error = None
|
||||
result_out = None
|
||||
for _ in range(n_average):
|
||||
time, norm, result = run_benchmark_on_target(target, test_script)
|
||||
if time < 0 or norm < 0:
|
||||
self_time, norm, result, runtime_us = run_benchmark_on_target(
|
||||
target, test_script, bm_run
|
||||
)
|
||||
if self_time < 0 or norm < 0:
|
||||
error = result
|
||||
break
|
||||
if result_out is None:
|
||||
@ -128,30 +158,43 @@ def run_benchmarks(target, param_n, param_m, n_average, test_list):
|
||||
elif result != result_out:
|
||||
error = "FAIL self"
|
||||
break
|
||||
times.append(time)
|
||||
scores.append(1e6 * norm / time)
|
||||
times.append(self_time)
|
||||
runtimes.append(runtime_us)
|
||||
scores.append(1e6 * norm / self_time)
|
||||
|
||||
# Check result against truth if needed
|
||||
if error is None and result_out != "None":
|
||||
_, _, result_exp = run_benchmark_on_target(PYTHON_TRUTH, test_script)
|
||||
_, _, result_exp, _ = run_benchmark_on_target(PYTHON_TRUTH, test_script, bm_run)
|
||||
if result_out != result_exp:
|
||||
error = "FAIL truth"
|
||||
|
||||
if error is not None:
|
||||
print(error)
|
||||
print(test_file, error)
|
||||
if error == "no matching params":
|
||||
table.add_row(test_file, *([None] * 3))
|
||||
else:
|
||||
table.add_row(test_file, *(["error"] * 3))
|
||||
else:
|
||||
t_avg, t_sd = compute_stats(times)
|
||||
r_avg, r_sd = compute_stats(runtimes)
|
||||
s_avg, s_sd = compute_stats(scores)
|
||||
print(
|
||||
"{:.2f} {:.4f} {:.2f} {:.4f}".format(
|
||||
t_avg, 100 * t_sd / t_avg, s_avg, 100 * s_sd / s_avg
|
||||
)
|
||||
# print(
|
||||
# "{:.2f} {:.4f} {:.2f} {:.4f} {:.2f} {:.4f}".format(
|
||||
# t_avg, 100 * t_sd / t_avg, s_avg, 100 * s_sd / s_avg, r_avg, 100 * r_sd / r_avg
|
||||
# )
|
||||
# )
|
||||
table.add_row(
|
||||
test_file,
|
||||
f"{t_avg:.2f}±{100 * t_sd / t_avg:.1f}%",
|
||||
f"{s_avg:.2f}±{100 * s_sd / s_avg:.1f}%",
|
||||
f"{r_avg:.2f}±{100 * r_sd / r_avg:.1f}%",
|
||||
)
|
||||
if 0:
|
||||
print(" times: ", times)
|
||||
print(" scores:", scores)
|
||||
|
||||
sys.stdout.flush()
|
||||
live.update(table, refresh=True)
|
||||
live.stop()
|
||||
|
||||
|
||||
def parse_output(filename):
|
||||
@ -268,9 +311,10 @@ def main():
|
||||
else:
|
||||
tests = sorted(args.files)
|
||||
|
||||
console = Console()
|
||||
print("N={} M={} n_average={}".format(N, M, n_average))
|
||||
|
||||
run_benchmarks(target, N, M, n_average, tests)
|
||||
run_benchmarks(console, target, N, M, n_average, tests)
|
||||
|
||||
if isinstance(target, pyboard.Pyboard):
|
||||
target.exit_raw_repl()
|
||||
|
106
tools/cortex-m-fault-gdb.py
Normal file
106
tools/cortex-m-fault-gdb.py
Normal file
@ -0,0 +1,106 @@
|
||||
"""Source this file into gdb `source ../../tools/cortex-m-fault-gdb.py` then run
|
||||
`cortex-m-fault` to print basic info about the fault registers."""
|
||||
|
||||
SCS = 0xE000E000
|
||||
SCB = SCS + 0x0D00
|
||||
CPUID = SCB + 0x000 # (R/ ) CPUID Base Register */
|
||||
ICSR = SCB + 0x004 # (R/W) Interrupt Control and State Register */
|
||||
VTOR = SCB + 0x008 # (R/W) Vector Table Offset Register */
|
||||
AIRCR = SCB + 0x00C # (R/W) Application Interrupt and Reset Control Register */
|
||||
SCR = SCB + 0x010 # (R/W) System Control Register */
|
||||
CCR = SCB + 0x014 # (R/W) Configuration Control Register */
|
||||
SHCSR = SCB + 0x024 # (R/W) System Handler Control and State Register */
|
||||
CFSR = SCB + 0x028 # (R/W) Configurable Fault Status Register */
|
||||
HFSR = SCB + 0x02C # (R/W) HardFault Status Register */
|
||||
DFSR = SCB + 0x030 # (R/W) Debug Fault Status Register */
|
||||
MMFAR = SCB + 0x034 # (R/W) MemManage Fault Address Register */
|
||||
BFAR = SCB + 0x038 # (R/W) BusFault Address Register */
|
||||
AFSR = SCB + 0x03C # (R/W) Auxiliary Fault Status Register */
|
||||
|
||||
PARTS = {0xC27: "Cortex M7"}
|
||||
|
||||
EXCEPTIONS = {
|
||||
0: "Thread mode",
|
||||
2: "Non Maskable Interrupt",
|
||||
3: "Hard Fault",
|
||||
4: "MemManage Fault",
|
||||
5: "Bus Fault",
|
||||
6: "Usage Fault",
|
||||
11: "SVCAll",
|
||||
14: "PendSV",
|
||||
15: "SysTick",
|
||||
}
|
||||
|
||||
|
||||
class CortexMFault(gdb.Command):
|
||||
def __init__(self):
|
||||
super(CortexMFault, self).__init__("cortex-m-fault", gdb.COMMAND_USER)
|
||||
|
||||
def _read(self, address):
|
||||
i = gdb.selected_inferior()
|
||||
return i.read_memory(address, 4).cast("I")[0]
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
cpuid = self._read(CPUID)
|
||||
implementer = cpuid >> 24
|
||||
if implementer != 0x41:
|
||||
raise RuntimeError()
|
||||
variant = (cpuid >> 20) & 0xF
|
||||
constant = (cpuid >> 16) & 0xF
|
||||
if constant != 0xF:
|
||||
raise RuntimeError()
|
||||
revision = cpuid & 0xF
|
||||
part_no = (cpuid >> 4) & 0xFFF
|
||||
print(PARTS[part_no])
|
||||
icsr = self._read(ICSR)
|
||||
if (icsr & (1 << 11)) != 0:
|
||||
print("No preempted exceptions")
|
||||
else:
|
||||
print("Another exception was preempted")
|
||||
vectactive = icsr & 0x1FF
|
||||
if vectactive != 0:
|
||||
if vectactive in EXCEPTIONS:
|
||||
print(EXCEPTIONS[vectactive])
|
||||
else:
|
||||
print(vectactive - 16)
|
||||
|
||||
vtor = self._read(VTOR)
|
||||
# print(hex(self._read(SHCSR)))
|
||||
cfsr = self._read(CFSR)
|
||||
ufsr = cfsr >> 16
|
||||
bfsr = (cfsr >> 8) & 0xFF
|
||||
mmfsr = cfsr & 0xFF
|
||||
print("ufsr", hex(ufsr), "bfsr", hex(bfsr), "mmfsr", hex(mmfsr))
|
||||
if (bfsr & (1 << 7)) != 0:
|
||||
print("Bad address", hex(self._read(BFAR)))
|
||||
if (bfsr & (1 << 3)) != 0:
|
||||
print("Unstacking from exception error")
|
||||
if (bfsr & (1 << 2)) != 0:
|
||||
print("Imprecise data bus error")
|
||||
if (bfsr & (1 << 1)) != 0:
|
||||
print("Precise data bus error")
|
||||
if (bfsr & (1 << 0)) != 0:
|
||||
print("Instruction bus error")
|
||||
|
||||
if (mmfsr & (1 << 7)) != 0:
|
||||
print("Bad address", hex(self._read(MMFAR)))
|
||||
if (mmfsr & (1 << 3)) != 0:
|
||||
print("Unstacking from exception error")
|
||||
if (mmfsr & (1 << 1)) != 0:
|
||||
print("Data access violation")
|
||||
if (mmfsr & (1 << 0)) != 0:
|
||||
print("Instruction access violation")
|
||||
|
||||
if (ufsr & (1 << 8)) != 0:
|
||||
print("Unaligned access")
|
||||
if (ufsr & (1 << 0)) != 0:
|
||||
print("Undefined instruction")
|
||||
hfsr = self._read(HFSR)
|
||||
if (hfsr & (1 << 30)) != 0:
|
||||
print("Forced hard fault")
|
||||
if (hfsr & (1 << 1)) != 0:
|
||||
print("Bus fault when reading vector table")
|
||||
print("VTOR", hex(vtor))
|
||||
|
||||
|
||||
CortexMFault()
|
@ -9,6 +9,7 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import serial
|
||||
import sys
|
||||
@ -80,6 +81,7 @@ class REPL:
|
||||
else:
|
||||
timeout_count += 1
|
||||
if timeout is not None and timeout_count >= 100 * timeout:
|
||||
print("timeout")
|
||||
raise TimeoutError(110, "timeout waiting for", ending)
|
||||
time.sleep(0.01)
|
||||
return data
|
||||
@ -93,16 +95,18 @@ class REPL:
|
||||
for i in range(0, len(data), chunk_size):
|
||||
chunk = data[i : min(i + chunk_size, len(data))]
|
||||
self.session += chunk
|
||||
self.serial.write(chunk)
|
||||
c = self.serial.write(chunk)
|
||||
if c < len(chunk):
|
||||
raise RuntimeError()
|
||||
time.sleep(0.01)
|
||||
|
||||
def reset(self):
|
||||
# Use read() since serial.reset_input_buffer() fails with termios.error now and then
|
||||
self.read()
|
||||
self.session = b""
|
||||
self.write(b"\r" + REPL.CHAR_CTRL_C + REPL.CHAR_CTRL_C) # interrupt any running program
|
||||
self.write(REPL.CHAR_CTRL_C + REPL.CHAR_CTRL_C) # interrupt any running program
|
||||
self.write(b"\r" + REPL.CHAR_CTRL_B) # enter or reset friendly repl
|
||||
data = self.read_until(b">>> ")
|
||||
self.read_until(b">>> ", timeout=60)
|
||||
|
||||
def execute(self, code, timeout=10, wait_for_response=True):
|
||||
self.read() # Throw away
|
||||
@ -161,7 +165,10 @@ class Disk:
|
||||
self._path = mount[0][1]
|
||||
else:
|
||||
name = os.path.basename(dev)
|
||||
sh.pmount("-tvfat", dev, name, _timeout=10)
|
||||
try:
|
||||
sh.pmount("-tvfat", dev, name, _timeout=10)
|
||||
except sh.CommandNotFound:
|
||||
raise ValueError()
|
||||
self.mountpoint = "/media/" + name
|
||||
self._path = self.mountpoint
|
||||
|
||||
@ -347,7 +354,7 @@ class CPboard:
|
||||
return cls(dev, baudrate=baudrate, wait=wait, timeout=timeout)
|
||||
|
||||
def __init__(self, device, baudrate=115200, wait=0, timeout=10):
|
||||
self.device = device
|
||||
self.device = str(pathlib.Path(device).resolve())
|
||||
self.usb_dev = None
|
||||
try:
|
||||
# Is it a usb.core.Device?
|
||||
@ -357,7 +364,7 @@ class CPboard:
|
||||
else:
|
||||
serials = [serial for serial in os.listdir("/dev/serial/by-path") if portstr in serial]
|
||||
if len(serials) != 1:
|
||||
raise RuntimeError("Can't find excatly one matching usb serial device")
|
||||
raise RuntimeError("Can't find exactly one matching usb serial device")
|
||||
self.device = os.path.realpath("/dev/serial/by-path/" + serials[0])
|
||||
self.usb_dev = device
|
||||
|
||||
@ -370,6 +377,10 @@ class CPboard:
|
||||
self.bootloader = False
|
||||
self.repl = REPL(self)
|
||||
|
||||
# Disable autoreload so that file copies won't mess us up.
|
||||
with self:
|
||||
self.exec("import supervisor;supervisor.runtime.autoreload = False")
|
||||
|
||||
def __enter__(self):
|
||||
self.open()
|
||||
return self
|
||||
@ -507,9 +518,12 @@ class CPboard:
|
||||
|
||||
part = [part for part in disks if "part1" in part]
|
||||
if not part:
|
||||
raise RuntimeError("Disk not found for: " + self.device)
|
||||
return None
|
||||
|
||||
return Disk(part[0])
|
||||
try:
|
||||
return Disk(part[0])
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
@property
|
||||
def firmware(self):
|
||||
@ -548,18 +562,33 @@ PyboardError = CPboardError
|
||||
class Pyboard:
|
||||
def __init__(self, device, baudrate=115200, user="micro", password="python", wait=0):
|
||||
self.board = CPboard.from_try_all(device, baudrate=baudrate, wait=wait)
|
||||
with self.board.disk as disk:
|
||||
disk.copy("skip_if.py")
|
||||
disk = self.board.disk
|
||||
if disk:
|
||||
with disk as open_disk:
|
||||
open_disk.copy("skip_if.py")
|
||||
|
||||
def close(self):
|
||||
self.board.close()
|
||||
|
||||
def enter_raw_repl(self):
|
||||
self.board.open()
|
||||
self.board.repl.reset()
|
||||
|
||||
def exit_raw_repl(self):
|
||||
self.close()
|
||||
|
||||
def execfile(self, filename):
|
||||
return self.board.execfile(filename)
|
||||
|
||||
def exec_(self, command, data_consumer=None):
|
||||
try:
|
||||
output, error = self.board.repl.execute(command, timeout=20000, wait_for_response=True)
|
||||
except OSError as e:
|
||||
raise CPboardError("timeout", e)
|
||||
if error:
|
||||
raise CPboardError("exception", output, error)
|
||||
return output
|
||||
|
||||
|
||||
def eval_namedtuple(board, command):
|
||||
from collections import namedtuple
|
||||
|
@ -121,7 +121,7 @@ if tile_y == 16:
|
||||
blinka_size = 16
|
||||
c_file.write(
|
||||
"""\
|
||||
uint32_t blinka_bitmap_data[32] = {
|
||||
const uint32_t blinka_bitmap_data[32] = {
|
||||
0x00000011, 0x11000000,
|
||||
0x00000111, 0x53100000,
|
||||
0x00000111, 0x56110000,
|
||||
@ -145,7 +145,7 @@ else:
|
||||
blinka_size = 12
|
||||
c_file.write(
|
||||
"""\
|
||||
uint32_t blinka_bitmap_data[28] = {
|
||||
const uint32_t blinka_bitmap_data[28] = {
|
||||
0x00000111, 0x00000000,
|
||||
0x00001153, 0x10000000,
|
||||
0x00001156, 0x11000000,
|
||||
@ -164,11 +164,11 @@ uint32_t blinka_bitmap_data[28] = {
|
||||
|
||||
c_file.write(
|
||||
"""\
|
||||
displayio_bitmap_t blinka_bitmap = {{
|
||||
const displayio_bitmap_t blinka_bitmap = {{
|
||||
.base = {{.type = &displayio_bitmap_type }},
|
||||
.width = {0},
|
||||
.height = {0},
|
||||
.data = blinka_bitmap_data,
|
||||
.data = (uint32_t*) blinka_bitmap_data,
|
||||
.stride = 2,
|
||||
.bits_per_value = 4,
|
||||
.x_shift = 3,
|
||||
@ -211,7 +211,7 @@ displayio_palette_t blinka_palette = {{
|
||||
|
||||
displayio_tilegrid_t supervisor_blinka_sprite = {{
|
||||
.base = {{.type = &displayio_tilegrid_type }},
|
||||
.bitmap = &blinka_bitmap,
|
||||
.bitmap = (displayio_bitmap_t*) &blinka_bitmap,
|
||||
.pixel_shader = &blinka_palette,
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
|
143
tools/swo_function_trace.py
Normal file
143
tools/swo_function_trace.py
Normal file
@ -0,0 +1,143 @@
|
||||
"""This prints out Chrome Trace Formatted json that can be viewed in Perfetto or Spall.
|
||||
https://ui.perfetto.dev/
|
||||
https://gravitymoth.com/spall/spall.html
|
||||
|
||||
Format:
|
||||
https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#
|
||||
|
||||
Connect a USB to Serial converter to the SWO pin and then provide the serial
|
||||
device to this script. It should be 1MBaud SWO signal. CTRL-C when you've captured enough data and
|
||||
then it'll process and output.
|
||||
|
||||
pip install pysigrok-libsigrokdecode
|
||||
python tools/swo_function_trace.py /dev/ttyACM0 build-metro_m7_1011/firmware.elf > trace.json
|
||||
"""
|
||||
|
||||
import serial
|
||||
import sys
|
||||
import sigrokdecode
|
||||
import time
|
||||
import json
|
||||
|
||||
from elftools.elf.elffile import ELFFile
|
||||
|
||||
f = open(sys.argv[-1], "rb")
|
||||
ef = ELFFile(f)
|
||||
|
||||
symtab = ef.get_section_by_name(".symtab")
|
||||
symbols = {}
|
||||
for s in symtab.iter_symbols():
|
||||
addr = s.entry["st_value"]
|
||||
symbols[addr] = s.name
|
||||
f.close()
|
||||
|
||||
# sys.exit(0)
|
||||
|
||||
decoder = sigrokdecode.get_decoder("arm_itm")()
|
||||
|
||||
decoder.reset()
|
||||
decoder.options = {"objdump": "", "elffile": ""}
|
||||
decoder.start()
|
||||
|
||||
dwt_timestamp = 0
|
||||
last_dwt_timestamp = 0
|
||||
streak = 0
|
||||
print("[")
|
||||
|
||||
stack = []
|
||||
|
||||
|
||||
def emit(ts, addr, channel):
|
||||
s = None
|
||||
if addr in symbols:
|
||||
s = symbols[addr]
|
||||
else:
|
||||
s = hex(addr)
|
||||
if addr < 0x6000_0000:
|
||||
s = "R:" + s
|
||||
else:
|
||||
s = "F:" + s
|
||||
if channel[0] == "3":
|
||||
stack.append(addr)
|
||||
else:
|
||||
if not stack or stack[-1] != addr:
|
||||
return
|
||||
stack.pop()
|
||||
event = {
|
||||
"name": s,
|
||||
"ph": "B" if channel[0] == "3" else "E",
|
||||
"ts": ts,
|
||||
"pid": 0,
|
||||
"tid": 0,
|
||||
}
|
||||
print(json.dumps(event), ",")
|
||||
|
||||
|
||||
def decoder_cb(ss, es, data):
|
||||
global streak
|
||||
global last_dwt_timestamp
|
||||
# print(ss, es, data)
|
||||
ptype = data[0]
|
||||
ts = (dwt_timestamp + (streak * 32)) / 500
|
||||
if ptype == 0:
|
||||
event = {"name": data[1][0], "ph": "i", "ts": ts, "pid": 0, "tid": 0, "s": "g"}
|
||||
print(json.dumps(event), ",")
|
||||
if data[1][0] == "Overflow":
|
||||
while stack:
|
||||
emit(ts, stack[-1], "4:")
|
||||
|
||||
if ptype in (0, 1):
|
||||
return
|
||||
if ptype == 2 and (data[1][0].startswith("3:") or data[1][0].startswith("4:")):
|
||||
channel, addr = data[1][0].split()
|
||||
addr = int(addr[2:], 16)
|
||||
# if addr & 0x1 != 0:
|
||||
# addr -= 1
|
||||
# print(dwt_timestamp + streak, channel, symbols[addr], hex(addr))
|
||||
emit(ts, addr, channel)
|
||||
else:
|
||||
# print(dwt_timestamp + streak, data)
|
||||
pass
|
||||
if dwt_timestamp == last_dwt_timestamp:
|
||||
streak += 1
|
||||
else:
|
||||
streak = 0
|
||||
|
||||
if last_dwt_timestamp > dwt_timestamp:
|
||||
raise RuntimeError()
|
||||
last_dwt_timestamp = dwt_timestamp
|
||||
|
||||
|
||||
decoder.add_callback(sigrokdecode.OUTPUT_ANN, None, decoder_cb)
|
||||
|
||||
s = serial.Serial(sys.argv[-2], 1000000)
|
||||
|
||||
|
||||
buffers = []
|
||||
while True:
|
||||
try:
|
||||
start_ts = time.monotonic_ns()
|
||||
b = s.read(s.in_waiting)
|
||||
if b:
|
||||
end_ts = time.monotonic_ns()
|
||||
buffers.append((start_ts, end_ts, b))
|
||||
# print(len(b))
|
||||
# if len(buffers) > 10:
|
||||
# break
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
|
||||
time_per_bit = 1_000_000_000 / 1000000
|
||||
|
||||
min_gap = 100000000
|
||||
total_bytes = 0
|
||||
for start_ts, end_ts, buf in buffers:
|
||||
# print(total_bytes, start_ts, end_ts, buf)
|
||||
ts_per_byte = (end_ts - start_ts) / len(buf)
|
||||
for i, b in enumerate(buf):
|
||||
# print(total_bytes, hex(b))
|
||||
total_bytes += 1
|
||||
decoder.decode(
|
||||
start_ts + ts_per_byte * i, start_ts + ts_per_byte * (i + 1), ("DATA", None, (b,))
|
||||
)
|
||||
dwt_timestamp = decoder.dwt_timestamp
|
67
tools/swo_viewer.py
Normal file
67
tools/swo_viewer.py
Normal file
@ -0,0 +1,67 @@
|
||||
"""This prints out all parsed ITM packets.
|
||||
|
||||
Connect a USB to Serial converter to the SWO pin and then provide the serial
|
||||
device to this script. It should be 1MBaud SWO signal. CTRL-C when you've
|
||||
captured enough data and then it'll process and output.
|
||||
|
||||
pip install pysigrok-libsigrokdecode
|
||||
python tools/swo_viewer.py /dev/ttyACM0
|
||||
"""
|
||||
|
||||
import serial
|
||||
import sys
|
||||
import sigrokdecode
|
||||
import time
|
||||
import json
|
||||
|
||||
decoder = sigrokdecode.get_decoder("arm_itm")()
|
||||
|
||||
decoder.reset()
|
||||
decoder.options = {"objdump": "", "elffile": ""}
|
||||
decoder.start()
|
||||
|
||||
dwt_timestamp = 0
|
||||
last_dwt_timestamp = 0
|
||||
streak = 0
|
||||
|
||||
stack = []
|
||||
|
||||
|
||||
def decoder_cb(ss, es, data):
|
||||
global streak
|
||||
global last_dwt_timestamp
|
||||
print(dwt_timestamp, ss, es, data)
|
||||
|
||||
|
||||
decoder.add_callback(sigrokdecode.OUTPUT_ANN, None, decoder_cb)
|
||||
|
||||
s = serial.Serial(sys.argv[-2], 1000000)
|
||||
|
||||
buffers = []
|
||||
while True:
|
||||
try:
|
||||
start_ts = time.monotonic_ns()
|
||||
b = s.read(s.in_waiting)
|
||||
if b:
|
||||
end_ts = time.monotonic_ns()
|
||||
buffers.append((start_ts, end_ts, b))
|
||||
# print(len(b))
|
||||
# if len(buffers) > 10:
|
||||
# break
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
|
||||
time_per_bit = 1_000_000_000 / 1000000
|
||||
|
||||
min_gap = 100000000
|
||||
total_bytes = 0
|
||||
for start_ts, end_ts, buf in buffers:
|
||||
# print(total_bytes, start_ts, end_ts, buf)
|
||||
ts_per_byte = (end_ts - start_ts) / len(buf)
|
||||
for i, b in enumerate(buf):
|
||||
# print(total_bytes, hex(b))
|
||||
total_bytes += 1
|
||||
decoder.decode(
|
||||
start_ts + ts_per_byte * i, start_ts + ts_per_byte * (i + 1), ("DATA", None, (b,))
|
||||
)
|
||||
dwt_timestamp = decoder.dwt_timestamp
|
Loading…
Reference in New Issue
Block a user