TNeoKernel  v1.04
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
tn_arch_pic32.h
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * TNeoKernel: 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  * TNeoKernel: copyright © 2014 Dmitry Frank.
8  *
9  * TNeoKernel 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: TNeoKernel.
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  * PIC32 architecture-dependent routines
42  *
43  */
44 
45 #ifndef _TN_ARCH_PIC32_H
46 #define _TN_ARCH_PIC32_H
47 
48 
49 /*******************************************************************************
50  * INCLUDED FILES
51  ******************************************************************************/
52 
53 #include "../../core/tn_cfg_dispatch.h"
54 
55 
56 
57 
58 #ifdef __cplusplus
59 extern "C" { /*}*/
60 #endif
61 
62 
63 /*******************************************************************************
64  * GLOBAL VARIABLES
65  ******************************************************************************/
66 
67 /// current interrupt nesting count. Used by macros
68 /// `tn_p32_soft_isr()` and `tn_p32_srs_isr()`.
69 extern volatile int tn_p32_int_nest_count;
70 
71 /// saved task stack pointer. Needed when switching stack pointer from
72 /// task stack to interrupt stack.
73 extern void *tn_p32_user_sp;
74 
75 /// saved ISR stack pointer. Needed when switching stack pointer from
76 /// interrupt stack to task stack.
77 extern void *tn_p32_int_sp;
78 
79 
80 
81 
82 
83 
84 
85 
86 #ifndef DOXYGEN_SHOULD_SKIP_THIS
87 
88 #define _TN_PIC32_INTSAVE_DATA_INVALID 0xffffffff
89 
90 #if TN_DEBUG
91 # define _TN_PIC32_INTSAVE_CHECK() \
92 { \
93  if (tn_save_status_reg == _TN_PIC32_INTSAVE_DATA_INVALID){ \
94  _TN_FATAL_ERROR(""); \
95  } \
96 }
97 #else
98 # define _TN_PIC32_INTSAVE_CHECK() /* nothing */
99 #endif
100 
101 /**
102  * FFS - find first set bit. Used in `_find_next_task_to_run()` function.
103  * Say, for `0xa8` it should return `3`.
104  *
105  * May be not defined: in this case, naive algorithm will be used.
106  */
107 #define _TN_FFS(x) (32 - __builtin_clz((x) & (0 - (x))))
108 
109 /**
110  * Used by the kernel as a signal that something really bad happened.
111  * Indicates TNeoKernel bugs as well as illegal kernel usage
112  * (e.g. sleeping in the idle task callback)
113  *
114  * Typically, set to assembler instruction that causes debugger to halt.
115  */
116 #define _TN_FATAL_ERROR(error_msg, ...) \
117  {__asm__ volatile(" sdbbp 0"); __asm__ volatile ("nop");}
118 
119 
120 
121 /**
122  * \def TN_ARCH_STK_ATTR_BEFORE
123  *
124  * Compiler-specific attribute that should be placed **before** declaration of
125  * array used for stack. It is needed because there are often additional
126  * restrictions applied to alignment of stack, so, to meet them, stack arrays
127  * need to be declared with these macros.
128  *
129  * @see TN_ARCH_STK_ATTR_AFTER
130  */
131 
132 /**
133  * \def TN_ARCH_STK_ATTR_AFTER
134  *
135  * Compiler-specific attribute that should be placed **after** declaration of
136  * array used for stack. It is needed because there are often additional
137  * restrictions applied to alignment of stack, so, to meet them, stack arrays
138  * need to be declared with these macros.
139  *
140  * @see TN_ARCH_STK_ATTR_BEFORE
141  */
142 
143 #if defined (__XC32)
144 # define TN_ARCH_STK_ATTR_BEFORE
145 # define TN_ARCH_STK_ATTR_AFTER __attribute__((aligned(0x8)))
146 #else
147 # error "Unknown compiler"
148 #endif
149 
150 /**
151  * Minimum task's stack size, in words, not in bytes; includes a space for
152  * context plus for parameters passed to task's body function.
153  */
154 #define TN_MIN_STACK_SIZE 36
155 
156 /**
157  * Width of `int` type.
158  */
159 #define TN_INT_WIDTH 32
160 
161 /**
162  * Unsigned integer type whose size is equal to the size of CPU register.
163  * Typically it's plain `unsigned int`.
164  */
165 typedef unsigned int TN_UWord;
166 
167 /**
168  * Unsigned integer type that is able to store pointers.
169  * We need it because some platforms don't define `uintptr_t`.
170  * Typically it's `unsigned int`.
171  */
172 typedef unsigned int TN_UIntPtr;
173 
174 /**
175  * Maximum number of priorities available, this value usually matches
176  * `#TN_INT_WIDTH`.
177  *
178  * @see TN_PRIORITIES_CNT
179  */
180 #define TN_PRIORITIES_MAX_CNT TN_INT_WIDTH
181 
182 /**
183  * Value for infinite waiting, usually matches `ULONG_MAX`,
184  * because `#TN_Timeout` is declared as `unsigned long`.
185  */
186 #define TN_WAIT_INFINITE (TN_Timeout)0xFFFFFFFF
187 
188 /**
189  * Value for initializing the task's stack
190  */
191 #define TN_FILL_STACK_VAL 0xFEEDFACE
192 
193 
194 
195 
196 /**
197  * Declares variable that is used by macros `TN_INT_DIS_SAVE()` and
198  * `TN_INT_RESTORE()` for storing status register value.
199  *
200  * It is good idea to initially set it to some invalid value,
201  * and if TN_DEBUG is non-zero, check it in TN_INT_RESTORE().
202  * Then, we can catch bugs if someone tries to restore interrupts status
203  * without saving it first.
204  *
205  * @see `TN_INT_DIS_SAVE()`
206  * @see `TN_INT_RESTORE()`
207  */
208 #define TN_INTSAVE_DATA \
209  int tn_save_status_reg = _TN_PIC32_INTSAVE_DATA_INVALID;
210 
211 /**
212  * The same as `#TN_INTSAVE_DATA` but for using in ISR together with
213  * `TN_INT_IDIS_SAVE()`, `TN_INT_IRESTORE()`.
214  *
215  * @see `TN_INT_IDIS_SAVE()`
216  * @see `TN_INT_IRESTORE()`
217  */
218 #define TN_INTSAVE_DATA_INT TN_INTSAVE_DATA
219 
220 /**
221  * \def TN_INT_DIS_SAVE()
222  *
223  * Disable interrupts and return previous value of status register,
224  * atomically. Similar `tn_arch_sr_save_int_dis()`, but implemented
225  * as a macro, so it is potentially faster.
226  *
227  * Uses `#TN_INTSAVE_DATA` as a temporary storage.
228  *
229  * @see `#TN_INTSAVE_DATA`
230  * @see `tn_arch_sr_save_int_dis()`
231  */
232 
233 /**
234  * \def TN_INT_RESTORE()
235  *
236  * Restore previously saved status register.
237  * Similar to `tn_arch_sr_restore()`, but implemented as a macro,
238  * so it is potentially faster.
239  *
240  * Uses `#TN_INTSAVE_DATA` as a temporary storage.
241  *
242  * @see `#TN_INTSAVE_DATA`
243  * @see `tn_arch_sr_save_int_dis()`
244  */
245 
246 #ifdef __mips16
247 # define TN_INT_DIS_SAVE() tn_save_status_reg = tn_arch_sr_save_int_dis()
248 # define TN_INT_RESTORE() _TN_PIC32_INTSAVE_CHECK(); \
249  tn_arch_sr_restore(tn_save_status_reg)
250 #else
251 # define TN_INT_DIS_SAVE() __asm__ __volatile__( \
252  "di %0; ehb" \
253  : "=d" (tn_save_status_reg) \
254  )
255 # define TN_INT_RESTORE() _TN_PIC32_INTSAVE_CHECK(); \
256  __builtin_mtc0(12, 0, tn_save_status_reg)
257 #endif
258 
259 /**
260  * The same as `TN_INT_DIS_SAVE()` but for using in ISR.
261  *
262  * Uses `#TN_INTSAVE_DATA_INT` as a temporary storage.
263  *
264  * @see `#TN_INTSAVE_DATA_INT`
265  */
266 #define TN_INT_IDIS_SAVE() TN_INT_DIS_SAVE()
267 
268 /**
269  * The same as `TN_INT_RESTORE()` but for using in ISR.
270  *
271  * Uses `#TN_INTSAVE_DATA_INT` as a temporary storage.
272  *
273  * @see `#TN_INTSAVE_DATA_INT`
274  */
275 #define TN_INT_IRESTORE() TN_INT_RESTORE()
276 
277 /**
278  * Returns nonzero if interrupts are disabled, zero otherwise.
279  */
280 #define TN_IS_INT_DISABLED() ((__builtin_mfc0(12, 0) & 1) == 0)
281 
282 /**
283  * Pend context switch from interrupt.
284  */
285 #define _TN_CONTEXT_SWITCH_IPEND_IF_NEEDED() \
286  _tn_context_switch_pend_if_needed()
287 
288 /**
289  * Converts size in bytes to size in `#TN_UWord`.
290  * For 32-bit platforms, we should shift it by 2 bit to the right;
291  * for 16-bit platforms, we should shift it by 1 bit to the right.
292  */
293 #define _TN_SIZE_BYTES_TO_UWORDS(size_in_bytes) ((size_in_bytes) >> 2)
294 
295 
296 
297 #endif //-- DOXYGEN_SHOULD_SKIP_THIS
298 
299 
300 
301 
302 
303 
304 
305 
306 
307 
308 // ---------------------------------------------------------------------------
309 
310 /**
311  * Interrupt handler wrapper macro for software context saving.
312  *
313  * Usage looks like the following:
314  *
315  * tn_p32_soft_isr(_TIMER_1_VECTOR)
316  * {
317  * INTClearFlag(INT_T1);
318  *
319  * //-- do something useful
320  * }
321  *
322  * Note that you should not use `__ISR(_TIMER_1_VECTOR)` macro for that.
323  *
324  * @param vec interrupt vector number, such as `_TIMER_1_VECTOR`, etc.
325  */
326 #define tn_p32_soft_isr(vec) \
327 __attribute__((__noinline__)) void _func##vec(void); \
328 void __attribute__((naked, nomips16)) \
329  __attribute__((vector(vec))) \
330  _isr##vec(void) \
331 { \
332  asm volatile(".set push"); \
333  asm volatile(".set mips32r2"); \
334  asm volatile(".set nomips16"); \
335  asm volatile(".set noreorder"); \
336  asm volatile(".set noat"); \
337  \
338  asm volatile("rdpgpr $sp, $sp"); \
339  \
340  /* Increase interrupt nesting count */ \
341  asm volatile("lui $k0, %hi(tn_p32_int_nest_count)"); \
342  asm volatile("lw $k1, %lo(tn_p32_int_nest_count)($k0)"); \
343  asm volatile("addiu $k1, $k1, 1"); \
344  asm volatile("sw $k1, %lo(tn_p32_int_nest_count)($k0)"); \
345  asm volatile("ori $k0, $zero, 1"); \
346  asm volatile("bne $k1, $k0, 1f"); \
347  \
348  /* Swap stack pointers if nesting count is one */ \
349  asm volatile("lui $k0, %hi(tn_p32_user_sp)"); \
350  asm volatile("sw $sp, %lo(tn_p32_user_sp)($k0)"); \
351  asm volatile("lui $k0, %hi(tn_p32_int_sp)"); \
352  asm volatile("lw $sp, %lo(tn_p32_int_sp)($k0)"); \
353  \
354  asm volatile("1:"); \
355  /* Save context on stack */ \
356  asm volatile("addiu $sp, $sp, -92"); \
357  asm volatile("mfc0 $k1, $14"); /* c0_epc*/ \
358  asm volatile("mfc0 $k0, $12, 2"); /* c0_srsctl*/ \
359  asm volatile("sw $k1, 84($sp)"); \
360  asm volatile("sw $k0, 80($sp)"); \
361  asm volatile("mfc0 $k1, $12"); /* c0_status*/ \
362  asm volatile("sw $k1, 88($sp)"); \
363  \
364  /* Enable nested interrupts */ \
365  asm volatile("mfc0 $k0, $13"); /* c0_cause*/ \
366  asm volatile("ins $k1, $zero, 1, 15"); \
367  asm volatile("ext $k0, $k0, 10, 6"); \
368  asm volatile("ins $k1, $k0, 10, 6"); \
369  asm volatile("mtc0 $k1, $12"); /* c0_status*/ \
370  \
371  /* Save caller-save registers on stack */ \
372  asm volatile("sw $ra, 76($sp)"); \
373  asm volatile("sw $t9, 72($sp)"); \
374  asm volatile("sw $t8, 68($sp)"); \
375  asm volatile("sw $t7, 64($sp)"); \
376  asm volatile("sw $t6, 60($sp)"); \
377  asm volatile("sw $t5, 56($sp)"); \
378  asm volatile("sw $t4, 52($sp)"); \
379  asm volatile("sw $t3, 48($sp)"); \
380  asm volatile("sw $t2, 44($sp)"); \
381  asm volatile("sw $t1, 40($sp)"); \
382  asm volatile("sw $t0, 36($sp)"); \
383  asm volatile("sw $a3, 32($sp)"); \
384  asm volatile("sw $a2, 28($sp)"); \
385  asm volatile("sw $a1, 24($sp)"); \
386  asm volatile("sw $a0, 20($sp)"); \
387  asm volatile("sw $v1, 16($sp)"); \
388  asm volatile("sw $v0, 12($sp)"); \
389  asm volatile("sw $at, 8($sp)"); \
390  asm volatile("mfhi $v0"); \
391  asm volatile("mflo $v1"); \
392  asm volatile("sw $v0, 4($sp)"); \
393  \
394  /* Call ISR */ \
395  asm volatile("la $t0, _func"#vec); \
396  asm volatile("jalr $t0"); \
397  asm volatile("sw $v1, 0($sp)"); \
398  \
399  /* Restore registers */ \
400  asm volatile("lw $v1, 0($sp)"); \
401  asm volatile("lw $v0, 4($sp)"); \
402  asm volatile("mtlo $v1"); \
403  asm volatile("mthi $v0"); \
404  asm volatile("lw $at, 8($sp)"); \
405  asm volatile("lw $v0, 12($sp)"); \
406  asm volatile("lw $v1, 16($sp)"); \
407  asm volatile("lw $a0, 20($sp)"); \
408  asm volatile("lw $a1, 24($sp)"); \
409  asm volatile("lw $a2, 28($sp)"); \
410  asm volatile("lw $a3, 32($sp)"); \
411  asm volatile("lw $t0, 36($sp)"); \
412  asm volatile("lw $t1, 40($sp)"); \
413  asm volatile("lw $t2, 44($sp)"); \
414  asm volatile("lw $t3, 48($sp)"); \
415  asm volatile("lw $t4, 52($sp)"); \
416  asm volatile("lw $t5, 56($sp)"); \
417  asm volatile("lw $t6, 60($sp)"); \
418  asm volatile("lw $t7, 64($sp)"); \
419  asm volatile("lw $t8, 68($sp)"); \
420  asm volatile("lw $t9, 72($sp)"); \
421  asm volatile("lw $ra, 76($sp)"); \
422  \
423  asm volatile("di"); \
424  asm volatile("ehb"); \
425  \
426  /* Restore context */ \
427  asm volatile("lw $k0, 84($sp)"); \
428  asm volatile("mtc0 $k0, $14"); /* c0_epc */ \
429  asm volatile("lw $k0, 80($sp)"); \
430  asm volatile("mtc0 $k0, $12, 2"); /* c0_srsctl */ \
431  asm volatile("addiu $sp, $sp, 92"); \
432  \
433  /* Decrease interrupt nesting count */ \
434  asm volatile("lui $k0, %hi(tn_p32_int_nest_count)"); \
435  asm volatile("lw $k1, %lo(tn_p32_int_nest_count)($k0)"); \
436  asm volatile("addiu $k1, $k1, -1"); \
437  asm volatile("sw $k1, %lo(tn_p32_int_nest_count)($k0)"); \
438  asm volatile("bne $k1, $zero, 1f"); \
439  asm volatile("lw $k1, -4($sp)"); \
440  \
441  /* Swap stack pointers if nesting count is zero */ \
442  asm volatile("lui $k0, %hi(tn_p32_int_sp)"); \
443  asm volatile("sw $sp, %lo(tn_p32_int_sp)($k0)"); \
444  asm volatile("lui $k0, %hi(tn_p32_user_sp)"); \
445  asm volatile("lw $sp, %lo(tn_p32_user_sp)($k0)"); \
446  \
447  asm volatile("1:"); \
448  asm volatile("wrpgpr $sp, $sp"); \
449  asm volatile("mtc0 $k1, $12"); /* c0_status */ \
450  asm volatile("eret"); \
451  \
452  asm volatile(".set pop"); \
453  \
454 } __attribute((__noinline__)) void _func##vec(void)
455 
456 
457 
458 
459 /**
460  * Interrupt handler wrapper macro for shadow register context saving.
461  *
462  * Usage looks like the following:
463  *
464  * tn_p32_srs_isr(_INT_UART_1_VECTOR)
465  * {
466  * INTClearFlag(INT_U1);
467  *
468  * //-- do something useful
469  * }
470  *
471  * Note that you should not use `__ISR(_INT_UART_1_VECTOR)` macro for that.
472  *
473  * @param vec interrupt vector number, such as `_TIMER_1_VECTOR`, etc.
474  */
475 #define tn_p32_srs_isr(vec) \
476 __attribute__((__noinline__)) void _func##vec(void); \
477 void __attribute__((naked, nomips16)) \
478  __attribute__((vector(vec))) \
479  _isr##vec(void) \
480 { \
481  asm volatile(".set push"); \
482  asm volatile(".set mips32r2"); \
483  asm volatile(".set nomips16"); \
484  asm volatile(".set noreorder"); \
485  asm volatile(".set noat"); \
486  \
487  asm volatile("rdpgpr $sp, $sp"); \
488  \
489  /* Increase interrupt nesting count */ \
490  asm volatile("lui $k0, %hi(tn_p32_int_nest_count)"); \
491  asm volatile("lw $k1, %lo(tn_p32_int_nest_count)($k0)"); \
492  asm volatile("addiu $k1, $k1, 1"); \
493  asm volatile("sw $k1, %lo(tn_p32_int_nest_count)($k0)"); \
494  asm volatile("ori $k0, $zero, 1"); \
495  asm volatile("bne $k1, $k0, 1f"); \
496  \
497  /* Swap stack pointers if nesting count is one */ \
498  asm volatile("lui $k0, %hi(tn_p32_user_sp)"); \
499  asm volatile("sw $sp, %lo(tn_p32_user_sp)($k0)"); \
500  asm volatile("lui $k0, %hi(tn_p32_int_sp)"); \
501  asm volatile("lw $sp, %lo(tn_p32_int_sp)($k0)"); \
502  \
503  asm volatile("1:"); \
504  /* Save context on stack */ \
505  asm volatile("addiu $sp, $sp, -20"); \
506  asm volatile("mfc0 $k1, $14"); /* c0_epc */ \
507  asm volatile("mfc0 $k0, $12, 2"); /* c0_srsctl */ \
508  asm volatile("sw $k1, 12($sp)"); \
509  asm volatile("sw $k0, 8($sp)"); \
510  asm volatile("mfc0 $k1, $12"); /* c0_status */ \
511  asm volatile("sw $k1, 16($sp)"); \
512  \
513  /* Enable nested interrupts */ \
514  asm volatile("mfc0 $k0, $13"); /* c0_cause */ \
515  asm volatile("ins $k1, $zero, 1, 15"); \
516  asm volatile("ext $k0, $k0, 10, 6"); \
517  asm volatile("ins $k1, $k0, 10, 6"); \
518  asm volatile("mtc0 $k1, $12"); /* c0_status */ \
519  \
520  /* Save caller-save registers on stack */ \
521  asm volatile("mfhi $v0"); \
522  asm volatile("mflo $v1"); \
523  asm volatile("sw $v0, 4($sp)"); \
524  \
525  /* Call ISR */ \
526  asm volatile("la $t0, _func"#vec); \
527  asm volatile("jalr $t0"); \
528  asm volatile("sw $v1, 0($sp)"); \
529  \
530  /* Restore registers */ \
531  asm volatile("lw $v1, 0($sp)"); \
532  asm volatile("lw $v0, 4($sp)"); \
533  asm volatile("mtlo $v1"); \
534  asm volatile("mthi $v0"); \
535  \
536  asm volatile("di"); \
537  asm volatile("ehb"); \
538  \
539  /* Restore context */ \
540  asm volatile("lw $k0, 12($sp)"); \
541  asm volatile("mtc0 $k0, $14"); /* c0_epc */ \
542  asm volatile("lw $k0, 8($sp)"); \
543  asm volatile("mtc0 $k0, $12, 2"); /* c0_srsctl */ \
544  asm volatile("addiu $sp, $sp, 20"); \
545  \
546  /* Decrease interrupt nesting count */ \
547  asm volatile("lui $k0, %hi(tn_p32_int_nest_count)"); \
548  asm volatile("lw $k1, %lo(tn_p32_int_nest_count)($k0)"); \
549  asm volatile("addiu $k1, $k1, -1"); \
550  asm volatile("sw $k1, %lo(tn_p32_int_nest_count)($k0)"); \
551  asm volatile("bne $k1, $zero, 1f"); \
552  asm volatile("lw $k1, -4($sp)"); \
553  \
554  /* Swap stack pointers if nesting count is zero */ \
555  asm volatile("lui $k0, %hi(tn_p32_int_sp)"); \
556  asm volatile("sw $sp, %lo(tn_p32_int_sp)($k0)"); \
557  asm volatile("lui $k0, %hi(tn_p32_user_sp)"); \
558  asm volatile("lw $sp, %lo(tn_p32_user_sp)($k0)"); \
559  \
560  asm volatile("1:"); \
561  asm volatile("wrpgpr $sp, $sp"); \
562  asm volatile("mtc0 $k1, $12"); /* c0_status */ \
563  asm volatile("eret"); \
564  \
565  asm volatile(".set pop"); \
566  \
567 } __attribute((__noinline__)) void _func##vec(void)
568 
569 
570 /**
571  * For compatibility with old projects, old name of `tn_p32_soft_isr()` macro
572  * is kept; please don't use it in new code.
573  */
574 #define tn_soft_isr tn_p32_soft_isr
575 
576 /**
577  * For compatibility with old projects, old name of `tn_p32_srs_isr()` macro
578  * is kept; please don't use it in new code.
579  */
580 #define tn_srs_isr tn_p32_srs_isr
581 
582 #ifdef __cplusplus
583 } /* extern "C" */
584 #endif
585 
586 #endif // _TN_ARCH_PIC32_H
587 
void * tn_p32_user_sp
saved task stack pointer.
volatile int tn_p32_int_nest_count
current interrupt nesting count.
void * tn_p32_int_sp
saved ISR stack pointer.
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.