-
Notifications
You must be signed in to change notification settings - Fork 980
/
platform.h
411 lines (358 loc) · 14.3 KB
/
platform.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_PLATFORM_H_
#define _PICO_PLATFORM_H_
/** \file platform.h
* \defgroup pico_platform pico_platform
*
* Macros and definitions (and functions when included by non assembly code) for the RP2 family device / architecture
* to provide a common abstraction over low level compiler / platform specifics.
*
* This header may be included by assembly code
*/
#include "hardware/platform_defs.h"
// Marker for builds targeting the RP2040
#define PICO_RP2040 1
// PICO_CONFIG: PICO_STACK_SIZE, Stack Size, min=0x100, default=0x800, advanced=true, group=pico_platform
#ifndef PICO_STACK_SIZE
#define PICO_STACK_SIZE _u(0x800)
#endif
// PICO_CONFIG: PICO_HEAP_SIZE, Heap size to reserve, min=0x100, default=0x800, advanced=true, group=pico_platform
#ifndef PICO_HEAP_SIZE
#define PICO_HEAP_SIZE _u(0x800)
#endif
// PICO_CONFIG: PICO_NO_RAM_VECTOR_TABLE, Enable/disable the RAM vector table, type=bool, default=0, advanced=true, group=pico_platform
#ifndef PICO_NO_RAM_VECTOR_TABLE
#define PICO_NO_RAM_VECTOR_TABLE 0
#endif
// PICO_CONFIG: PICO_RP2040_B0_SUPPORTED, Whether to include any specific software support for RP2040 B0 revision, type=bool, default=1, advanced=true, group=pico_platform
#ifndef PICO_RP2040_B0_SUPPORTED
#define PICO_RP2040_B0_SUPPORTED 1
#endif
// PICO_CONFIG: PICO_FLOAT_SUPPORT_ROM_V1, Include float support code for RP2040 B0 when that chip revision is supported , type=bool, default=1, advanced=true, group=pico_platform
#ifndef PICO_FLOAT_SUPPORT_ROM_V1
#define PICO_FLOAT_SUPPORT_ROM_V1 1
#endif
// PICO_CONFIG: PICO_DOUBLE_SUPPORT_ROM_V1, Include double support code for RP2040 B0 when that chip revision is supported , type=bool, default=1, advanced=true, group=pico_platform
#ifndef PICO_DOUBLE_SUPPORT_ROM_V1
#define PICO_DOUBLE_SUPPORT_ROM_V1 1
#endif
// PICO_CONFIG: PICO_RP2040_B1_SUPPORTED, Whether to include any specific software support for RP2040 B1 revision, type=bool, default=1, advanced=true, group=pico_platform
#ifndef PICO_RP2040_B1_SUPPORTED
#define PICO_RP2040_B1_SUPPORTED 1
#endif
// PICO_CONFIG: PICO_RP2040_B2_SUPPORTED, Whether to include any specific software support for RP2040 B2 revision, type=bool, default=1, advanced=true, group=pico_platform
#ifndef PICO_RP2040_B2_SUPPORTED
#define PICO_RP2040_B2_SUPPORTED 1
#endif
// --- remainder of file is not included by assembly code ---
#ifndef __ASSEMBLER__
#include <sys/cdefs.h>
#include "pico/types.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \brief Marker for an interrupt handler
* \ingroup pico_platform
* For example an IRQ handler function called my_interrupt_handler:
*
* void __isr my_interrupt_handler(void) {
*/
#define __isr
/*! \brief Section attribute macro for placement in RAM after the `.data` section
* \ingroup pico_platform
*
* For example a 400 element `uint32_t` array placed after the .data section
*
* uint32_t __after_data("my_group_name") a_big_array[400];
*
* The section attribute is `.after_data.<group>`
*
* \param group a string suffix to use in the section name to distinguish groups that can be linker
* garbage-collected independently
*/
#define __after_data(group) __attribute__((section(".after_data." group)))
/*! \brief Section attribute macro for placement not in flash (i.e in RAM)
* \ingroup pico_platform
*
* For example a 3 element `uint32_t` array placed in RAM (even though it is `static const`)
*
* static const uint32_t __not_in_flash("my_group_name") an_array[3];
*
* The section attribute is `.time_critical.<group>`
*
* \param group a string suffix to use in the section name to distinguish groups that can be linker
* garbage-collected independently
*/
#define __not_in_flash(group) __attribute__((section(".time_critical." group)))
/*! \brief Section attribute macro for placement in the SRAM bank 4 (known as "scratch X")
* \ingroup pico_platform
*
* Scratch X is commonly used for critical data and functions accessed only by one core (when only
* one core is accessing the RAM bank, there is no opportunity for stalls)
*
* For example a `uint32_t` variable placed in "scratch X"
*
* uint32_t __scratch_x("my_group_name") foo = 23;
*
* The section attribute is `.scratch_x.<group>`
*
* \param group a string suffix to use in the section name to distinguish groups that can be linker
* garbage-collected independently
*/
#define __scratch_x(group) __attribute__((section(".scratch_x." group)))
/*! \brief Section attribute macro for placement in the SRAM bank 5 (known as "scratch Y")
* \ingroup pico_platform
*
* Scratch Y is commonly used for critical data and functions accessed only by one core (when only
* one core is accessing the RAM bank, there is no opportunity for stalls)
*
* For example a `uint32_t` variable placed in "scratch Y"
*
* uint32_t __scratch_y("my_group_name") foo = 23;
*
* The section attribute is `.scratch_y.<group>`
*
* \param group a string suffix to use in the section name to distinguish groups that can be linker
* garbage-collected independently
*/
#define __scratch_y(group) __attribute__((section(".scratch_y." group)))
/*! \brief Section attribute macro for data that is to be left uninitialized
* \ingroup pico_platform
*
* Data marked this way will retain its value across a reset (normally uninitialized data - in the .bss
* section) is initialized to zero during runtime initialization
*
* For example a `uint32_t` foo that will retain its value if the program is restarted by reset.
*
* uint32_t __uninitialized_ram("my_group_name") foo;
*
* The section attribute is `.uninitialized_ram.<group>`
*
* \param group a string suffix to use in the section name to distinguish groups that can be linker
* garbage-collected independently
*/
#define __uninitialized_ram(group) __attribute__((section(".uninitialized_ram." #group))) group
/*! \brief Section attribute macro for placement in flash even in a COPY_TO_RAM binary
* \ingroup pico_platform
*
* For example a `uint32_t` variable explicitly placed in flash (it will hard fault if you attempt to write it!)
*
* uint32_t __in_flash("my_group_name") foo = 23;
*
* The section attribute is `.flashdata.<group>`
*
* \param group a string suffix to use in the section name to distinguish groups that can be linker
* garbage-collected independently
*/
#define __in_flash(group) __attribute__((section(".flashdata" group)))
/*! \brief Indicates a function should not be stored in flash
* \ingroup pico_platform
*
* Decorates a function name, such that the function will execute from RAM (assuming it is not inlined
* into a flash function by the compiler)
*
* For example a function called my_func taking an int parameter:
*
* void __not_in_flash_func(my_func)(int some_arg) {
*
* The function is placed in the `.time_critical.<func_name>` linker section
*
* \see __no_inline_not_in_flash_func
*/
#define __not_in_flash_func(func_name) __not_in_flash(__STRING(func_name)) func_name
/*! \brief Indicates a function is time/latency critical and should not run from flash
* \ingroup pico_platform
*
* Decorates a function name, such that the function will execute from RAM (assuming it is not inlined
* into a flash function by the compiler) to avoid possible flash latency. Currently this macro is identical
* in implementation to `__not_in_flash_func`, however the semantics are distinct and a `__time_critical_func`
* may in the future be treated more specially to reduce the overhead when calling such function from a flash
* function.
*
* For example a function called my_func taking an int parameter:
*
* void __time_critical(my_func)(int some_arg) {
*
* The function is placed in the `.time_critical.<func_name>` linker section
*
* \see __not_in_flash_func
*/
#define __time_critical_func(func_name) __not_in_flash_func(func_name)
/*! \brief Indicate a function should not be stored in flash and should not be inlined
* \ingroup pico_platform
*
* Decorates a function name, such that the function will execute from RAM, explicitly marking it as
* noinline to prevent it being inlined into a flash function by the compiler
*
* For example a function called my_func taking an int parameter:
*
* void __no_inline_not_in_flash_func(my_func)(int some_arg) {
*
* The function is placed in the `.time_critical.<func_name>` linker section
*/
#define __no_inline_not_in_flash_func(func_name) __noinline __not_in_flash_func(func_name)
#define __packed_aligned __packed __aligned(4)
/*! \brief Attribute to force inlining of a function regardless of optimization level
* \ingroup pico_platform
*
* For example my_function here will always be inlined:
*
* int __force_inline my_function(int x) {
*
*/
#if defined(__GNUC__) && __GNUC__ <= 7
#define __force_inline inline __always_inline
#else
#define __force_inline __always_inline
#endif
/*! \brief Macro to determine the number of elements in an array
* \ingroup pico_platform
*/
#ifndef count_of
#define count_of(a) (sizeof(a)/sizeof((a)[0]))
#endif
/*! \brief Macro to return the maximum of two comparable values
* \ingroup pico_platform
*/
#ifndef MAX
#define MAX(a, b) ((a)>(b)?(a):(b))
#endif
/*! \brief Macro to return the minimum of two comparable values
* \ingroup pico_platform
*/
#ifndef MIN
#define MIN(a, b) ((b)>(a)?(a):(b))
#endif
/*! \brief Execute a breakpoint instruction
* \ingroup pico_platform
*/
static inline void __breakpoint(void) {
__asm__("bkpt #0");
}
/*! \brief Ensure that the compiler does not move memory access across this method call
* \ingroup pico_platform
*
* For example in the following code:
*
* *some_memory_location = var_a;
* __compiler_memory_barrier();
* uint32_t var_b = *some_other_memory_location
*
* The compiler will not move the load from `some_other_memory_location` above the memory barrier (which it otherwise
* might - even above the memory store!)
*/
__force_inline static void __compiler_memory_barrier(void) {
__asm__ volatile ("" : : : "memory");
}
/*! \brief Macro for converting memory addresses to 32 bit addresses suitable for DMA
* \ingroup pico_platform
*
* This is just a cast to `uintptr_t` on the RP2040, however you may want to use this when developing code
* that also runs in "host" mode. If the host mode is 64 bit and you are embedding data pointers
* in other data (e.g. DMA chaining), then there is a need in "host" mode to convert a 64 bit native
* pointer to a 32 bit value for storage, which can be done using this macro.
*/
#define host_safe_hw_ptr(x) ((uintptr_t)(x))
#define native_safe_hw_ptr(x) host_safe_hw_ptr(x)
/*! \brief Panics with the message "Unsupported"
* \ingroup pico_platform
* \see panic
*/
void __attribute__((noreturn)) panic_unsupported(void);
/*! \brief Displays a panic message and halts execution
* \ingroup pico_platform
*
* An attempt is made to output the message to all registered STDOUT drivers
* after which this method executes a BKPT instruction.
*
* @param fmt format string (printf-like)
* @param ... printf-like arguments
*/
void __attribute__((noreturn)) panic(const char *fmt, ...);
// PICO_CONFIG: PICO_NO_FPGA_CHECK, Remove the FPGA platform check for small code size reduction, type=bool, default=0, advanced=true, group=pico_runtime
#ifndef PICO_NO_FPGA_CHECK
#define PICO_NO_FPGA_CHECK 0
#endif
#if PICO_NO_FPGA_CHECK
static inline bool running_on_fpga(void) {return false;}
#else
bool running_on_fpga(void);
#endif
/*! \brief Returns the RP2040 chip revision number
* \ingroup pico_platform
* @return the RP2040 chip revision number (1 for B0/B1, 2 for B2)
*/
uint8_t rp2040_chip_version(void);
/*! \brief Returns the RP2040 rom version number
* \ingroup pico_platform
* @return the RP2040 rom version number (1 for RP2040-B0, 2 for RP2040-B1, 3 for RP2040-B2)
*/
static inline uint8_t rp2040_rom_version(void) {
return *(uint8_t*)0x13;
}
/*! \brief No-op function for the body of tight loops
* \ingroup pico_platform
*
* Np-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 Multiply two integers using an assembly `MUL` instruction
* \ingroup pico_platform
*
* This multiplies a by b using multiply instruction using the ARM mul instruction regardless of values (the compiler
* might otherwise choose to perform shifts/adds), i.e. this is a 1 cycle operation.
*
* \param a the first operand
* \param b the second operand
* \return a * b
*/
__force_inline static int32_t __mul_instruction(int32_t a, int32_t b) {
asm ("mul %0, %1" : "+l" (a) : "l" (b) : );
return a;
}
/*! \brief multiply two integer values using the fastest method possible
* \ingroup pico_platform
*
* Efficiently multiplies value a by possibly constant value b.
*
* 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
* 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
* and will be used
*
* \param a the first operand
* \param b the second operand
* \return a * b
*/
#define __fast_mul(a, b) __builtin_choose_expr(__builtin_constant_p(b) && !__builtin_constant_p(a), \
(__builtin_popcount(b) >= 2 ? __mul_instruction(a,b) : (a)*(b)), \
(a)*(b))
/*! \brief Utility macro to assert two types are equivalent.
* \ingroup pico_platform
*
* This macro can be useful in other macros along with `typeof` to assert that two parameters are of equivalent type
* (or that a single parameter is of an expected type)
*/
#define __check_type_compatible(type_a, type_b) static_assert(__builtin_types_compatible_p(type_a, type_b), __STRING(type_a) " is not compatible with " __STRING(type_b));
/*! \brief Get the current exception level on this core
* \ingroup pico_platform
*
* \return the exception number if the CPU is handling an exception, or 0 otherwise
*/
uint __get_current_exception(void);
#define WRAPPER_FUNC(x) __wrap_ ## x
#define REAL_FUNC(x) __real_ ## x
#ifdef __cplusplus
}
#endif
#else // __ASSEMBLER__
#define WRAPPER_FUNC_NAME(x) __wrap_##x
#define SECTION_NAME(x) .text.##x
#define RAM_SECTION_NAME(x) .time_critical.##x
#endif // !__ASSEMBLER__
#endif