TNeo  v1.08
tn_arch_cortex_m.h
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * TNeo: real-time kernel initially based on TNKernel
4  *
5  * TNKernel: copyright 2004, 2013 Yuri Tiomkin.
6  * PIC32-specific routines: copyright 2013, 2014 Anders Montonen.
7  * TNeo: copyright 2014 Dmitry Frank.
8  *
9  * TNeo was born as a thorough review and re-implementation of
10  * TNKernel. The new kernel has well-formed code, inherited bugs are fixed
11  * as well as new features being added, and it is tested carefully with
12  * unit-tests.
13  *
14  * API is changed somewhat, so it's not 100% compatible with TNKernel,
15  * hence the new name: TNeo.
16  *
17  * Permission to use, copy, modify, and distribute this software in source
18  * and binary forms and its documentation for any purpose and without fee
19  * is hereby granted, provided that the above copyright notice appear
20  * in all copies and that both that copyright notice and this permission
21  * notice appear in supporting documentation.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE DMITRY FRANK AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DMITRY FRANK OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33  * THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  ******************************************************************************/
36 
37 /**
38  *
39  * \file
40  *
41  * Cortex-M0/M0+/M3/M4/M4F architecture-dependent routines
42  *
43  */
44 
45 #ifndef _TN_ARCH_CORTEX_M_H
46 #define _TN_ARCH_CORTEX_M_H
47 
48 
49 /*******************************************************************************
50  * INCLUDED FILES
51  ******************************************************************************/
52 
53 #include "../tn_arch_detect.h"
54 #include "../../core/tn_cfg_dispatch.h"
55 
56 
57 
58 
59 #ifdef __cplusplus
60 extern "C" { /*}*/
61 #endif
62 
63 
64 /*******************************************************************************
65  * ARCH-DEPENDENT DEFINITIONS
66  ******************************************************************************/
67 
68 
69 
70 
71 
72 
73 
74 #ifndef DOXYGEN_SHOULD_SKIP_THIS
75 
76 #define _TN_PIC32_INTSAVE_DATA_INVALID 0xffffffff
77 
78 #if TN_DEBUG
79 # define _TN_PIC32_INTSAVE_CHECK() \
80 { \
81  if (TN_INTSAVE_VAR == _TN_PIC32_INTSAVE_DATA_INVALID){ \
82  _TN_FATAL_ERROR(""); \
83  } \
84 }
85 #else
86 # define _TN_PIC32_INTSAVE_CHECK() /* nothing */
87 #endif
88 
89 #if defined(__TN_ARCHFEAT_CORTEX_M_ARMv7M_ISA__)
90 /**
91  * FFS - find first set bit. Used in `_find_next_task_to_run()` function.
92  * Say, for `0xa8` it should return `3`.
93  *
94  * May be not defined: in this case, naive algorithm will be used.
95  */
96 #define _TN_FFS(x) ffs_asm(x)
97 int ffs_asm(int x);
98 #endif
99 
100 /**
101  * Used by the kernel as a signal that something really bad happened.
102  * Indicates TNeo bugs as well as illegal kernel usage
103  * (e.g. sleeping in the idle task callback)
104  *
105  * Typically, set to assembler instruction that causes debugger to halt.
106  */
107 
108 #if defined(__TN_COMPILER_IAR__)
109 # define _TN_FATAL_ERROR(error_msg, ...) \
110  {asm("bkpt #0");}
111 #else
112 # define _TN_FATAL_ERROR(error_msg, ...) \
113  {__asm__ volatile("bkpt #0");}
114 #endif
115 
116 
117 
118 /**
119  * \def TN_ARCH_STK_ATTR_BEFORE
120  *
121  * Compiler-specific attribute that should be placed **before** declaration of
122  * array used for stack. It is needed because there are often additional
123  * restrictions applied to alignment of stack, so, to meet them, stack arrays
124  * need to be declared with these macros.
125  *
126  * @see TN_ARCH_STK_ATTR_AFTER
127  */
128 
129 /**
130  * \def TN_ARCH_STK_ATTR_AFTER
131  *
132  * Compiler-specific attribute that should be placed **after** declaration of
133  * array used for stack. It is needed because there are often additional
134  * restrictions applied to alignment of stack, so, to meet them, stack arrays
135  * need to be declared with these macros.
136  *
137  * @see TN_ARCH_STK_ATTR_BEFORE
138  */
139 
140 #if defined(__TN_COMPILER_ARMCC__)
141 
142 # define TN_ARCH_STK_ATTR_BEFORE __align(8)
143 # define TN_ARCH_STK_ATTR_AFTER
144 
145 #elif defined(__TN_COMPILER_GCC__) || defined(__TN_COMPILER_CLANG__)
146 
147 # define TN_ARCH_STK_ATTR_BEFORE
148 # define TN_ARCH_STK_ATTR_AFTER __attribute__((aligned(0x08)))
149 
150 #elif defined(__TN_COMPILER_IAR__)
151 
152 # define TN_ARCH_STK_ATTR_BEFORE
153 # define TN_ARCH_STK_ATTR_AFTER
154 
155 #endif
156 
157 
158 #if defined(__TN_ARCHFEAT_CORTEX_M_FPU__)
159 # define _TN_CORTEX_FPU_CONTEXT_SIZE 32 /* FPU registers: S0 .. S31 */
160 #else
161 # define _TN_CORTEX_FPU_CONTEXT_SIZE 0 /* no FPU registers */
162 #endif
163 
164 
165 /**
166  * Minimum task's stack size, in words, not in bytes; includes a space for
167  * context plus for parameters passed to task's body function.
168  */
169 #define TN_MIN_STACK_SIZE (17 /* context: 17 words */ \
170  + _TN_STACK_OVERFLOW_SIZE_ADD \
171  + _TN_CORTEX_FPU_CONTEXT_SIZE \
172  )
173 
174 /**
175  * Width of `int` type.
176  */
177 #define TN_INT_WIDTH 32
178 
179 /**
180  * Unsigned integer type whose size is equal to the size of CPU register.
181  * Typically it's plain `unsigned int`.
182  */
183 typedef unsigned int TN_UWord;
184 
185 /**
186  * Unsigned integer type that is able to store pointers.
187  * We need it because some platforms don't define `uintptr_t`.
188  * Typically it's `unsigned int`.
189  */
190 typedef unsigned int TN_UIntPtr;
191 
192 /**
193  * Maximum number of priorities available, this value usually matches
194  * `#TN_INT_WIDTH`.
195  *
196  * @see TN_PRIORITIES_CNT
197  */
198 #define TN_PRIORITIES_MAX_CNT TN_INT_WIDTH
199 
200 /**
201  * Value for infinite waiting, usually matches `ULONG_MAX`,
202  * because `#TN_TickCnt` is declared as `unsigned long`.
203  */
204 #define TN_WAIT_INFINITE (TN_TickCnt)0xFFFFFFFF
205 
206 /**
207  * Value for initializing the task's stack
208  */
209 #define TN_FILL_STACK_VAL 0xFEEDFACE
210 
211 
212 
213 
214 /**
215  * Variable name that is used for storing interrupts state
216  * by macros TN_INTSAVE_DATA and friends
217  */
218 #define TN_INTSAVE_VAR tn_save_status_reg
219 
220 /**
221  * Declares variable that is used by macros `TN_INT_DIS_SAVE()` and
222  * `TN_INT_RESTORE()` for storing status register value.
223  *
224  * It is good idea to initially set it to some invalid value,
225  * and if TN_DEBUG is non-zero, check it in TN_INT_RESTORE().
226  * Then, we can catch bugs if someone tries to restore interrupts status
227  * without saving it first.
228  *
229  * @see `TN_INT_DIS_SAVE()`
230  * @see `TN_INT_RESTORE()`
231  */
232 #define TN_INTSAVE_DATA \
233  TN_UWord TN_INTSAVE_VAR = _TN_PIC32_INTSAVE_DATA_INVALID;
234 
235 /**
236  * The same as `#TN_INTSAVE_DATA` but for using in ISR together with
237  * `TN_INT_IDIS_SAVE()`, `TN_INT_IRESTORE()`.
238  *
239  * @see `TN_INT_IDIS_SAVE()`
240  * @see `TN_INT_IRESTORE()`
241  */
242 #define TN_INTSAVE_DATA_INT TN_INTSAVE_DATA
243 
244 /**
245  * \def TN_INT_DIS_SAVE()
246  *
247  * Disable interrupts and return previous value of status register,
248  * atomically. Similar `tn_arch_sr_save_int_dis()`, but implemented
249  * as a macro, so it is potentially faster.
250  *
251  * Uses `#TN_INTSAVE_DATA` as a temporary storage.
252  *
253  * @see `#TN_INTSAVE_DATA`
254  * @see `tn_arch_sr_save_int_dis()`
255  */
256 
257 /**
258  * \def TN_INT_RESTORE()
259  *
260  * Restore previously saved status register.
261  * Similar to `tn_arch_sr_restore()`, but implemented as a macro,
262  * so it is potentially faster.
263  *
264  * Uses `#TN_INTSAVE_DATA` as a temporary storage.
265  *
266  * @see `#TN_INTSAVE_DATA`
267  * @see `tn_arch_sr_save_int_dis()`
268  */
269 
270 #define TN_INT_DIS_SAVE() TN_INTSAVE_VAR = tn_arch_sr_save_int_dis()
271 #define TN_INT_RESTORE() _TN_PIC32_INTSAVE_CHECK(); \
272  tn_arch_sr_restore(TN_INTSAVE_VAR)
273 
274 /**
275  * The same as `TN_INT_DIS_SAVE()` but for using in ISR.
276  *
277  * Uses `#TN_INTSAVE_DATA_INT` as a temporary storage.
278  *
279  * @see `#TN_INTSAVE_DATA_INT`
280  */
281 #define TN_INT_IDIS_SAVE() TN_INT_DIS_SAVE()
282 
283 /**
284  * The same as `TN_INT_RESTORE()` but for using in ISR.
285  *
286  * Uses `#TN_INTSAVE_DATA_INT` as a temporary storage.
287  *
288  * @see `#TN_INTSAVE_DATA_INT`
289  */
290 #define TN_INT_IRESTORE() TN_INT_RESTORE()
291 
292 /**
293  * Returns nonzero if interrupts are disabled, zero otherwise.
294  */
295 #define TN_IS_INT_DISABLED() (_tn_arch_is_int_disabled())
296 
297 /**
298  * Pend context switch from interrupt.
299  */
300 #define _TN_CONTEXT_SWITCH_IPEND_IF_NEEDED() \
301  _tn_context_switch_pend_if_needed()
302 
303 /**
304  * Converts size in bytes to size in `#TN_UWord`.
305  * For 32-bit platforms, we should shift it by 2 bit to the right;
306  * for 16-bit platforms, we should shift it by 1 bit to the right.
307  */
308 #define _TN_SIZE_BYTES_TO_UWORDS(size_in_bytes) ((size_in_bytes) >> 2)
309 
310 #if defined(__TN_COMPILER_ARMCC__)
311 # if TN_FORCED_INLINE
312 # define _TN_INLINE __forceinline
313 # else
314 # define _TN_INLINE __inline
315 # endif
316 # define _TN_STATIC_INLINE static _TN_INLINE
317 # define _TN_VOLATILE_WORKAROUND /* nothing */
318 #elif defined(__TN_COMPILER_GCC__) || defined(__TN_COMPILER_CLANG__)
319 # if TN_FORCED_INLINE
320 # define _TN_INLINE inline __attribute__ ((always_inline))
321 # else
322 # define _TN_INLINE inline
323 # endif
324 # define _TN_STATIC_INLINE static _TN_INLINE
325 # define _TN_VOLATILE_WORKAROUND /* nothing */
326 #elif defined(__TN_COMPILER_IAR__)
327 # if TN_FORCED_INLINE
328 # define _TN_INLINE _Pragma("inline=forced")
329 # else
330 # define _TN_INLINE inline
331 # endif
332 /*
333  * NOTE: for IAR, `_TN_INLINE` should go before `static`, because
334  * when we use forced inline by _Pragma, and `static` is before _Pragma,
335  * then IAR compiler generates a warning that pragma should immediately
336  * precede the declaration.
337  */
338 # define _TN_STATIC_INLINE _TN_INLINE static
339 # define _TN_VOLATILE_WORKAROUND volatile
340 #else
341 # error unknown Cortex compiler
342 #endif
343 
344 #define _TN_ARCH_STACK_PT_TYPE _TN_ARCH_STACK_PT_TYPE__FULL
345 #define _TN_ARCH_STACK_DIR _TN_ARCH_STACK_DIR__DESC
346 
347 #endif //-- DOXYGEN_SHOULD_SKIP_THIS
348 
349 
350 
351 
352 
353 
354 
355 
356 
357 
358 
359 #ifdef __cplusplus
360 } /* extern "C" */
361 #endif
362 
363 #endif // _TN_ARCH_CORTEX_M_H
364 
unsigned int TN_UIntPtr
Unsigned integer type that is able to store pointers.
unsigned int TN_UWord
Unsigned integer type whose size is equal to the size of CPU register.