diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index b5dbf7d6091..379042b812b 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1547,12 +1547,6 @@ msgstr "" msgid "Unable to start mDNS query" msgstr "" -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" -msgstr "" - #: ports/espressif/common-hal/nvm/ByteArray.c msgid "NVS Error" msgstr "" @@ -1933,14 +1927,6 @@ msgstr "" msgid "Out of MDNS service slots" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" -msgstr "" - -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" -msgstr "" - #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c msgid "All timers for this pin are in use" msgstr "" @@ -3013,8 +2999,7 @@ msgid "substring not found" msgstr "" #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" msgstr "" @@ -3023,7 +3008,7 @@ msgid "lhs and rhs should be compatible" msgstr "" #: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +#: shared-bindings/nvm/ByteArray.c msgid "array/bytes required on right side" msgstr "" @@ -3643,13 +3628,11 @@ msgstr "" msgid "CBC blocks must be multiples of 16 bytes" msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/nvm/ByteArray.c msgid "Slice and value different lengths." msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/nvm/ByteArray.c msgid "Array values should be single bytes." msgstr "" @@ -4038,7 +4021,7 @@ msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: shared-bindings/memorymap/AddressRange.c +#: shared-bindings/memorymap/__init__.c msgid "Address range wraps around" msgstr "" @@ -4372,6 +4355,10 @@ msgstr "" msgid "%q() without %q()" msgstr "" +#: shared-module/memorymap/AddressRange.c shared-module/memorymap/__init__.c +msgid "Address range not allowed" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" diff --git a/ports/espressif/common-hal/memorymap/AddressRange.c b/ports/espressif/common-hal/memorymap/AddressRange.c deleted file mode 100644 index a901215edbd..00000000000 --- a/ports/espressif/common-hal/memorymap/AddressRange.c +++ /dev/null @@ -1,83 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2020 microDev -// -// SPDX-License-Identifier: MIT - -#include - -#include "shared-bindings/memorymap/AddressRange.h" - -#include "py/runtime.h" -#include "soc/soc.h" - -size_t allow_ranges[][2] = { - // ULP accessible RAM - {SOC_RTC_DATA_LOW, SOC_RTC_DATA_HIGH}, - // CPU accessible RAM that is preserved during sleep if the RTC power domain is left on. - {SOC_RTC_DRAM_LOW, SOC_RTC_DRAM_HIGH}, - // RTC peripheral registers - {0x60008000, 0x60009000} -}; - -void common_hal_memorymap_addressrange_construct(memorymap_addressrange_obj_t *self, uint8_t *start_address, size_t length) { - bool allowed = false; - for (size_t i = 0; i < MP_ARRAY_SIZE(allow_ranges); i++) { - uint8_t *allowed_start = (uint8_t *)allow_ranges[i][0]; - uint8_t *allowed_end = (uint8_t *)allow_ranges[i][1]; - if (allowed_start <= start_address && - (start_address + length) <= allowed_end) { - allowed = true; - break; - } - } - - if (!allowed) { - mp_raise_ValueError(MP_ERROR_TEXT("Address range not allowed")); - } - - self->start_address = start_address; - self->len = length; -} - -size_t common_hal_memorymap_addressrange_get_length(const memorymap_addressrange_obj_t *self) { - return self->len; -} - -void common_hal_memorymap_addressrange_set_bytes(const memorymap_addressrange_obj_t *self, - size_t start_index, uint8_t *values, size_t len) { - uint8_t *address = self->start_address + start_index; - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - if (len == 1) { - *((uint8_t *)address) = values[0]; - } else if (len == sizeof(uint16_t) && (((size_t)address) % sizeof(uint16_t)) == 0) { - *((uint16_t *)address) = ((uint16_t *)values)[0]; - } else if (len == sizeof(uint32_t) && (((size_t)address) % sizeof(uint32_t)) == 0) { - *((uint32_t *)address) = ((uint32_t *)values)[0]; - } else if (len == sizeof(uint64_t) && (((size_t)address) % sizeof(uint64_t)) == 0) { - *((uint64_t *)address) = ((uint64_t *)values)[0]; - } else { - memcpy(address, values, len); - } - #pragma GCC diagnostic pop -} - -void common_hal_memorymap_addressrange_get_bytes(const memorymap_addressrange_obj_t *self, - size_t start_index, size_t len, uint8_t *values) { - uint8_t *address = self->start_address + start_index; - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - if (len == 1) { - values[0] = *((uint8_t *)address); - } else if (len == sizeof(uint16_t) && (((size_t)address) % sizeof(uint16_t)) == 0) { - ((uint16_t *)values)[0] = *((uint16_t *)address); - } else if (len == sizeof(uint32_t) && (((size_t)address) % sizeof(uint32_t)) == 0) { - ((uint32_t *)values)[0] = *((uint32_t *)address); - } else if (len == sizeof(uint64_t) && (((size_t)address) % sizeof(uint64_t)) == 0) { - ((uint64_t *)values)[0] = *((uint64_t *)address); - } else { - memcpy(values, address, len); - } - #pragma GCC diagnostic pop -} diff --git a/ports/espressif/common-hal/memorymap/AddressRange.h b/ports/espressif/common-hal/memorymap/AddressRange.h deleted file mode 100644 index 71bd76b9ea5..00000000000 --- a/ports/espressif/common-hal/memorymap/AddressRange.h +++ /dev/null @@ -1,15 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2020 microDev -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - uint8_t *start_address; - size_t len; -} memorymap_addressrange_obj_t; diff --git a/ports/espressif/common-hal/memorymap/__init__.c b/ports/espressif/common-hal/memorymap/__init__.c deleted file mode 100644 index 3919535a70a..00000000000 --- a/ports/espressif/common-hal/memorymap/__init__.c +++ /dev/null @@ -1,7 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC -// -// SPDX-License-Identifier: MIT - -// No memorymap module functions. diff --git a/ports/espressif/common-hal/memorymap/ranges.h b/ports/espressif/common-hal/memorymap/ranges.h new file mode 100644 index 00000000000..8c2ad6afc7d --- /dev/null +++ b/ports/espressif/common-hal/memorymap/ranges.h @@ -0,0 +1,18 @@ + +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 microDev +// +// SPDX-License-Identifier: MIT + +#include +#include "shared-module/memorymap/__init__.h" +#include "soc/soc.h" + +const static memorymap_range_t memorymap_ranges[] = { + {(uint8_t *)SOC_RTC_DATA_LOW, SOC_RTC_DATA_HIGH - SOC_RTC_DATA_LOW}, + // CPU accessible RAM that is preserved during sleep if the RTC power domain is left on. + {(uint8_t *)SOC_RTC_DRAM_LOW, SOC_RTC_DRAM_HIGH - SOC_RTC_DRAM_LOW}, + // RTC peripheral registers + {(uint8_t *)0x60008000, 0x9000} +}; diff --git a/ports/nordic/common-hal/memorymap/AddressRange.c b/ports/nordic/common-hal/memorymap/AddressRange.c deleted file mode 100644 index e801b921d5e..00000000000 --- a/ports/nordic/common-hal/memorymap/AddressRange.c +++ /dev/null @@ -1,114 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2020 microDev -// -// SPDX-License-Identifier: MIT - -#include -#include "nrf.h" - -#include "shared-bindings/memorymap/AddressRange.h" - -#include "py/runtime.h" - - -#ifdef NRF51_SERIES -size_t allow_ranges[][2] = { - // FLASH - {0x00000000, 0x00040000}, - // FICR & UICR ranges - {0x10000000, 0x10002000}, - // RAM - {0x20000000, 0x20010000}, - // PERIPHERALS - {0x40000000, 0x60000000} -}; -#elif defined NRF52_SERIES -size_t allow_ranges[][2] = { - // FLASH - {0x00000000, 0x00100000}, - // FICR & UICR ranges - {0x10000000, 0x10002000}, - // RAM - {0x20000000, 0x20040000}, - // PERIPHERALS - {0x40000000, 0x60000000} -}; -#elif defined NRF53_SERIES -size_t allow_ranges[][2] = { - // FLASH - {0x00000000, 0x00100000}, - // FICR & UICR ranges - {0x00FF0000, 0x01000000}, - // RAM - {0x20000000, 0x20080000}, - // PERIPHERALS - {0x40000000, 0x60000000}, - {0xE0000000, 0xE0100000} -}; -#else -#error "Unsupported nRF variant" -#endif - -void common_hal_memorymap_addressrange_construct(memorymap_addressrange_obj_t *self, uint8_t *start_address, size_t length) { - bool allowed = false; - for (size_t i = 0; i < MP_ARRAY_SIZE(allow_ranges); i++) { - uint8_t *allowed_start = (uint8_t *)allow_ranges[i][0]; - uint8_t *allowed_end = (uint8_t *)allow_ranges[i][1]; - if (allowed_start <= start_address && - (start_address + length) <= allowed_end) { - allowed = true; - break; - } - } - - if (!allowed) { - mp_raise_ValueError(MP_ERROR_TEXT("Address range not allowed")); - } - - self->start_address = start_address; - self->len = length; -} - -size_t common_hal_memorymap_addressrange_get_length(const memorymap_addressrange_obj_t *self) { - return self->len; -} - - -void common_hal_memorymap_addressrange_set_bytes(const memorymap_addressrange_obj_t *self, - size_t start_index, uint8_t *values, size_t len) { - uint8_t *address = self->start_address + start_index; - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - if (len == 1) { - *((uint8_t *)address) = values[0]; - } else if (len == sizeof(uint16_t) && (((size_t)address) % sizeof(uint16_t)) == 0) { - *((uint16_t *)address) = ((uint16_t *)values)[0]; - } else if (len == sizeof(uint32_t) && (((size_t)address) % sizeof(uint32_t)) == 0) { - *((uint32_t *)address) = ((uint32_t *)values)[0]; - } else if (len == sizeof(uint64_t) && (((size_t)address) % sizeof(uint64_t)) == 0) { - *((uint64_t *)address) = ((uint64_t *)values)[0]; - } else { - memcpy(address, values, len); - } - #pragma GCC diagnostic pop -} - -void common_hal_memorymap_addressrange_get_bytes(const memorymap_addressrange_obj_t *self, - size_t start_index, size_t len, uint8_t *values) { - uint8_t *address = self->start_address + start_index; - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wcast-align" - if (len == 1) { - values[0] = *((uint8_t *)address); - } else if (len == sizeof(uint16_t) && (((size_t)address) % sizeof(uint16_t)) == 0) { - ((uint16_t *)values)[0] = *((uint16_t *)address); - } else if (len == sizeof(uint32_t) && (((size_t)address) % sizeof(uint32_t)) == 0) { - ((uint32_t *)values)[0] = *((uint32_t *)address); - } else if (len == sizeof(uint64_t) && (((size_t)address) % sizeof(uint64_t)) == 0) { - ((uint64_t *)values)[0] = *((uint64_t *)address); - } else { - memcpy(values, address, len); - } - #pragma GCC diagnostic pop -} diff --git a/ports/nordic/common-hal/memorymap/__init__.c b/ports/nordic/common-hal/memorymap/__init__.c deleted file mode 100644 index 3919535a70a..00000000000 --- a/ports/nordic/common-hal/memorymap/__init__.c +++ /dev/null @@ -1,7 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC -// -// SPDX-License-Identifier: MIT - -// No memorymap module functions. diff --git a/ports/nordic/common-hal/memorymap/ranges.h b/ports/nordic/common-hal/memorymap/ranges.h new file mode 100644 index 00000000000..f3acc0d4598 --- /dev/null +++ b/ports/nordic/common-hal/memorymap/ranges.h @@ -0,0 +1,51 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 microDev +// +// SPDX-License-Identifier: MIT + +#include +#include "nrf.h" + +#include "shared-bindings/memorymap/__init__.h" + +#include "py/runtime.h" + + +#ifdef NRF51_SERIES +const static memorymap_range_t memorymap_ranges[] = { + // FLASH + {(uint8_t *)0x00000000, 0x00040000}, + // FICR & UICR ranges + {(uint8_t *)0x10000000, 0x00002000}, + // RAM + {(uint8_t *)0x20000000, 0x00010000}, + // PERIPHERALS + {(uint8_t *)0x40000000, 0x20000000} +}; +#elif defined NRF52_SERIES +const static memorymap_range_t memorymap_ranges[] = { + // FLASH + {(uint8_t *)0x00000000, 0x00100000}, + // FICR & UICR ranges + {(uint8_t *)0x10000000, 0x00002000}, + // RAM + {(uint8_t *)0x20000000, 0x00040000}, + // PERIPHERALS + {(uint8_t *)0x40000000, 0x20000000} +}; +#elif defined NRF53_SERIES +const static memorymap_range_t memorymap_ranges[] = { + // FLASH + {(uint8_t *)0x00000000, 0x00100000}, + // FICR & UICR ranges + {(uint8_t *)0x00FF0000, 0x00010000}, + // RAM + {(uint8_t *)0x20000000, 0x00080000}, + // PERIPHERALS + {(uint8_t *)0x40000000, 0x20000000}, + {(uint8_t *)0xE0000000, 0x00100000} +}; +#else +#error "Unsupported nRF variant" +#endif diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.c b/ports/raspberrypi/bindings/rp2pio/StateMachine.c index 398685be8a0..81fb2da58e4 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.c +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.c @@ -1053,7 +1053,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_pc_obj, rp2pio_statemachine_ob MP_PROPERTY_GETTER(rp2pio_statemachine_pc_obj, (mp_obj_t)&rp2pio_statemachine_get_pc_obj); -//| rxfifo: memorymap.AddressRange +//| rxfifo: memoryview //| """Access the state machine's rxfifo directly //| //| If the state machine's fifo mode is ``txput`` then accessing this object diff --git a/ports/raspberrypi/common-hal/memorymap/AddressRange.c b/ports/raspberrypi/common-hal/memorymap/AddressRange.c deleted file mode 100644 index a5e860cb40c..00000000000 --- a/ports/raspberrypi/common-hal/memorymap/AddressRange.c +++ /dev/null @@ -1,139 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2020 microDev -// SPDX-FileCopyrightText: Copyright (c) 2023 Bob Abeles -// -// SPDX-License-Identifier: MIT - -#include - -#include "shared-bindings/memorymap/AddressRange.h" - -#include "py/runtime.h" - -#include "hardware/regs/addressmap.h" - -// RP2 address map ranges, must be arranged in order by ascending start address -#if PICO_RP2040 -addressmap_rp2_range_t rp2_ranges[] = { - {(uint8_t *)ROM_BASE, 0x00004000, ROM}, // boot ROM - {(uint8_t *)XIP_BASE, 0x00100000, XIP}, // XIP normal cache operation - {(uint8_t *)XIP_NOALLOC_BASE, 0x00100000, XIP}, // XIP check for hit, no update on miss - {(uint8_t *)XIP_NOCACHE_BASE, 0x00100000, XIP}, // XIP don't check for hit, no update on miss - {(uint8_t *)XIP_NOCACHE_NOALLOC_BASE, 0x00100000, XIP}, // XIP bypass cache completely - {(uint8_t *)XIP_CTRL_BASE, 0x00004000, IO}, // XIP control registers - {(uint8_t *)XIP_SRAM_BASE, 0x00004000, SRAM}, // XIP SRAM 16KB XIP cache - {(uint8_t *)XIP_SSI_BASE, 0x00004000, IO}, // XIP SSI registers - {(uint8_t *)SRAM_BASE, 0x00042000, SRAM}, // SRAM 256KB striped plus 16KB contiguous - {(uint8_t *)SRAM0_BASE, 0x00040000, SRAM}, // SRAM0 to SRAM3 256KB non-striped - {(uint8_t *)SYSINFO_BASE, 0x00070000, IO}, // APB peripherals - {(uint8_t *)DMA_BASE, 0x00004000, IO}, // DMA registers - {(uint8_t *)USBCTRL_DPRAM_BASE, 0x00001000, SRAM}, // USB DPSRAM 4KB - {(uint8_t *)USBCTRL_REGS_BASE, 0x00004000, IO}, // USB registers - {(uint8_t *)PIO0_BASE, 0x00004000, IO}, // PIO0 registers - {(uint8_t *)PIO1_BASE, 0x00004000, IO}, // PIO1 registers - {(uint8_t *)SIO_BASE, 0x00001000, IO}, // SIO registers, no aliases - {(uint8_t *)PPB_BASE, 0x00004000, IO} // PPB registers -}; -#endif -#if PICO_RP2350 -addressmap_rp2_range_t rp2_ranges[] = { - {(uint8_t *)ROM_BASE, 0x00004000, ROM}, // boot ROM - {(uint8_t *)XIP_BASE, 0x00100000, XIP}, // XIP normal cache operation - {(uint8_t *)XIP_NOCACHE_NOALLOC_BASE, 0x00100000, XIP}, // XIP bypass cache completely - {(uint8_t *)XIP_MAINTENANCE_BASE, 0x00100000, XIP}, // XIP cache maintenance based on lower 3 address bits. Data is ignored - {(uint8_t *)XIP_NOCACHE_NOALLOC_NOTRANSLATE_BASE, 0x00100000, XIP}, // XIP skip cache and address translation - {(uint8_t *)SRAM_BASE, SRAM_END - SRAM_BASE, SRAM}, // SRAM 256KB striped plus 16KB contiguous - {(uint8_t *)SYSINFO_BASE, 0x00070000, IO}, // APB peripherals - {(uint8_t *)XIP_CTRL_BASE, 0x00004000, IO}, // XIP control registers - {(uint8_t *)XIP_QMI_BASE, 0x00004000, IO}, // XIP QMI registers - {(uint8_t *)DMA_BASE, 0x00004000, IO}, // DMA registers - {(uint8_t *)USBCTRL_DPRAM_BASE, 0x00001000, SRAM}, // USB DPSRAM 4KB - {(uint8_t *)USBCTRL_REGS_BASE, 0x00004000, IO}, // USB registers - {(uint8_t *)PIO0_BASE, 0x00004000, IO}, // PIO0 registers - {(uint8_t *)PIO1_BASE, 0x00004000, IO}, // PIO1 registers - {(uint8_t *)PIO2_BASE, 0x00004000, IO}, // PIO2 registers - {(uint8_t *)SIO_BASE, 0x00001000, IO}, // SIO registers, no aliases - {(uint8_t *)PPB_BASE, 0x00004000, IO} // PPB registers -}; -#endif - -void common_hal_memorymap_addressrange_construct(memorymap_addressrange_obj_t *self, - uint8_t *start_address, size_t length) { - for (size_t i = 0; i < MP_ARRAY_SIZE(rp2_ranges); i++) { - if (start_address <= rp2_ranges[i].start_address) { - uint8_t *range_end_address = rp2_ranges[i].start_address + rp2_ranges[i].len - 1; - uint8_t *end_address = start_address + length - 1; - if (start_address > range_end_address || end_address > range_end_address) { - break; - } - self->start_address = start_address; - self->len = length; - self->type = rp2_ranges[i].type; - return; - } - } - - mp_raise_ValueError(MP_ERROR_TEXT("Address range not allowed")); -} - -size_t common_hal_memorymap_addressrange_get_length(const memorymap_addressrange_obj_t *self) { - return self->len; -} - -void common_hal_memorymap_addressrange_set_bytes(const memorymap_addressrange_obj_t *self, - size_t start_index, uint8_t *values, size_t len) { - uint8_t *dest_addr = self->start_address + start_index; - switch (self->type) { - case SRAM: - // Writes to SRAM may be arbitrary length and alignment. We use memcpy() which - // may optimize aligned writes depending on CIRCUITPY_FULL_BUILD of the CP build. - memcpy(dest_addr, values, len); - break; - case IO: - if ((size_t)dest_addr & 0x03 || len & 0x03) { - // Unaligned access or unaligned length not supported by RP2 for IO registers - mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to access unaligned IO register")); - } else { - // Aligned access and length, use 32-bit writes - uint32_t *dest_addr32 = (uint32_t *)dest_addr; - size_t access_count = len >> 2; - for (size_t i = 0; i < access_count; i++) { - *dest_addr32++ = ((uint32_t *)values)[i]; - } - } - break; - case XIP: - case ROM: - // XIP and ROM are read-only - mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to write to read-only memory")); - break; - } -} - -void common_hal_memorymap_addressrange_get_bytes(const memorymap_addressrange_obj_t *self, - size_t start_index, size_t len, uint8_t *values) { - uint8_t *src_addr = self->start_address + start_index; - switch (self->type) { - case SRAM: - case XIP: - case ROM: - // Reads from these sources may be arbitrary length and alignment. We use memcpy() - // which may optimize aligned writes depending on CIRCUITPY_FULL_BUILD of the CP build. - memcpy(values, src_addr, len); - break; - case IO: - if ((size_t)src_addr & 0x03 || len & 0x03) { - // Unaligned access or unaligned length not supported by RP2 for IO registers - mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to access unaligned IO register")); - } else { - // Aligned access and length, use 32-bit reads - uint32_t *src_addr32 = (uint32_t *)src_addr; - size_t access_count = len >> 2; - for (size_t i = 0; i < access_count; i++) { - ((uint32_t *)values)[i] = *src_addr32++; - } - } - break; - } -} diff --git a/ports/raspberrypi/common-hal/memorymap/AddressRange.h b/ports/raspberrypi/common-hal/memorymap/AddressRange.h deleted file mode 100644 index 8f5d1fab26c..00000000000 --- a/ports/raspberrypi/common-hal/memorymap/AddressRange.h +++ /dev/null @@ -1,26 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2020 microDev -// SPDX-FileCopyrightText: Copyright (c) 2023 Bob Abeles -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "py/obj.h" - -// depending on the section memory type, different access methods and rules apply -typedef enum { SRAM, ROM, XIP, IO } memorymap_rp2_section_t; - -typedef struct { - mp_obj_base_t base; - uint8_t *start_address; - size_t len; - memorymap_rp2_section_t type; -} memorymap_addressrange_obj_t; - -typedef struct { - uint8_t *start_address; - size_t len; - memorymap_rp2_section_t type; -} addressmap_rp2_range_t; diff --git a/ports/raspberrypi/common-hal/memorymap/__init__.c b/ports/raspberrypi/common-hal/memorymap/__init__.c deleted file mode 100644 index 3919535a70a..00000000000 --- a/ports/raspberrypi/common-hal/memorymap/__init__.c +++ /dev/null @@ -1,7 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC -// -// SPDX-License-Identifier: MIT - -// No memorymap module functions. diff --git a/ports/raspberrypi/common-hal/memorymap/ranges.h b/ports/raspberrypi/common-hal/memorymap/ranges.h new file mode 100644 index 00000000000..e550da62c3b --- /dev/null +++ b/ports/raspberrypi/common-hal/memorymap/ranges.h @@ -0,0 +1,49 @@ +#pragma once + +#include "hardware/regs/addressmap.h" +#include "shared-module/memorymap/__init__.h" + +// RP2 address map ranges, must be arranged in order by ascending start address +#if PICO_RP2040 +const static memorymap_range_t memorymap_ranges[] = { + {(uint8_t *)ROM_BASE, 0x00004000, 1}, // boot ROM + {(uint8_t *)XIP_BASE, 0x00100000}, // XIP normal cache operation + {(uint8_t *)XIP_NOALLOC_BASE, 0x00100000}, // XIP check for hit, no update on miss + {(uint8_t *)XIP_NOCACHE_BASE, 0x00100000}, // XIP don't check for hit, no update on miss + {(uint8_t *)XIP_NOCACHE_NOALLOC_BASE, 0x00100000}, // XIP bypass cache completely + {(uint8_t *)XIP_CTRL_BASE, 0x00004000}, // XIP control registers + {(uint8_t *)XIP_SRAM_BASE, 0x00004000}, // XIP SRAM 16KB XIP cache + {(uint8_t *)XIP_SSI_BASE, 0x00004000}, // XIP SSI registers + {(uint8_t *)SRAM_BASE, 0x00042000}, // SRAM 256KB striped plus 16KB contiguous + {(uint8_t *)SRAM0_BASE, 0x00040000}, // SRAM0 to SRAM3 256KB non-striped + {(uint8_t *)SYSINFO_BASE, 0x00070000}, // APB peripherals + {(uint8_t *)DMA_BASE, 0x00004000}, // DMA registers + {(uint8_t *)USBCTRL_DPRAM_BASE, 0x00001000}, // USB DPSRAM 4KB + {(uint8_t *)USBCTRL_REGS_BASE, 0x00004000}, // USB registers + {(uint8_t *)PIO0_BASE, 0x00004000}, // PIO0 registers + {(uint8_t *)PIO1_BASE, 0x00004000}, // PIO1 registers + {(uint8_t *)SIO_BASE, 0x00001000}, // SIO registers, no aliases + {(uint8_t *)PPB_BASE, 0x00004000} // PPB registers +}; +#endif +#if PICO_RP2350 +const static memorymap_range_t memorymap_ranges[] = { + {(uint8_t *)ROM_BASE, 0x00004000, 1}, // boot ROM + {(uint8_t *)XIP_BASE, 0x00100000}, // XIP normal cache operation + {(uint8_t *)XIP_NOCACHE_NOALLOC_BASE, 0x00100000}, // XIP bypass cache completely + {(uint8_t *)XIP_MAINTENANCE_BASE, 0x00100000}, // XIP cache maintenance based on lower 3 address bits. Data is ignored + {(uint8_t *)XIP_NOCACHE_NOALLOC_NOTRANSLATE_BASE, 0x00100000}, // XIP skip cache and address translation + {(uint8_t *)SRAM_BASE, SRAM_END - SRAM_BASE}, // SRAM 256KB striped plus 16KB contiguous + {(uint8_t *)SYSINFO_BASE, 0x00070000}, // APB peripherals + {(uint8_t *)XIP_CTRL_BASE, 0x00004000}, // XIP control registers + {(uint8_t *)XIP_QMI_BASE, 0x00004000}, // XIP QMI registers + {(uint8_t *)DMA_BASE, 0x00004000}, // DMA registers + {(uint8_t *)USBCTRL_DPRAM_BASE, 0x00001000}, // USB DPSRAM 4KB + {(uint8_t *)USBCTRL_REGS_BASE, 0x00004000}, // USB registers + {(uint8_t *)PIO0_BASE, 0x00004000}, // PIO0 registers + {(uint8_t *)PIO1_BASE, 0x00004000}, // PIO1 registers + {(uint8_t *)PIO2_BASE, 0x00004000}, // PIO2 registers + {(uint8_t *)SIO_BASE, 0x00001000}, // SIO registers, no aliases + {(uint8_t *)PPB_BASE, 0x00004000} // PPB registers +}; +#endif diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index 407c2c94b73..03acc0be970 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -10,9 +10,9 @@ #include "common-hal/microcontroller/__init__.h" #include "shared-bindings/digitalio/Pull.h" +#include "shared-bindings/memorymap/__init__.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/memorymap/AddressRange.h" #include "hardware/platform_defs.h" #include "hardware/structs/iobank0.h" @@ -491,10 +491,9 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, #if PICO_PIO_VERSION > 0 if (fifo_type == PIO_FIFO_JOIN_TXPUT || fifo_type == PIO_FIFO_JOIN_TXGET) { - self->rxfifo_obj.base.type = &memorymap_addressrange_type; - common_hal_memorymap_addressrange_construct(&self->rxfifo_obj, (uint8_t *)self->pio->rxf_putget[self->state_machine], 4 * sizeof(uint32_t)); + self->rxfifo_obj = common_hal_memorymap_addressrange_make_new((uint8_t *)self->pio->rxf_putget[self->state_machine], 4 * sizeof(uint32_t)); } else { - self->rxfifo_obj.base.type = NULL; + self->rxfifo_obj = mp_const_none; } #endif @@ -1612,9 +1611,7 @@ int common_hal_rp2pio_statemachine_get_pc(rp2pio_statemachine_obj_t *self) { mp_obj_t common_hal_rp2pio_statemachine_get_rxfifo(rp2pio_statemachine_obj_t *self) { #if PICO_PIO_VERSION > 0 - if (self->rxfifo_obj.base.type) { - return MP_OBJ_FROM_PTR(&self->rxfifo_obj); - } + return self->rxfifo_obj; #endif return mp_const_none; } diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h index eae1247d6f4..905539e7d53 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h @@ -9,7 +9,6 @@ #include "py/obj.h" #include "common-hal/microcontroller/Pin.h" -#include "common-hal/memorymap/AddressRange.h" #include "hardware/pio.h" // Shared PIO allocator declarations (rp2pio_statemachine_find_pio, @@ -143,7 +142,7 @@ typedef struct { bool dma_completed_write, byteswap; bool dma_completed_read; #if PICO_PIO_VERSION > 0 - memorymap_addressrange_obj_t rxfifo_obj; + mp_obj_t rxfifo_obj; #endif } rp2pio_statemachine_obj_t; diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 4c91ed102c2..1e028f56441 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -548,8 +548,6 @@ SRC_COMMON_HAL_ALL = \ max3421e/Max3421E.c \ mcp4822/__init__.c \ mcp4822/MCP4822.c \ - memorymap/__init__.c \ - memorymap/AddressRange.c \ microcontroller/__init__.c \ microcontroller/Pin.c \ microcontroller/Processor.c \ @@ -787,6 +785,7 @@ SRC_SHARED_MODULE_ALL = \ keypad/Keys.c \ max3421e/__init__.c \ max3421e/Max3421E.c \ + memorymap/__init__.c \ memorymonitor/__init__.c \ memorymonitor/AllocationAlarm.c \ memorymonitor/AllocationSize.c \ diff --git a/shared-bindings/memorymap/AddressRange.c b/shared-bindings/memorymap/AddressRange.c deleted file mode 100644 index 5f7ee0deb95..00000000000 --- a/shared-bindings/memorymap/AddressRange.c +++ /dev/null @@ -1,227 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2017 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include "py/binary.h" -#include "py/runtime.h" -#include "py/runtime0.h" -#include "shared-bindings/memorymap/AddressRange.h" - -//| class AddressRange: -//| r"""Presents a range of addresses as a bytearray. -//| -//| The addresses may access memory or memory mapped peripherals. -//| -//| Some address ranges may be protected by CircuitPython to prevent errors. -//| An exception will be raised when constructing an AddressRange for an -//| invalid or protected address. -//| -//| Multiple AddressRanges may overlap. There is no "claiming" of addresses. -//| -//| Example usage on ESP32-S2:: -//| -//| import memorymap -//| rtc_slow_mem = memorymap.AddressRange(start=0x50000000, length=0x2000) -//| rtc_slow_mem[0:3] = b"\xcc\x10\x00" -//| -//| Example I/O register usage on RP2040:: -//| -//| import binascii -//| import board -//| import digitalio -//| import memorymap -//| -//| def rp2040_set_pad_drive(p, d): -//| pads_bank0 = memorymap.AddressRange(start=0x4001C000, length=0x4000) -//| pad_ctrl = int.from_bytes(pads_bank0[p*4+4:p*4+8], "little") -//| # Pad control register is updated using an MP-safe atomic XOR -//| pad_ctrl ^= (d << 4) -//| pad_ctrl &= 0x00000030 -//| pads_bank0[p*4+0x1004:p*4+0x1008] = pad_ctrl.to_bytes(4, "little") -//| -//| def rp2040_get_pad_drive(p): -//| pads_bank0 = memorymap.AddressRange(start=0x4001C000, length=0x4000) -//| pad_ctrl = int.from_bytes(pads_bank0[p*4+4:p*4+8], "little") -//| return (pad_ctrl >> 4) & 0x3 -//| -//| # set GPIO16 pad drive strength to 12 mA -//| rp2040_set_pad_drive(16, 3) -//| -//| # print GPIO16 pad drive strength -//| print(rp2040_get_pad_drive(16)) -//| -//| Note that the above example does **not** work on RP2350 because base -//| address and organization of the "pads0" registers changed compared -//| to the RP2040. -//| """ -//| - -//| def __init__(self, *, start: int, length: int) -> None: -//| """Constructs an address range starting at ``start`` and ending at -//| ``start + length``. An exception will be raised if any of the -//| addresses are invalid or protected.""" -//| ... -//| -static mp_obj_t memorymap_addressrange_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_start, ARG_length }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_length, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - // Argument start is a pointer into the address map, so we validate it here because a - // signed int argument will overflow if it is in the upper half of the map. - size_t start; - if (mp_obj_is_small_int(args[ARG_start].u_obj)) { - start = MP_OBJ_SMALL_INT_VALUE(args[ARG_start].u_obj); - } else if (mp_obj_is_exact_type(args[ARG_start].u_obj, &mp_type_int)) { - start = mp_obj_int_get_uint_checked(args[ARG_start].u_obj); - } else { - mp_obj_t arg = mp_unary_op(MP_UNARY_OP_INT_MAYBE, args[ARG_start].u_obj); - start = mp_obj_int_get_uint_checked(arg); - } - size_t length = - mp_arg_validate_int_min(args[ARG_length].u_int, 1, MP_QSTR_length); - // Check for address range wrap here as this can break port-specific code due to size_t overflow. - if (start + length - 1 < start) { - mp_raise_ValueError(MP_ERROR_TEXT("Address range wraps around")); - } - - memorymap_addressrange_obj_t *self = mp_obj_malloc(memorymap_addressrange_obj_t, &memorymap_addressrange_type); - common_hal_memorymap_addressrange_construct(self, (uint8_t *)start, length); - - return MP_OBJ_FROM_PTR(self); -} - -//| def __bool__(self) -> bool: ... -//| def __len__(self) -> int: -//| """Return the length. This is used by (`len`)""" -//| ... -//| -static mp_obj_t memorymap_addressrange_unary_op(mp_unary_op_t op, mp_obj_t self_in) { - memorymap_addressrange_obj_t *self = MP_OBJ_TO_PTR(self_in); - uint16_t len = common_hal_memorymap_addressrange_get_length(self); - switch (op) { - case MP_UNARY_OP_BOOL: - return mp_obj_new_bool(len != 0); - case MP_UNARY_OP_LEN: - return MP_OBJ_NEW_SMALL_INT(len); - default: - return MP_OBJ_NULL; // op not supported - } -} - -static const mp_rom_map_elem_t memorymap_addressrange_locals_dict_table[] = { -}; - -static MP_DEFINE_CONST_DICT(memorymap_addressrange_locals_dict, memorymap_addressrange_locals_dict_table); - -//| @overload -//| def __getitem__(self, index: slice) -> bytearray: ... -//| @overload -//| def __getitem__(self, index: int) -> int: -//| """Returns the value(s) at the given index. -//| -//| 1, 2, 4 and 8 byte aligned reads will be done in one transaction -//| when possible. -//| All others may use multiple transactions.""" -//| ... -//| -//| @overload -//| def __setitem__(self, index: slice, value: ReadableBuffer) -> None: ... -//| -//| @overload -//| def __setitem__(self, index: int, value: int) -> None: -//| """Set the value(s) at the given index. -//| -//| 1, 2, 4 and 8 byte aligned writes will be done in one transaction -//| when possible. -//| All others may use multiple transactions.""" -//| ... -//| -//| -static mp_obj_t memorymap_addressrange_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { - if (value == MP_OBJ_NULL) { - // delete item - // slice deletion - return MP_OBJ_NULL; // op not supported - } else { - memorymap_addressrange_obj_t *self = MP_OBJ_TO_PTR(self_in); - if (0) { - #if MICROPY_PY_BUILTINS_SLICE - } else if (mp_obj_is_type(index_in, &mp_type_slice)) { - mp_bound_slice_t slice; - if (!mp_seq_get_fast_slice_indexes(common_hal_memorymap_addressrange_get_length(self), index_in, &slice)) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("only slices with step=1 (aka None) are supported")); - } - if (value != MP_OBJ_SENTINEL) { - #if MICROPY_PY_ARRAY_SLICE_ASSIGN - // Assign - size_t src_len = slice.stop - slice.start; - uint8_t *src_items; - if (mp_obj_is_type(value, &mp_type_array) || - mp_obj_is_type(value, &mp_type_bytearray) || - mp_obj_is_type(value, &mp_type_memoryview) || - mp_obj_is_type(value, &mp_type_bytes)) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(value, &bufinfo, MP_BUFFER_READ); - if (bufinfo.len != src_len) { - mp_raise_ValueError(MP_ERROR_TEXT("Slice and value different lengths.")); - } - src_len = bufinfo.len; - src_items = bufinfo.buf; - if (1 != mp_binary_get_size('@', bufinfo.typecode, NULL)) { - mp_raise_ValueError(MP_ERROR_TEXT("Array values should be single bytes.")); - } - } else { - mp_raise_NotImplementedError(MP_ERROR_TEXT("array/bytes required on right side")); - } - - common_hal_memorymap_addressrange_set_bytes(self, slice.start, src_items, src_len); - return mp_const_none; - #else - return MP_OBJ_NULL; // op not supported - #endif - } else { - // Read slice. - size_t len = slice.stop - slice.start; - uint8_t *items = m_new(uint8_t, len); - common_hal_memorymap_addressrange_get_bytes(self, slice.start, len, items); - return mp_obj_new_bytearray_by_ref(len, items); - } - #endif - } else { - // Single index rather than slice. - size_t index = mp_get_index(self->base.type, common_hal_memorymap_addressrange_get_length(self), - index_in, false); - if (value == MP_OBJ_SENTINEL) { - // load - uint8_t value_out; - common_hal_memorymap_addressrange_get_bytes(self, index, 1, &value_out); - return MP_OBJ_NEW_SMALL_INT(value_out); - } else { - // store - mp_int_t byte_value = mp_obj_get_int(value); - mp_arg_validate_int_range(byte_value, 0, 255, MP_QSTR_bytes); - - uint8_t short_value = byte_value; - common_hal_memorymap_addressrange_set_bytes(self, index, &short_value, 1); - return mp_const_none; - } - } - } -} - -MP_DEFINE_CONST_OBJ_TYPE( - memorymap_addressrange_type, - MP_QSTR_AddressRange, - MP_TYPE_FLAG_NONE, - make_new, memorymap_addressrange_make_new, - locals_dict, (mp_obj_t)&memorymap_addressrange_locals_dict, - subscr, memorymap_addressrange_subscr, - unary_op, memorymap_addressrange_unary_op - ); diff --git a/shared-bindings/memorymap/AddressRange.h b/shared-bindings/memorymap/AddressRange.h deleted file mode 100644 index 32bd0562a88..00000000000 --- a/shared-bindings/memorymap/AddressRange.h +++ /dev/null @@ -1,23 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2017 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "common-hal/memorymap/AddressRange.h" - -extern const mp_obj_type_t memorymap_addressrange_type; - -void common_hal_memorymap_addressrange_construct(memorymap_addressrange_obj_t *self, uint8_t *start_address, size_t length); - -size_t common_hal_memorymap_addressrange_get_length(const memorymap_addressrange_obj_t *self); - -void common_hal_memorymap_addressrange_set_bytes(const memorymap_addressrange_obj_t *self, - size_t start_index, uint8_t *values, size_t len); - -// len and values are intentionally swapped to signify values is an output and -// also leverage the compiler to validate uses are expected. -void common_hal_memorymap_addressrange_get_bytes(const memorymap_addressrange_obj_t *self, - size_t start_index, size_t len, uint8_t *values); diff --git a/shared-bindings/memorymap/__init__.c b/shared-bindings/memorymap/__init__.c index 9e404d16497..8bd0dc6004f 100644 --- a/shared-bindings/memorymap/__init__.c +++ b/shared-bindings/memorymap/__init__.c @@ -9,7 +9,6 @@ #include "py/runtime.h" #include "shared-bindings/memorymap/__init__.h" -#include "shared-bindings/memorymap/AddressRange.h" //| """Raw memory map access //| @@ -17,9 +16,93 @@ //| address space seen from the processor running CircuitPython. It is usually //| the physical address space. //| """ +//| +//| def AddressRange(start_address: int, length: int) -> memoryview: +//| r"""Presents a range of addresses as a memoryview. +//| +//| +//| The addresses may access memory or memory mapped peripherals. +//| +//| Some address ranges may be protected by CircuitPython to prevent errors. +//| An exception will be raised when constructing an AddressRange for an +//| invalid or protected address. +//| +//| Multiple AddressRanges may overlap. There is no "claiming" of addresses. +//| +//| *New in CircuitPython 11.0:* This returns a `memoryview` object instead of an ``AddressRange`` object. +//| A `memoryview` object can be cast, used as an argument to `struct.pack` or `struct.unpack`, etc. +//| +//| *New in CircuitPython 11.0:* On RP2 family microcontrollers, I/O ranges can be accessed as 8- or 16- +//| bit values. When writing, the smaller value is repeated 2 or 4 times to form the value actually +//| transferred, as documented in the MCU datasheet. +//| +//| A `memoryview` object can be cast, used as an argument to `struct.pack` or `struct.unpack`, etc. +//| Example usage on ESP32-S2:: +//| +//| import memorymap +//| rtc_slow_mem = memorymap.AddressRange(start=0x50000000, length=0x2000) +//| rtc_slow_mem[0:3] = b"\xcc\x10\x00" +//| +//| Example I/O register usage on RP2040:: +//| +//| import binascii +//| import board +//| import digitalio +//| import memorymap +//| +//| pads_bank0 = memorymap.AddressRange(start=0x4001C000, length=0x4000).cast('L') +//| pads_bank0_xor = memorymap.AddressRange(start=0x4001C000+0x1000, length=0x4000).cast('L') +//| +//| def rp2040_set_pad_drive(p, d): +//| pad_ctrl = pads_bank0[p+1] +//| # Pad control register is updated using an MP-safe atomic XOR +//| pad_ctrl ^= (d << 4) +//| pad_ctrl &= 0x00000030 +//| pads_bank0_xor[p+1] = pad_ctrl +//| +//| def rp2040_get_pad_drive(p): +//| pad_ctrl = pads_bank0[p+1] +//| return (pad_ctrl >> 4) & 0x3 +//| +//| # set GPIO16 pad drive strength to 12 mA +//| rp2040_set_pad_drive(16, 3) +//| +//| # print GPIO16 pad drive strength +//| print(rp2040_get_pad_drive(16)) +//| +//| Note that the above example does **not** work on RP2350 because base +//| address and organization of the "pads0" registers changed compared +//| to the RP2040. +//| """ +//| + +static mp_obj_t memorymap_addressrange(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_start, ARG_length }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_length, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Argument start is a pointer into the address map, so we validate it here because a + // signed int argument will overflow if it is in the upper half of the map. + size_t start = mp_obj_get_uint(args[ARG_start].u_obj); + size_t length = + mp_arg_validate_int_min(args[ARG_length].u_int, 1, MP_QSTR_length); + + // Check for address range wrap here as this can break port-specific code due to size_t overflow. + if (start + length - 1 < start) { + mp_raise_ValueError(MP_ERROR_TEXT("Address range wraps around")); + } + + return common_hal_memorymap_addressrange_make_new((uint8_t *)start, length); +} +MP_DEFINE_CONST_FUN_OBJ_KW(memorymap_addressrange_obj, 0, memorymap_addressrange); + static const mp_rom_map_elem_t memorymap_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_memorymap) }, - { MP_ROM_QSTR(MP_QSTR_AddressRange), MP_ROM_PTR(&memorymap_addressrange_type) }, + { MP_ROM_QSTR(MP_QSTR_AddressRange), MP_ROM_PTR(&memorymap_addressrange_obj) }, }; static MP_DEFINE_CONST_DICT(memorymap_module_globals, memorymap_module_globals_table); diff --git a/shared-bindings/memorymap/__init__.h b/shared-bindings/memorymap/__init__.h index a3eb3cbe147..c7ee42990d3 100644 --- a/shared-bindings/memorymap/__init__.h +++ b/shared-bindings/memorymap/__init__.h @@ -5,3 +5,7 @@ // SPDX-License-Identifier: MIT #pragma once + +#include "py/obj.h" + +mp_obj_t common_hal_memorymap_addressrange_make_new(uint8_t *start_address, size_t length); diff --git a/shared-module/memorymap/__init__.c b/shared-module/memorymap/__init__.c new file mode 100644 index 00000000000..8f1484e8d40 --- /dev/null +++ b/shared-module/memorymap/__init__.c @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Jeff Epler +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/runtime.h" + +#include "shared-bindings/memorymap/__init__.h" +#include "shared-module/memorymap/__init__.h" +#include "common-hal/memorymap/ranges.h" + +mp_obj_t common_hal_memorymap_addressrange_make_new(uint8_t *start_address, size_t length) { + for (size_t i = 0; i < MP_ARRAY_SIZE(memorymap_ranges); i++) { + const memorymap_range_t *range = &memorymap_ranges[i]; + if (start_address <= range->start_address) { + uint8_t *range_end_address = range->start_address + range->len - 1; + uint8_t *end_address = start_address + length - 1; + if (start_address > range_end_address || end_address > range_end_address) { + break; + } + return mp_obj_new_memoryview(range->readonly ? 'B' : 0x80 | 'B', length, start_address); + } + } + + mp_raise_ValueError(MP_ERROR_TEXT("Address range not allowed")); +} diff --git a/ports/nordic/common-hal/memorymap/AddressRange.h b/shared-module/memorymap/__init__.h similarity index 54% rename from ports/nordic/common-hal/memorymap/AddressRange.h rename to shared-module/memorymap/__init__.h index 71bd76b9ea5..f349fe5ed2c 100644 --- a/ports/nordic/common-hal/memorymap/AddressRange.h +++ b/shared-module/memorymap/__init__.h @@ -1,15 +1,15 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2020 microDev +// SPDX-FileCopyrightText: Copyright (c) 2025 Jeff Epler // // SPDX-License-Identifier: MIT #pragma once -#include "py/obj.h" +#include typedef struct { - mp_obj_base_t base; uint8_t *start_address; - size_t len; -} memorymap_addressrange_obj_t; + uint32_t len : 31; + uint32_t readonly : 1; +} memorymap_range_t;