Initial commit pulled in a bunch of stuff - see description

* Add `PICO_MINIMAL_STORED_VECTOR_TABLE` config replacing (`PICO_NO_STORED_VECTOR_TABLE` which was a lie
* Add `PICO_NUM_VTABLE_IRQS`` which allows you to limit the number of IRQs included in both the STORED or RAM vector tables, and make the rest of the SDK behave properly based on that
* Because these new variables in `pico_crt0` are circularly dependent somewhat with variables in `hardware_irq` hoist all the interdependent variables into a new `pico_platform_common` which is common to all `rp2` platforms
* Move some previously duplicated `pico_platform` code into `pico_platform_common`

Net effect:

1. if you set PICO_MINIMAL_STORED_VECTOR_TABLE=1, you get a 4 word VTABLE on Arm.. you still get a RAM vector table with up to PICO_NUM_VTABLE_IRQs (defaults to NUM_IRQs) but everything - including things like `isr_pendsv` point to `__unhandled_user_irq`.
2. PICO_NUM_VTABLE_IRQs (default NUM_IRQS) sets the number of IRQs that have handlers in the VTABLE (this affects the space reserved, and what the irq APIs let you touch - at least as far as invalid_params_if!)
3. If you set PICO_MINIMAL_STORED_VECTOR_TABLE=1 for a no flash binary, then PICO_NUM_VTABLE_IRQs is forced to 0 as there is no reserved space for the handlers.

Co-authored-by: graham sanderson <graham.sanderson@raspberrypi.com>
This commit is contained in:
will-v-pi 2025-03-26 21:44:21 +00:00 committed by GitHub
parent 39fafaa434
commit a5ba689cb5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 287 additions and 268 deletions

View file

@ -82,6 +82,7 @@ endif()
# Basic bootrom headers
pico_add_subdirectory(rp2_common/boot_bootrom_headers)
pico_add_subdirectory(rp2_common/pico_platform_common)
pico_add_subdirectory(rp2_common/pico_platform_compiler)
pico_add_subdirectory(rp2_common/pico_platform_sections)
pico_add_subdirectory(rp2_common/pico_platform_panic)

View file

@ -112,6 +112,7 @@ cc_library(
"//src/rp2_common/hardware_watchdog:__pkg__",
"//src/rp2_common/hardware_xosc:__pkg__",
"//src/rp2_common/pico_crt0:__pkg__",
"//src/rp2_common/pico_platform_common:__pkg__",
"//src/rp2_common/pico_printf:__pkg__",
"//src/rp2_common/pico_runtime:__pkg__",
"//src/rp2_common/pico_runtime_init:__pkg__",

View file

@ -128,7 +128,7 @@ extern "C" {
typedef void (*irq_handler_t)(void);
static inline void check_irq_param(__unused uint num) {
invalid_params_if(HARDWARE_IRQ, num >= NUM_IRQS);
invalid_params_if(HARDWARE_IRQ, num >= PICO_NUM_VTABLE_IRQS);
}
/*! \brief Set specified interrupt's priority

View file

@ -96,7 +96,7 @@ void PICO_WEAK_FUNCTION_IMPL_NAME(irq_init_priorities)() {
}
static uint get_user_irq_claim_index(uint irq_num) {
invalid_params_if(HARDWARE_IRQ, irq_num < FIRST_USER_IRQ || irq_num >= NUM_IRQS);
invalid_params_if(HARDWARE_IRQ, irq_num < FIRST_USER_IRQ || irq_num >= PICO_NUM_VTABLE_IRQS);
// we count backwards from the last, to match the existing hard coded uses of user IRQs in the SDK which were previously using 31
static_assert(NUM_IRQS - FIRST_USER_IRQ <= 8, ""); // we only use a single byte's worth of claim bits today.
return NUM_IRQS - irq_num - 1u;

View file

@ -27,6 +27,7 @@ cc_library(
deps = [
"//src/rp2040/hardware_regs",
"//src/rp2040/hardware_regs:platform_defs",
"//src/rp2_common/pico_platform_common:pico_platform_common_headers",
"//src/rp2_common/pico_platform_compiler",
"//src/rp2_common/pico_platform_panic:pico_platform_panic_headers",
"//src/rp2_common/pico_platform_sections",
@ -44,6 +45,7 @@ cc_library(
"//src/rp2040/hardware_regs",
"//src/rp2040/hardware_regs:platform_defs",
"//src/rp2_common/hardware_base",
"//src/rp2_common/pico_platform_common",
"//src/rp2_common/pico_platform_compiler",
"//src/rp2_common/pico_platform_panic",
"//src/rp2_common/pico_platform_sections",

View file

@ -17,6 +17,7 @@ if (NOT TARGET pico_platform)
target_link_libraries(pico_platform_headers INTERFACE hardware_regs)
pico_mirrored_target_link_libraries(pico_platform INTERFACE
pico_platform_common
pico_platform_compiler
pico_platform_panic
pico_platform_sections

View file

@ -23,6 +23,7 @@
#include "pico/platform/compiler.h"
#include "pico/platform/sections.h"
#include "pico/platform/panic.h"
#include "pico/platform/common.h"
#include "hardware/regs/addressmap.h"
#include "hardware/regs/sio.h"
@ -66,10 +67,6 @@
#define PICO_RP2040_B2_SUPPORTED 1
#endif
#ifndef PICO_RAM_VECTOR_TABLE_SIZE
#define PICO_RAM_VECTOR_TABLE_SIZE (VTABLE_FIRST_IRQ + NUM_IRQS)
#endif
// PICO_CONFIG: PICO_CLKDIV_ROUND_NEAREST, True if floating point clock divisors should be rounded to the nearest possible clock divisor by default rather than rounding down, type=bool, default=1, group=pico_platform
#ifndef PICO_CLKDIV_ROUND_NEAREST
#define PICO_CLKDIV_ROUND_NEAREST 1
@ -80,16 +77,6 @@
#ifdef __cplusplus
extern "C" {
#endif
/*! \brief No-op function for the body of tight loops
* \ingroup pico_platform
*
* No-op function intended to be called by any tight hardware polling loop. Using this ubiquitously
* makes it much easier to find tight loops, but also in the future \#ifdef-ed support for lockup
* debugging might be added
*/
static __force_inline void tight_loop_contents(void) {}
/*! \brief Helper method to busy-wait for at least the given number of cycles
* \ingroup pico_platform
*
@ -112,17 +99,6 @@ static inline void busy_wait_at_least_cycles(uint32_t minimum_cycles) {
);
}
// PICO_CONFIG: PICO_NO_FPGA_CHECK, Remove the FPGA platform check for small code size reduction, type=bool, default=1, advanced=true, group=pico_runtime
#ifndef PICO_NO_FPGA_CHECK
#define PICO_NO_FPGA_CHECK 1
#endif
#if PICO_NO_FPGA_CHECK
static inline bool running_on_fpga(void) {return false;}
#else
bool running_on_fpga(void);
#endif
/*! \brief Execute a breakpoint instruction
* \ingroup pico_platform
*/
@ -158,9 +134,6 @@ static __force_inline uint __get_current_exception(void) {
return exception;
}
#define host_safe_hw_ptr(x) ((uintptr_t)(x))
#define native_safe_hw_ptr(x) host_safe_hw_ptr(x)
/*! \brief Returns the RP2040 chip revision number
* \ingroup pico_platform
* @return the RP2040 chip revision number (1 for B0/B1, 2 for B2)

View file

@ -6,23 +6,8 @@
#include "pico.h"
#include "hardware/address_mapped.h"
#include "hardware/regs/tbman.h"
#include "hardware/regs/sysinfo.h"
// Note we leave the FPGA check in by default so that we can run bug repro
// binaries coming in from the wild on the FPGA platform. It takes up around
// 48 bytes if you include all the calls, so you can pass PICO_NO_FPGA_CHECK=1
// to remove it. The FPGA check is used to skip initialisation of hardware
// (mainly clock generators and oscillators) that aren't present on FPGA.
#if !PICO_NO_FPGA_CHECK
// Inline stub provided in header if this code is unused (so folding can be
// done in each TU instead of relying on LTO)
bool running_on_fpga(void) {
return (*(io_ro_32 *)TBMAN_BASE) & TBMAN_PLATFORM_FPGA_BITS;
}
#endif
#define MANUFACTURER_RPI 0x927
#define PART_RP2 0x2

View file

@ -27,6 +27,7 @@ cc_library(
deps = [
"//src/rp2350/hardware_regs",
"//src/rp2350/hardware_regs:platform_defs",
"//src/rp2_common/pico_platform_common:pico_platform_common_headers",
"//src/rp2_common/pico_platform_compiler",
"//src/rp2_common/pico_platform_panic:pico_platform_panic_headers",
"//src/rp2_common/pico_platform_sections",
@ -44,6 +45,7 @@ cc_library(
"//src/rp2350/hardware_regs",
"//src/rp2350/hardware_regs:platform_defs",
"//src/rp2_common/hardware_base",
"//src/rp2_common/pico_platform_common",
"//src/rp2_common/pico_platform_compiler",
"//src/rp2_common/pico_platform_panic",
"//src/rp2_common/pico_platform_sections",

View file

@ -23,6 +23,7 @@ if (NOT TARGET pico_platform)
hardware_regs
)
pico_mirrored_target_link_libraries(pico_platform INTERFACE
pico_platform_common
pico_platform_compiler
pico_platform_panic
pico_platform_sections

View file

@ -23,13 +23,14 @@
#include "pico/platform/compiler.h"
#include "pico/platform/sections.h"
#include "pico/platform/panic.h"
#include "pico/platform/common.h"
#include "hardware/regs/addressmap.h"
#include "hardware/regs/sio.h"
#ifdef __riscv
#include "hardware/regs/rvcsr.h"
#endif
// PICO_CONFIG: PICO_RP2350A, Whether the current board has an RP2350 in an A (30 GPIO) package, type=bool, default=Usually provided via board header, group=pico_platform
// PICO_CONFIG: PICO_RP2350A, Whether the current board has an RP2350 in an A (30 GPIO) package - set to 0 for RP2350 in a B (48 GPIO) package, type=bool, default=Usually provided via board header, group=pico_platform
#if 0 // make tooling checks happy
#define PICO_RP2350A 0
#endif
@ -54,10 +55,6 @@
#define PICO_NO_RAM_VECTOR_TABLE 0
#endif
#ifndef PICO_RAM_VECTOR_TABLE_SIZE
#define PICO_RAM_VECTOR_TABLE_SIZE (VTABLE_FIRST_IRQ + NUM_IRQS)
#endif
// PICO_CONFIG: PICO_USE_STACK_GUARDS, Enable/disable stack guards, type=bool, default=0, advanced=true, group=pico_platform
#ifndef PICO_USE_STACK_GUARDS
#define PICO_USE_STACK_GUARDS 0
@ -73,16 +70,6 @@
#ifdef __cplusplus
extern "C" {
#endif
/*! \brief No-op function for the body of tight loops
* \ingroup pico_platform
*
* No-op function intended to be called by any tight hardware polling loop. Using this ubiquitously
* makes it much easier to find tight loops, but also in the future \#ifdef-ed support for lockup
* debugging might be added
*/
static __force_inline void tight_loop_contents(void) {}
/*! \brief Helper method to busy-wait for at least the given number of cycles
* \ingroup pico_platform
*
@ -116,27 +103,6 @@ static inline void busy_wait_at_least_cycles(uint32_t minimum_cycles) {
);
}
// PICO_CONFIG: PICO_NO_FPGA_CHECK, Remove the FPGA platform check for small code size reduction, type=bool, default=1, advanced=true, group=pico_runtime
#ifndef PICO_NO_FPGA_CHECK
#define PICO_NO_FPGA_CHECK 1
#endif
// PICO_CONFIG: PICO_NO_SIM_CHECK, Remove the SIM platform check for small code size reduction, type=bool, default=1, advanced=true, group=pico_runtime
#ifndef PICO_NO_SIM_CHECK
#define PICO_NO_SIM_CHECK 1
#endif
#if PICO_NO_FPGA_CHECK
static inline bool running_on_fpga(void) {return false;}
#else
bool running_on_fpga(void);
#endif
#if PICO_NO_SIM_CHECK
static inline bool running_in_sim(void) {return false;}
#else
bool running_in_sim(void);
#endif
/*! \brief Execute a breakpoint instruction
* \ingroup pico_platform
*/
@ -221,9 +187,6 @@ __force_inline static bool pico_processor_state_is_nonsecure(void) {
#endif
}
#define host_safe_hw_ptr(x) ((uintptr_t)(x))
#define native_safe_hw_ptr(x) host_safe_hw_ptr(x)
/*! \brief Returns the RP2350 chip revision number
* \ingroup pico_platform
* @return the RP2350 chip revision number (1 for B0/B1, 2 for B2)

View file

@ -6,28 +6,8 @@
#include "pico.h"
#include "hardware/address_mapped.h"
#include "hardware/regs/tbman.h"
#include "hardware/regs/sysinfo.h"
// Note we leave the FPGA check in by default so that we can run bug repro
// binaries coming in from the wild on the FPGA platform. It takes up around
// 48 bytes if you include all the calls, so you can pass PICO_NO_FPGA_CHECK=1
// to remove it. The FPGA check is used to skip initialisation of hardware
// (mainly clock generators and oscillators) that aren't present on FPGA.
#if !PICO_NO_FPGA_CHECK
// Inline stub provided in header if this code is unused (so folding can be
// done in each TU instead of relying on LTO)
bool __attribute__((weak)) running_on_fpga(void) {
return (*(io_ro_32 *)TBMAN_BASE) & TBMAN_PLATFORM_FPGA_BITS;
}
#endif
#if !PICO_NO_SIM_CHECK
bool __attribute__((weak)) running_in_sim(void) {
return (*(io_ro_32 *)TBMAN_BASE) & TBMAN_PLATFORM_HDLSIM_BITS;
}
#endif
#define MANUFACTURER_RPI 0x926
#define PART_RP4 0x4
@ -36,9 +16,9 @@ uint8_t rp2350_chip_version(void) {
uint32_t chip_id = *((io_ro_32*)(SYSINFO_BASE + SYSINFO_CHIP_ID_OFFSET));
uint32_t __unused manufacturer = chip_id & SYSINFO_CHIP_ID_MANUFACTURER_BITS;
uint32_t __unused part = (chip_id & SYSINFO_CHIP_ID_PART_BITS) >> SYSINFO_CHIP_ID_PART_LSB;
assert(manufacturer == MANUFACTURER_RPI);
assert(part == PART_RP4);
assert(manufacturer == MANUFACTURER_RPI && part == PART_RP4);
// 0 == A0, 1 == A1, 2 == A2
uint version = (chip_id & SYSINFO_CHIP_ID_REVISION_BITS) >> SYSINFO_CHIP_ID_REVISION_LSB;
uint32_t version = (chip_id & SYSINFO_CHIP_ID_REVISION_BITS) >> SYSINFO_CHIP_ID_REVISION_LSB;
version = (version & 3u) | ((version & 8u) >> 1);
return (uint8_t)version;
}

View file

@ -31,12 +31,14 @@ static inline exception_handler_t *get_exception_table(void) {
#endif
}
#if !PICO_NO_RAM_VECTOR_TABLE
static void set_raw_exception_handler_and_restore_interrupts(enum exception_number num, exception_handler_t handler, uint32_t save) {
// update vtable (vtable_handler may be same or updated depending on cases, but we do it anyway for compactness)
get_exception_table()[num] = handler;
__dmb();
restore_interrupts_from_disabled(save);
}
#endif
static inline void check_exception_param(__unused enum exception_number num) {
invalid_params_if(HARDWARE_EXCEPTION, num < MIN_EXCEPTION_NUM || num > MAX_EXCEPTION_NUM);
@ -54,10 +56,12 @@ exception_handler_t exception_set_exclusive_handler(enum exception_number num, e
exception_handler_t current = exception_get_vtable_handler(num);
hard_assert(handler == current || exception_is_compile_time_default(current));
set_raw_exception_handler_and_restore_interrupts(num, handler, save);
return current;
#else
((void)num);
((void)handler);
panic_unsupported();
#endif
return current;
}
void exception_restore_handler(enum exception_number num, exception_handler_t original_handler) {
@ -66,6 +70,8 @@ void exception_restore_handler(enum exception_number num, exception_handler_t or
uint32_t save = save_and_disable_interrupts();
set_raw_exception_handler_and_restore_interrupts(num, original_handler, save);
#else
((void)num);
((void)original_handler);
panic_unsupported();
#endif
}

View file

@ -195,7 +195,7 @@ extern "C" {
typedef void (*irq_handler_t)(void);
static inline void check_irq_param(__unused uint num) {
invalid_params_if(HARDWARE_IRQ, num >= NUM_IRQS);
invalid_params_if(HARDWARE_IRQ, num >= PICO_NUM_VTABLE_IRQS);
}
/*! \brief Set specified interrupt's priority

View file

@ -57,13 +57,6 @@ static inline void *remove_thumb_bit(void *addr) {
#endif
}
static void set_raw_irq_handler_and_unlock(uint num, irq_handler_t handler, uint32_t save) {
// update vtable (vtable_handler may be same or updated depending on cases, but we do it anyway for compactness)
get_vtable()[VTABLE_FIRST_IRQ + num] = handler;
__dmb();
spin_unlock(spin_lock_instance(PICO_SPINLOCK_ID_IRQ), save);
}
void irq_set_enabled(uint num, bool enabled) {
check_irq_param(num);
// really should update irq_set_mask_enabled?
@ -82,7 +75,7 @@ bool irq_is_enabled(uint num) {
}
static inline void irq_set_mask_n_enabled_internal(uint n, uint32_t mask, bool enabled) {
invalid_params_if(HARDWARE_IRQ, n * 32u >= ((NUM_IRQS + 31u) & ~31u));
invalid_params_if(HARDWARE_IRQ, n * 32u >= ((PICO_NUM_VTABLE_IRQS + 31u) & ~31u));
#if defined(__riscv)
if (enabled) {
hazard3_irqarray_clear(RVCSR_MEIFA_OFFSET, 2 * n, mask & 0xffffu);
@ -135,7 +128,7 @@ void irq_set_pending(uint num) {
#endif
}
#if !PICO_DISABLE_SHARED_IRQ_HANDLERS
#if !PICO_DISABLE_SHARED_IRQ_HANDLERS && !PICO_NO_RAM_VECTOR_TABLE
// limited by 8 bit relative links (and reality)
static_assert(PICO_MAX_SHARED_IRQ_HANDLERS >= 1 && PICO_MAX_SHARED_IRQ_HANDLERS < 0x7f, "");
@ -215,9 +208,17 @@ bool irq_has_shared_handler(uint irq_num) {
return is_shared_irq_raw_handler(handler);
}
#else // PICO_DISABLE_SHARED_IRQ_HANDLERS
static void set_raw_irq_handler_and_unlock(uint num, irq_handler_t handler, uint32_t save) {
// update vtable (vtable_handler may be same or updated depending on cases, but we do it anyway for compactness)
get_vtable()[VTABLE_FIRST_IRQ + num] = handler;
__dmb();
spin_unlock(spin_lock_instance(PICO_SPINLOCK_ID_IRQ), save);
}
#else // PICO_DISABLE_SHARED_IRQ_HANDLERS && PICO_NO_RAM_VECTOR_TABLE
#define is_shared_irq_raw_handler(h) false
bool irq_has_shared_handler(uint irq_num) {
((void)irq_num);
return false;
}
#endif
@ -237,6 +238,7 @@ void irq_set_exclusive_handler(uint num, irq_handler_t handler) {
hard_assert(current == __unhandled_user_irq || current == handler);
set_raw_irq_handler_and_unlock(num, handler, save);
#else
((void)handler);
panic_unsupported();
#endif
}
@ -258,7 +260,7 @@ irq_handler_t irq_get_exclusive_handler(uint num) {
}
#if !PICO_DISABLE_SHARED_IRQ_HANDLERS
#if !PICO_DISABLE_SHARED_IRQ_HANDLERS && !PICO_NO_RAM_VECTOR_TABLE
#ifndef __riscv
@ -368,6 +370,8 @@ static inline int8_t get_slot_index(struct irq_handler_chain_slot *slot) {
void irq_add_shared_handler(uint num, irq_handler_t handler, uint8_t order_priority) {
check_irq_param(num);
#if PICO_NO_RAM_VECTOR_TABLE
((void)handler);
((void)order_priority);
panic_unsupported();
#elif PICO_DISABLE_SHARED_IRQ_HANDLERS
irq_set_exclusive_handler(num, handler);
@ -461,7 +465,7 @@ void irq_add_shared_handler(uint num, irq_handler_t handler, uint8_t order_prior
#endif // !PICO_NO_RAM_VECTOR_TABLE && !PICO_DISABLE_SHARED_IRQ_HANDLERS
}
#if !PICO_DISABLE_SHARED_IRQ_HANDLERS
#if !PICO_DISABLE_SHARED_IRQ_HANDLERS && !PICO_NO_RAM_VECTOR_TABLE
static inline irq_handler_t handler_from_slot(struct irq_handler_chain_slot *slot) {
#ifndef __riscv
return slot->handler;
@ -586,6 +590,8 @@ void irq_remove_handler(uint num, irq_handler_t handler) {
}
set_raw_irq_handler_and_unlock(num, vtable_handler, save);
#else
((void)num);
((void)handler);
panic_unsupported();
#endif
}
@ -626,7 +632,7 @@ uint irq_get_priority(uint num) {
#endif
}
#if !PICO_DISABLE_SHARED_IRQ_HANDLERS
#if !PICO_DISABLE_SHARED_IRQ_HANDLERS && !PICO_NO_RAM_VECTOR_TABLE
// used by irq_handler_chain.S to remove the last link in a handler chain after it executes
// note this must be called only with the last slot in a chain (and during the exception)
void irq_add_tail_to_free_list(struct irq_handler_chain_slot *slot) {
@ -670,7 +676,7 @@ __weak void runtime_init_per_core_irq_priorities(void) {
*p++ = prio4;
}
#else
for (uint i = 0; i < NUM_IRQS; ++i) {
for (uint i = 0; i < PICO_NUM_VTABLE_IRQS; ++i) {
irq_set_priority(i, PICO_DEFAULT_IRQ_PRIORITY);
}
#endif
@ -678,7 +684,7 @@ __weak void runtime_init_per_core_irq_priorities(void) {
}
static uint get_user_irq_claim_index(uint irq_num) {
invalid_params_if(HARDWARE_IRQ, irq_num < FIRST_USER_IRQ || irq_num >= NUM_IRQS);
invalid_params_if(HARDWARE_IRQ, irq_num < FIRST_USER_IRQ || irq_num >= PICO_NUM_VTABLE_IRQS);
// we count backwards from the last, to match the existing hard coded uses of user IRQs in the SDK which were previously using 31
static_assert(NUM_IRQS - FIRST_USER_IRQ <= 8, ""); // we only use a single byte's worth of claim bits today.
return NUM_IRQS - irq_num - 1u;

View file

@ -23,14 +23,23 @@
pico_default_asm_setup
#ifdef PICO_NO_STORED_VECTOR_TABLE
#warning PICO_NO_STORED_VECTOR_TABLE is no longer used. PICO_MINIMAL_STORED_VECTOR_TABLE is not identical but usually serves the same purpose
#endif
.section .vectors, "ax"
.align 2
.global __vectors, __VECTOR_TABLE
.global __vectors, __VECTOR_TABLE, __vectors_end
__VECTOR_TABLE:
__vectors:
.word __StackTop
.word _reset_handler
#if PICO_MINIMAL_STORED_VECTOR_TABLE
.word isr_invalid // NMI
.word isr_invalid // HardFault
#else
.word isr_nmi
.word isr_hardfault
.word isr_invalid // Reserved, should never fire
@ -45,15 +54,9 @@ __vectors:
.word isr_invalid // Reserved, should never fire
.word isr_pendsv
.word isr_systick
#if PICO_NO_STORED_VECTOR_TABLE && !PICO_NO_FLASH // note in no flash binary, we only have the single RAM vector table anyway
#if PICO_NO_RAM_VECTOR_TABLE
#error Can't specify PICO_NO_STORED_VECTOR_TABLE and PICO_NO_RAM_VECTOR_TABLE
#endif
// we don't include any IRQ vectors; we will initialize them during runtime_init in the RAM vector table
#else
.macro if_irq_word num func
.if \num < NUM_IRQS
.if \num < PICO_NUM_VTABLE_IRQS
.word \func
.endif
.endm
@ -142,10 +145,11 @@ if_irq_word 76 isr_irq76
if_irq_word 77 isr_irq77
if_irq_word 78 isr_irq78
if_irq_word 79 isr_irq79
#if NUM_IRQS > 80
#if PICO_NUM_VTABLE_IRQS > 80
#error more IRQ entries required
#endif
#endif
#endif // #if !PICO_MINIMAL_STORED_VECTOR_TABLE
__vectors_end:
// all default exception handlers do nothing, and we can check for them being set to our
// default values by seeing if they point to somewhere between __defaults_isrs_start and __default_isrs_end
@ -164,24 +168,14 @@ __default_isrs_start:
bkpt #0
.endm
// these are separated out for clarity
decl_isr_bkpt isr_invalid
decl_isr_bkpt isr_nmi
decl_isr_bkpt isr_hardfault
decl_isr_bkpt isr_svcall
decl_isr_bkpt isr_pendsv
decl_isr_bkpt isr_systick
.global __default_isrs_end
__default_isrs_end:
.altmacro
.macro decl_isr name
#if !PICO_NO_STORED_VECTOR_TABLE | PICO_NO_FLASH
#if !PICO_MINIMAL_STORED_VECTOR_TABLE | PICO_NO_FLASH
// We declare a weak label, so user can override
.weak \name
#else
// We declare a strong label, so user can't override (their version would not automatically be used)
// We declare a strong global label, so user can't override (their version would not automatically be used)
.global \name
#endif
.type \name,%function
.thumb_func
@ -189,8 +183,14 @@ __default_isrs_end:
.endm
.macro if_irq_decl num func
.if \num < NUM_IRQS
.if \num < PICO_NUM_VTABLE_IRQS
decl_isr \func
.elseif \num < NUM_IRQS
// We declare a strong global label, so user can't override (their version would not automatically be used)
.global \func
.type \func,%function
.thumb_func
\func:
.endif
.endm
@ -274,7 +274,7 @@ if_irq_decl 76 isr_irq76
if_irq_decl 77 isr_irq77
if_irq_decl 78 isr_irq78
if_irq_decl 79 isr_irq79
#if NUM_IRQS > 80
#if PICO_NUM_VTABLE_IRQS > 80
#error more IRQ entries required
#endif
@ -282,12 +282,30 @@ if_irq_decl 79 isr_irq79
.global __unhandled_user_irq
.thumb_func
__unhandled_user_irq:
// if we include the implementation if there could be a valid IRQ hanler in the vtable that uses it
#if !(PICO_NO_RAM_VECTOR_TABLE && PICO_MINIMAL_STORED_VECTOR_TABLE)
mrs r0, ipsr
subs r0, #16
.global unhandled_user_irq_num_in_r0
unhandled_user_irq_num_in_r0:
#endif
// note the next instruction is a breakpoint too, however we have a 2 byte alignment hole
// and it is preferrable to have distinct labels, to inform the user what has happened in the debugger.
bkpt #0
decl_isr_bkpt isr_invalid
#if !PICO_MINIMAL_STORED_VECTOR_TABLE
// these are separated out for clarity
decl_isr_bkpt isr_nmi
decl_isr_bkpt isr_hardfault
decl_isr_bkpt isr_svcall
decl_isr_bkpt isr_pendsv
decl_isr_bkpt isr_systick
#endif
.global __default_isrs_end
__default_isrs_end:
// ----------------------------------------------------------------------------
.section .binary_info_header, "a"

View file

@ -160,64 +160,22 @@ check_irq_before_exit:
addi sp, sp, 80
mret
// Default software vector table for system interrupts, routed through
// mip.meip. Note this is assumed in e.g. hardware_irq to begin exactly 0x34
// words after the hardware vector table indicated by mtvec (defined above).
.p2align 4
.global __soft_vector_table
__soft_vector_table:
.word isr_irq0
.word isr_irq1
.word isr_irq2
.word isr_irq3
.word isr_irq4
.word isr_irq5
.word isr_irq6
.word isr_irq7
.word isr_irq8
.word isr_irq9
.word isr_irq10
.word isr_irq11
.word isr_irq12
.word isr_irq13
.word isr_irq14
.word isr_irq15
.word isr_irq16
.word isr_irq17
.word isr_irq18
.word isr_irq19
.word isr_irq20
.word isr_irq21
.word isr_irq22
.word isr_irq23
.word isr_irq24
.word isr_irq25
.word isr_irq26
.word isr_irq27
.word isr_irq28
.word isr_irq29
.word isr_irq30
.word isr_irq31
.word isr_irq32
.word isr_irq33
.word isr_irq34
.word isr_irq35
.word isr_irq36
.word isr_irq37
.word isr_irq38
.word isr_irq39
.word isr_irq40
.word isr_irq41
.word isr_irq42
.word isr_irq43
.word isr_irq44
.word isr_irq45
.word isr_irq46
.word isr_irq47
.word isr_irq48
.word isr_irq49
.word isr_irq50
.word isr_irq51
.macro vtable_irq_n n
.word isr_irq\n
.endm
.set IRQN, 0
.rept PICO_NUM_VTABLE_IRQS
vtable_irq_n IRQN
.set IRQN, IRQN + 1
.endr
// all default trap handlers do nothing, and we can check for them being set to our
// default values by seeing if they point to somewhere between __defaults_isrs_start and __default_isrs_end
@ -252,58 +210,23 @@ decl_isr isr_riscv_machine_exception
decl_isr_bkpt isr_riscv_machine_timer
decl_isr_bkpt isr_riscv_machine_soft_irq
decl_isr isr_irq0
decl_isr isr_irq1
decl_isr isr_irq2
decl_isr isr_irq3
decl_isr isr_irq4
decl_isr isr_irq5
decl_isr isr_irq6
decl_isr isr_irq7
decl_isr isr_irq8
decl_isr isr_irq9
decl_isr isr_irq10
decl_isr isr_irq11
decl_isr isr_irq12
decl_isr isr_irq13
decl_isr isr_irq14
decl_isr isr_irq15
decl_isr isr_irq16
decl_isr isr_irq17
decl_isr isr_irq18
decl_isr isr_irq19
decl_isr isr_irq20
decl_isr isr_irq21
decl_isr isr_irq22
decl_isr isr_irq23
decl_isr isr_irq24
decl_isr isr_irq25
decl_isr isr_irq26
decl_isr isr_irq27
decl_isr isr_irq28
decl_isr isr_irq29
decl_isr isr_irq30
decl_isr isr_irq31
decl_isr isr_irq32
decl_isr isr_irq33
decl_isr isr_irq34
decl_isr isr_irq35
decl_isr isr_irq36
decl_isr isr_irq37
decl_isr isr_irq38
decl_isr isr_irq39
decl_isr isr_irq40
decl_isr isr_irq41
decl_isr isr_irq42
decl_isr isr_irq43
decl_isr isr_irq44
decl_isr isr_irq45
decl_isr isr_irq46
decl_isr isr_irq47
decl_isr isr_irq48
decl_isr isr_irq49
decl_isr isr_irq50
decl_isr isr_irq51
// Declare all the ISR labels
.macro decl_isr_n n
.if \n < PICO_NUM_VTABLE_IRQS
decl_isr isr_irq\n
.elseif \n < NUM_IRQS
// We declare a strong label, so user can't override, since there is no vtable entry
.type isr_irq\n,%function
.thumb_func
isr_irq\n:
.endif
.endm
.set IRQN, 0
.rept PICO_NUM_VTABLE_IRQS
decl_isr_n IRQN
.set IRQN, IRQN + 1
.endr
// fall through
// All unhandled USER IRQs fall through to here. Note there is no way to get

View file

@ -0,0 +1,25 @@
load("//bazel:defs.bzl", "compatible_with_rp2")
package(default_visibility = ["//visibility:public"])
cc_library(
name = "pico_platform_common_headers",
hdrs = ["include/pico/platform/common.h"],
includes = ["include"],
visibility = [
"//src/rp2040/pico_platform:__pkg__",
"//src/rp2350/pico_platform:__pkg__",
],
)
cc_library(
name = "pico_platform_common",
srcs = ["common.c"],
target_compatible_with = compatible_with_rp2(),
deps = [
":pico_platform_common_headers",
"//src/rp2_common:platform_defs",
"//src/rp2_common/hardware_base",
"//src/common/pico_base_headers",
],
)

View file

@ -0,0 +1,8 @@
if (NOT TARGET pico_platform_common)
pico_add_library(pico_platform_common)
target_sources(pico_platform_common INTERFACE ${CMAKE_CURRENT_LIST_DIR}/common.c)
target_include_directories(pico_platform_common_headers SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include)
target_link_libraries(pico_platform_common_headers INTERFACE hardware_regs)
endif()

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 2025 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico.h"
#include "hardware/address_mapped.h"
#include "hardware/regs/tbman.h"
// Note we leave the FPGA check in by default so that we can run bug repro
// binaries coming in from the wild on the FPGA platform. It takes up around
// 48 bytes if you include all the calls, so you can pass PICO_NO_FPGA_CHECK=1
// to remove it. The FPGA check is used to skip initialisation of hardware
// (mainly clock generators and oscillators) that aren't present on FPGA.
#if !PICO_NO_FPGA_CHECK
// Inline stub provided in header if this code is unused (so folding can be
// done in each TU instead of relying on LTO)
bool __attribute__((weak)) running_on_fpga(void) {
return (*(io_ro_32 *)TBMAN_BASE) & TBMAN_PLATFORM_FPGA_BITS;
}
#endif
#if !PICO_NO_SIM_CHECK
bool __attribute__((weak)) running_in_sim(void) {
return (*(io_ro_32 *)TBMAN_BASE) & TBMAN_PLATFORM_HDLSIM_BITS;
}
#endif

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2025 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_PLATFORM_COMMON_H
#define _PICO_PLATFORM_COMMON_H
/** \file pico/platform/common.h
* \ingroup pico_platform
*
* \brief Macros and definitions common to all rp2 platforms but not specific to any library
*
* This header may be included by assembly code
*
* Note certain library specific defines are defined here when they are interdpedent across libraries,
* but making an explicit library dependency does not make sense.
*/
// PICO_CONFIG: PICO_MINIMAL_STORED_VECTOR_TABLE, Only store a very minimal vector table in the binary on Arm, type=bool, default=0, advanced=true, group=pico_crt0
#ifndef PICO_MINIMAL_STORED_VECTOR_TABLE
#define PICO_MINIMAL_STORED_VECTOR_TABLE 0
#endif
#if PICO_MINIMAL_STORED_VECTOR_TABLE && (PICO_NO_FLASH && !defined(__riscv))
#if PICO_NUM_VTABLE_IRQS
#warning PICO_NUM_VTABLE_IRQS is specied with PICO_MINIMAL_STORED_VECTOR_TABLE for NO_FLASH Arm binary; ignored
#undef PICO_NUM_VTABLE_IRQS
#endif
#define PICO_NUM_VTABLE_IRQS 0
#else
// PICO_CONFIG: PICO_NUM_VTABLE_IRQS, Number of IRQ handlers in the vector table - can be lowered to save space if you aren't using some higher IRQs, type=int, default=NUM_IRQS, group=hardware_irq
#ifndef PICO_NUM_VTABLE_IRQS
#define PICO_NUM_VTABLE_IRQS NUM_IRQS
#endif
#endif
#ifndef __ASSEMBLER__
// PICO_CONFIG: PICO_NO_FPGA_CHECK, Remove the FPGA platform check for small code size reduction, type=bool, default=1, advanced=true, group=pico_runtime
#ifndef PICO_NO_FPGA_CHECK
#define PICO_NO_FPGA_CHECK 1
#endif
// PICO_CONFIG: PICO_NO_SIM_CHECK, Remove the SIM platform check for small code size reduction, type=bool, default=1, advanced=true, group=pico_runtime
#ifndef PICO_NO_SIM_CHECK
#define PICO_NO_SIM_CHECK 1
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if PICO_NO_FPGA_CHECK
static inline bool running_on_fpga(void) {return false;}
#else
bool running_on_fpga(void);
#endif
#if PICO_NO_SIM_CHECK
static inline bool running_in_sim(void) {return false;}
#else
bool running_in_sim(void);
#endif
/*! \brief No-op function for the body of tight loops
* \ingroup pico_platform
*
* No-op function intended to be called by any tight hardware polling loop. Using this ubiquitously
* makes it much easier to find tight loops, but also in the future \#ifdef-ed support for lockup
* debugging might be added
*/
static __force_inline void tight_loop_contents(void) {}
#define host_safe_hw_ptr(x) ((uintptr_t)(x))
#define native_safe_hw_ptr(x) host_safe_hw_ptr(x)
#ifdef __cplusplus
}
#endif
#endif // __ASSEMBLER__
#endif

View file

@ -7,8 +7,8 @@
#ifndef _PICO_PLATFORM_COMPILER_H
#define _PICO_PLATFORM_COMPILER_H
/** \file platform_compiler.h
* \defgroup pico_platform pico_platform
/** \file pico/platform/compiler.h
* \ingroup pico_platform
*
* \brief Macros and definitions (and functions when included by non assembly code) to adapt for different compilers
*

View file

@ -195,23 +195,32 @@ PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_spin_locks_reset, PICO_RUNTIME_INIT_
// RISC-V to have an initial flash-resident vector table at a well-known
// location, unlike Cortex-M which can take an NMI on cycle 0.
#ifndef __riscv
#include "hardware/structs/scb.h"
#include "hardware/irq.h"
#if !PICO_RUNTIME_NO_INIT_INSTALL_RAM_VECTOR_TABLE
uint32_t __attribute__((section(".ram_vector_table"))) ram_vector_table[PICO_RAM_VECTOR_TABLE_SIZE];
#include "hardware/structs/scb.h"
void runtime_init_install_ram_vector_table(void) {
// Note on RISC-V the RAM vector table is initialised during crt0
#if !(PICO_NO_RAM_VECTOR_TABLE || PICO_NO_FLASH) && !defined(__riscv)
#if !PICO_NO_STORED_VECTOR_TABLE
__builtin_memcpy(ram_vector_table, (uint32_t *) scb_hw->vtor, sizeof(ram_vector_table));
#else
__builtin_memcpy(ram_vector_table, (uint32_t *) scb_hw->vtor, MIN(VTABLE_FIRST_IRQ, sizeof(ram_vector_table)));
for(uint i = VTABLE_FIRST_IRQ; i<count_of(ram_vector_table); i++) {
ram_vector_table[i] = (uintptr_t)__unhandled_user_irq;
}
// note that this is not a safely overridable value, you should use override PICO_NUM_VTABLE_IRQs instead.
// keeping around as a #define though as it used to be supported
#ifdef PICO_RAM_VECTOR_TABLE_SIZE
#warning Overriding PICO_RAM_VECTOR_TABLE_SIZE is deprecated; specify PICO_NUM_VTABLE_IRQS instead
#endif
#ifndef PICO_RAM_VECTOR_TABLE_SIZE
#define PICO_RAM_VECTOR_TABLE_SIZE (VTABLE_FIRST_IRQ + PICO_NUM_VTABLE_IRQS)
#endif
uint32_t __attribute__((section(".ram_vector_table"))) ram_vector_table[PICO_RAM_VECTOR_TABLE_SIZE];
void runtime_init_install_ram_vector_table(void) {
// Note on RISC-V the RAM vector table is initialised during crt0
#if !(PICO_NO_RAM_VECTOR_TABLE || PICO_NO_FLASH)
extern uint32_t __vectors;
extern uint32_t __vectors_end;
uint32_t stored_words = &__vectors_end - &__vectors;
__builtin_memcpy(ram_vector_table, &__vectors, 4 * MIN(stored_words, PICO_RAM_VECTOR_TABLE_SIZE));
for(uint i = stored_words; i<count_of(ram_vector_table); i++) {
ram_vector_table[i] = (uintptr_t)__unhandled_user_irq;
}
scb_hw->vtor = (uintptr_t) ram_vector_table;
#endif
}