2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
4 * SPDX-License-Identifier: BSD-3-Clause
8 * \defgroup pico_platform pico_platform
10 * \brief Macros and definitions (and functions when included by non assembly code) for the RP2 family device / architecture
11 * to provide a common abstraction over low level compiler / platform specifics
13 * This header may be included by assembly code
16 #ifndef _PICO_PLATFORM_H
17 #define _PICO_PLATFORM_H
20 #error pico/platform.h should not be included directly; include pico.h instead
23 #include "pico/platform/compiler.h"
24 #include "pico/platform/sections.h"
25 #include "pico/platform/panic.h"
26 #include "hardware/regs/addressmap.h"
27 #include "hardware/regs/sio.h"
29 #include "hardware/regs/rvcsr.h"
32 // 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
33 #if 0 // make tooling checks happy
34 #define PICO_RP2350A 0
37 // PICO_CONFIG: PICO_RP2350_A2_SUPPORTED, Whether to include any specific software support for RP2350 A2 revision, type=bool, default=1, advanced=true, group=pico_platform
38 #ifndef PICO_RP2350_A2_SUPPORTED
39 #define PICO_RP2350_A2_SUPPORTED 1
42 // PICO_CONFIG: PICO_STACK_SIZE, Minimum amount of stack space reserved in the linker script for each core. See also PICO_CORE1_STACK_SIZE, min=0x100, default=0x800, advanced=true, group=pico_platform
43 #ifndef PICO_STACK_SIZE
44 #define PICO_STACK_SIZE _u(0x800)
47 // PICO_CONFIG: PICO_HEAP_SIZE, Minimum amount of heap space reserved by the linker script, min=0x100, default=0x800, advanced=true, group=pico_platform
48 #ifndef PICO_HEAP_SIZE
49 #define PICO_HEAP_SIZE _u(0x800)
52 // PICO_CONFIG: PICO_NO_RAM_VECTOR_TABLE, Enable/disable the RAM vector table, type=bool, default=0, advanced=true, group=pico_platform
53 #ifndef PICO_NO_RAM_VECTOR_TABLE
54 #define PICO_NO_RAM_VECTOR_TABLE 0
57 #ifndef PICO_RAM_VECTOR_TABLE_SIZE
58 #define PICO_RAM_VECTOR_TABLE_SIZE (VTABLE_FIRST_IRQ + NUM_IRQS)
61 // PICO_CONFIG: PICO_USE_STACK_GUARDS, Enable/disable stack guards, type=bool, default=0, advanced=true, group=pico_platform
62 #ifndef PICO_USE_STACK_GUARDS
63 #define PICO_USE_STACK_GUARDS 0
68 /*! \brief No-op function for the body of tight loops
69 * \ingroup pico_platform
71 * No-op function intended to be called by any tight hardware polling loop. Using this ubiquitously
72 * makes it much easier to find tight loops, but also in the future \#ifdef-ed support for lockup
73 * debugging might be added
75 static __force_inline
void tight_loop_contents(void) {}
77 /*! \brief Helper method to busy-wait for at least the given number of cycles
78 * \ingroup pico_platform
80 * This method is useful for introducing very short delays.
82 * This method busy-waits in a tight loop for the given number of system clock cycles. The total wait time is only accurate to within 2 cycles,
83 * and this method uses a loop counter rather than a hardware timer, so the method will always take longer than expected if an
84 * interrupt is handled on the calling core during the busy-wait; you can of course disable interrupts to prevent this.
86 * You can use \ref clock_get_hz(clk_sys) to determine the number of clock cycles per second if you want to convert an actual
87 * time duration to a number of cycles.
89 * \param minimum_cycles the minimum number of system clock cycles to delay for
91 static inline void busy_wait_at_least_cycles(uint32_t minimum_cycles
) {
92 pico_default_asm_volatile (
94 // Note the range is halved on RISC-V due to signed comparison (no carry flag)
96 ".option norvc\n" // force 32 bit addi, so branch prediction guaranteed
106 : "+r" (minimum_cycles
) : : "cc", "memory"
110 // 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
111 #ifndef PICO_NO_FPGA_CHECK
112 #define PICO_NO_FPGA_CHECK 1
115 // 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
116 #ifndef PICO_NO_SIM_CHECK
117 #define PICO_NO_SIM_CHECK 1
120 #if PICO_NO_FPGA_CHECK
121 static inline bool running_on_fpga(void) {return false;}
123 bool running_on_fpga(void);
125 #if PICO_NO_SIM_CHECK
126 static inline bool running_in_sim(void) {return false;}
128 bool running_in_sim(void);
131 /*! \brief Execute a breakpoint instruction
132 * \ingroup pico_platform
134 static __force_inline
void __breakpoint(void) {
138 pico_default_asm_volatile ("bkpt #0" : : : "memory");
142 /*! \brief Get the current core number
143 * \ingroup pico_platform
145 * \return The core number the call was made from
147 __force_inline
static uint
get_core_num(void) {
148 return (*(uint32_t *) (SIO_BASE
+ SIO_CPUID_OFFSET
));
151 /*! \brief Get the current exception level on this core
152 * \ingroup pico_platform
154 * On Cortex-M this is the exception number defined in the architecture
155 * reference, which is equal to VTABLE_FIRST_IRQ + irq num if inside an
156 * interrupt handler. (VTABLE_FIRST_IRQ is defined in platform_defs.h).
158 * On Hazard3, this function returns VTABLE_FIRST_IRQ + irq num if inside of
159 * an external IRQ handler (or a fault from such a handler), and 0 otherwise,
160 * generally aligning with the Cortex-M values.
162 * \return the exception number if the CPU is handling an exception, or 0 otherwise
164 static __force_inline uint
__get_current_exception(void) {
167 pico_default_asm_volatile (
169 : "=r" (meicontext
) : "i" (RVCSR_MEICONTEXT_OFFSET
)
171 if (meicontext
& RVCSR_MEICONTEXT_NOIRQ_BITS
) {
174 return VTABLE_FIRST_IRQ
+ (
175 (meicontext
& RVCSR_MEICONTEXT_IRQ_BITS
) >> RVCSR_MEICONTEXT_IRQ_LSB
180 pico_default_asm_volatile (
189 /*! \brief Return true if executing in the NonSecure state (Arm-only)
190 * \ingroup pico_platform
192 * \return True if currently executing in the NonSecure state on an Arm processor
194 __force_inline
static bool pico_processor_state_is_nonsecure(void) {
196 // todo add a define to disable NS checking at all?
197 // IDAU-Exempt addresses return S=1 when tested in the Secure state,
198 // whereas executing a tt in the NonSecure state will always return S=0.
200 pico_default_asm_volatile (
205 return !(tt
& (1u << 22));
207 // NonSecure is an Arm concept, there is nothing meaningful to return
208 // here. Note it's not possible in general to detect whether you are
209 // executing in U-mode as, for example, M-mode is classically
210 // virtualisable in U-mode.
215 #define host_safe_hw_ptr(x) ((uintptr_t)(x))
216 #define native_safe_hw_ptr(x) host_safe_hw_ptr(x)
218 /*! \brief Returns the RP2350 chip revision number
219 * \ingroup pico_platform
220 * @return the RP2350 chip revision number (1 for B0/B1, 2 for B2)
222 uint8_t rp2350_chip_version(void);
224 /*! \brief Returns the RP2040 chip revision number for compatibility
225 * \ingroup pico_platform
226 * @return 2 RP2040 errata fixed in B2 are fixed in RP2350
228 static inline uint8_t rp2040_chip_version(void) {
232 /*! \brief Returns the RP2040 rom version number
233 * \ingroup pico_platform
234 * @return the RP2040 rom version number (1 for RP2040-B0, 2 for RP2040-B1, 3 for RP2040-B2)
236 static inline uint8_t rp2040_rom_version(void) {
237 GCC_Pragma("GCC diagnostic push")
238 GCC_Pragma("GCC diagnostic ignored \"-Warray-bounds\"")
239 return *(uint8_t*)0x13;
240 GCC_Pragma("GCC diagnostic pop")
243 /*! \brief Multiply two integers using an assembly `MUL` instruction
244 * \ingroup pico_platform
246 * This multiplies a by b using multiply instruction using the ARM mul instruction regardless of values (the compiler
247 * might otherwise choose to perform shifts/adds), i.e. this is a 1 cycle operation.
249 * \param a the first operand
250 * \param b the second operand
253 __force_inline
static int32_t __mul_instruction(int32_t a
, int32_t b
) {
255 __asm ("mul %0, %0, %1" : "+r" (a
) : "r" (b
) : );
257 pico_default_asm ("muls %0, %1" : "+l" (a
) : "l" (b
) : "cc");
262 /*! \brief multiply two integer values using the fastest method possible
263 * \ingroup pico_platform
265 * Efficiently multiplies value a by possibly constant value b.
267 * If b is known to be constant and not zero or a power of 2, then a mul instruction is used rather than gcc's default
268 * which is often a slow combination of shifts and adds. If b is a power of 2 then a single shift is of course preferable
271 * \param a the first operand
272 * \param b the second operand
275 #define __fast_mul(a, b) __builtin_choose_expr(__builtin_constant_p(b) && !__builtin_constant_p(a), \
276 (__builtin_popcount(b) >= 2 ? __mul_instruction(a,b) : (a)*(b)), \
279 #endif // __ASSEMBLER__