xref: /Kernel-v10.6.2/portable/GCC/AVR32_UC3/portmacro.h (revision ef7b253b56c9788077f5ecd6c9deb4021923d646)
1 /*
2  * FreeRTOS Kernel V10.6.2
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT AND BSD-3-Clause
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28 
29 /*This file has been prepared for Doxygen automatic documentation generation.*/
30 /*! \file *********************************************************************
31  *
32  * \brief FreeRTOS port source for AVR32 UC3.
33  *
34  * - Compiler:           GNU GCC for AVR32
35  * - Supported devices:  All AVR32 devices can be used.
36  * - AppNote:
37  *
38  * \author               Atmel Corporation (Now Microchip):
39  *                                        https://www.microchip.com \n
40  *                       Support and FAQ: https://www.microchip.com/support/
41  *
42  *****************************************************************************/
43 
44 /*
45  * Copyright (c) 2007, Atmel Corporation All rights reserved.
46  *
47  * Redistribution and use in source and binary forms, with or without
48  * modification, are permitted provided that the following conditions are met:
49  *
50  * 1. Redistributions of source code must retain the above copyright notice,
51  * this list of conditions and the following disclaimer.
52  *
53  * 2. Redistributions in binary form must reproduce the above copyright notice,
54  * this list of conditions and the following disclaimer in the documentation
55  * and/or other materials provided with the distribution.
56  *
57  * 3. The name of ATMEL may not be used to endorse or promote products derived
58  * from this software without specific prior written permission.
59  *
60  * THIS SOFTWARE IS PROVIDED BY ATMEL ``AS IS'' AND ANY EXPRESS OR IMPLIED
61  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
62  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
63  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
64  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
65  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
66  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
67  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
68  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
69  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70  */
71 
72 #ifndef PORTMACRO_H
73 #define PORTMACRO_H
74 
75 /*-----------------------------------------------------------
76  * Port specific definitions.
77  *
78  * The settings in this file configure FreeRTOS correctly for the
79  * given hardware and compiler.
80  *
81  * These settings should not be altered.
82  *-----------------------------------------------------------
83  */
84 #include <avr32/io.h>
85 #include "intc.h"
86 #include "compiler.h"
87 
88 /* *INDENT-OFF* */
89 #ifdef __cplusplus
90     extern "C" {
91 #endif
92 /* *INDENT-ON* */
93 
94 
95 /* Type definitions. */
96 #define portCHAR        char
97 #define portFLOAT       float
98 #define portDOUBLE      double
99 #define portLONG        long
100 #define portSHORT       short
101 #define portSTACK_TYPE  uint32_t
102 #define portBASE_TYPE   long
103 
104 typedef portSTACK_TYPE StackType_t;
105 typedef long BaseType_t;
106 typedef unsigned long UBaseType_t;
107 
108 #define TASK_DELAY_MS(x)   ( (x)        /portTICK_PERIOD_MS )
109 #define TASK_DELAY_S(x)    ( (x)*1000   /portTICK_PERIOD_MS )
110 #define TASK_DELAY_MIN(x)  ( (x)*60*1000/portTICK_PERIOD_MS )
111 
112 #define configTICK_TC_IRQ             ATPASTE2(AVR32_TC_IRQ, configTICK_TC_CHANNEL)
113 
114 #if( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS )
115     typedef uint16_t TickType_t;
116     #define portMAX_DELAY ( TickType_t ) 0xffff
117 #elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS )
118     typedef uint32_t TickType_t;
119     #define portMAX_DELAY ( TickType_t )    ( 0xFFFFFFFFUL )
120 #else
121     #error configTICK_TYPE_WIDTH_IN_BITS set to unsupported tick type width.
122 #endif
123 /*-----------------------------------------------------------*/
124 
125 /* Architecture specifics. */
126 #define portSTACK_GROWTH      ( -1 )
127 #define portTICK_PERIOD_MS      ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
128 #define portBYTE_ALIGNMENT    4
129 #define portNOP()             {__asm__ __volatile__ ("nop");}
130 /*-----------------------------------------------------------*/
131 
132 
133 /*-----------------------------------------------------------*/
134 
135 /* INTC-specific. */
136 #define DISABLE_ALL_EXCEPTIONS()    Disable_global_exception()
137 #define ENABLE_ALL_EXCEPTIONS()     Enable_global_exception()
138 
139 #define DISABLE_ALL_INTERRUPTS()    Disable_global_interrupt()
140 #define ENABLE_ALL_INTERRUPTS()     Enable_global_interrupt()
141 
142 #define DISABLE_INT_LEVEL(int_lev)  Disable_interrupt_level(int_lev)
143 #define ENABLE_INT_LEVEL(int_lev)   Enable_interrupt_level(int_lev)
144 
145 
146 /*
147  * Debug trace.
148  * Activated if and only if configDBG is nonzero.
149  * Prints a formatted string to stdout.
150  * The current source file name and line number are output with a colon before
151  * the formatted string.
152  * A carriage return and a linefeed are appended to the output.
153  * stdout is redirected to the USART configured by configDBG_USART.
154  * The parameters are the same as for the standard printf function.
155  * There is no return value.
156  * SHALL NOT BE CALLED FROM WITHIN AN INTERRUPT as fputs and printf use malloc,
157  * which is interrupt-unsafe with the current __malloc_lock and __malloc_unlock.
158  */
159 #if configDBG
160 #define portDBG_TRACE(...) \
161 {\
162   fputs(__FILE__ ":" ASTRINGZ(__LINE__) ": ", stdout);\
163   printf(__VA_ARGS__);\
164   fputs("\r\n", stdout);\
165 }
166 #else
167 #define portDBG_TRACE(...)
168 #endif
169 
170 
171 /* Critical section management. */
172 #define portDISABLE_INTERRUPTS()  DISABLE_ALL_INTERRUPTS()
173 #define portENABLE_INTERRUPTS()   ENABLE_ALL_INTERRUPTS()
174 
175 
176 extern void vPortEnterCritical( void );
177 extern void vPortExitCritical( void );
178 
179 #define portENTER_CRITICAL()      vPortEnterCritical();
180 #define portEXIT_CRITICAL()       vPortExitCritical();
181 
182 
183 /* Added as there is no such function in FreeRTOS. */
184 extern void *pvPortRealloc( void *pv, size_t xSize );
185 /*-----------------------------------------------------------*/
186 
187 
188 /*=============================================================================================*/
189 
190 /*
191  * Restore Context for cases other than INTi.
192  */
193 #define portRESTORE_CONTEXT()                                                           \
194 {                                                                                       \
195   extern volatile uint32_t ulCriticalNesting;                                   \
196   extern volatile void *volatile pxCurrentTCB;                                          \
197                                                                                         \
198   __asm__ __volatile__ (                                                                \
199     /* Set SP to point to new stack */                                                  \
200     "mov     r8, LO(%[pxCurrentTCB])                                                    \n\t"\
201     "orh     r8, HI(%[pxCurrentTCB])                                                    \n\t"\
202     "ld.w    r0, r8[0]                                                                  \n\t"\
203     "ld.w    sp, r0[0]                                                                  \n\t"\
204                                                                                         \
205     /* Restore ulCriticalNesting variable */                                            \
206     "ld.w    r0, sp++                                                                   \n\t"\
207     "mov     r8, LO(%[ulCriticalNesting])                                               \n\t"\
208     "orh     r8, HI(%[ulCriticalNesting])                                               \n\t"\
209     "st.w    r8[0], r0                                                                  \n\t"\
210                                                                                         \
211     /* Restore R0..R7 */                                                                \
212     "ldm     sp++, r0-r7                                                                \n\t"\
213     /* R0-R7 should not be used below this line */                                      \
214     /* Skip PC and SR (will do it at the end) */                                        \
215     "sub     sp, -2*4                                                                   \n\t"\
216     /* Restore R8..R12 and LR */                                                        \
217     "ldm     sp++, r8-r12, lr                                                           \n\t"\
218     /* Restore SR */                                                                    \
219     "ld.w    r0, sp[-8*4]\n\t" /* R0 is modified, is restored later. */                 \
220     "mtsr    %[SR], r0                                                                  \n\t"\
221     /* Restore r0 */                                                                    \
222     "ld.w    r0, sp[-9*4]                                                               \n\t"\
223     /* Restore PC */                                                                    \
224     "ld.w    pc, sp[-7*4]" /* Get PC from stack - PC is the 7th register saved */       \
225     :                                                                                   \
226     : [ulCriticalNesting] "i" (&ulCriticalNesting),                                     \
227       [pxCurrentTCB] "i" (&pxCurrentTCB),                                               \
228       [SR] "i" (AVR32_SR)                                                               \
229   );                                                                                    \
230 }
231 
232 
233 /*
234  * portSAVE_CONTEXT_INT() and portRESTORE_CONTEXT_INT(): for INT0..3 exceptions.
235  * portSAVE_CONTEXT_SCALL() and portRESTORE_CONTEXT_SCALL(): for the scall exception.
236  *
237  * Had to make different versions because registers saved on the system stack
238  * are not the same between INT0..3 exceptions and the scall exception.
239  */
240 
241 // Task context stack layout:
242   // R8  (*)
243   // R9  (*)
244   // R10 (*)
245   // R11 (*)
246   // R12 (*)
247   // R14/LR (*)
248   // R15/PC (*)
249   // SR (*)
250   // R0
251   // R1
252   // R2
253   // R3
254   // R4
255   // R5
256   // R6
257   // R7
258   // ulCriticalNesting
259 // (*) automatically done for INT0..INT3, but not for SCALL
260 
261 /*
262  * The ISR used for the scheduler tick depends on whether the cooperative or
263  * the preemptive scheduler is being used.
264  */
265 #if configUSE_PREEMPTION == 0
266 
267 /*
268  * portSAVE_CONTEXT_OS_INT() for OS Tick exception.
269  */
270 #define portSAVE_CONTEXT_OS_INT()                                                       \
271 {                                                                                       \
272   /* Save R0..R7 */                                                                     \
273   __asm__ __volatile__ ("stm     --sp, r0-r7");                                         \
274                                                                                         \
275   /* With the cooperative scheduler, as there is no context switch by interrupt, */     \
276   /* there is also no context save. */                                                  \
277 }
278 
279 /*
280  * portRESTORE_CONTEXT_OS_INT() for Tick exception.
281  */
282 #define portRESTORE_CONTEXT_OS_INT()                                                    \
283 {                                                                                       \
284   __asm__ __volatile__ (                                                                \
285     /* Restore R0..R7 */                                                                \
286     "ldm     sp++, r0-r7\n\t"                                                           \
287                                                                                         \
288     /* With the cooperative scheduler, as there is no context switch by interrupt, */   \
289     /* there is also no context restore. */                                             \
290     "rete"                                                                              \
291   );                                                                                    \
292 }
293 
294 #else
295 
296 /*
297  * portSAVE_CONTEXT_OS_INT() for OS Tick exception.
298  */
299 #define portSAVE_CONTEXT_OS_INT()                                                                   \
300 {                                                                                                   \
301   extern volatile uint32_t ulCriticalNesting;                                               \
302   extern volatile void *volatile pxCurrentTCB;                                                      \
303                                                                                                     \
304   /* When we come here */                                                                           \
305   /* Registers R8..R12, LR, PC and SR had already been pushed to system stack */                    \
306                                                                                                     \
307   __asm__ __volatile__ (                                                                            \
308     /* Save R0..R7 */                                                                               \
309     "stm     --sp, r0-r7                                                                            \n\t"\
310                                                                                                     \
311     /* Save ulCriticalNesting variable  - R0 is overwritten */                                      \
312     "mov     r8, LO(%[ulCriticalNesting])\n\t"                                                      \
313     "orh     r8, HI(%[ulCriticalNesting])\n\t"                                                      \
314     "ld.w    r0, r8[0]                                                                              \n\t"\
315     "st.w    --sp, r0                                                                               \n\t"\
316                                                                                                     \
317     /* Check if INT0 or higher were being handled (case where the OS tick interrupted another */    \
318     /* interrupt handler (which was of a higher priority level but decided to lower its priority */ \
319     /* level and allow other lower interrupt level to occur). */                                    \
320     /* In this case we don't want to do a task switch because we don't know what the stack */       \
321     /* currently looks like (we don't know what the interrupted interrupt handler was doing). */    \
322     /* Saving SP in pxCurrentTCB and then later restoring it (thinking restoring the task) */       \
323     /* will just be restoring the interrupt handler, no way!!! */                                   \
324     /* So, since we won't do a vTaskSwitchContext(), it's of no use to save SP. */                  \
325     "ld.w    r0, sp[9*4]\n\t" /* Read SR in stack */                                                \
326     "bfextu  r0, r0, 22, 3\n\t" /* Extract the mode bits to R0. */                                  \
327     "cp.w    r0, 1\n\t" /* Compare the mode bits with supervisor mode(b'001) */                     \
328     "brhi    LABEL_INT_SKIP_SAVE_CONTEXT_%[LINE]                                                    \n\t"\
329                                                                                                     \
330     /* Store SP in the first member of the structure pointed to by pxCurrentTCB */                  \
331     /* NOTE: we don't enter a critical section here because all interrupt handlers */               \
332     /* MUST perform a SAVE_CONTEXT/RESTORE_CONTEXT in the same way as */                            \
333     /* portSAVE_CONTEXT_OS_INT/port_RESTORE_CONTEXT_OS_INT if they call OS functions. */            \
334     /* => all interrupt handlers must use portENTER_SWITCHING_ISR/portEXIT_SWITCHING_ISR. */        \
335     "mov     r8, LO(%[pxCurrentTCB])\n\t"                                                           \
336     "orh     r8, HI(%[pxCurrentTCB])\n\t"                                                           \
337     "ld.w    r0, r8[0]\n\t"                                                                         \
338     "st.w    r0[0], sp\n"                                                                           \
339                                                                                                     \
340     "LABEL_INT_SKIP_SAVE_CONTEXT_%[LINE]:"                                                          \
341     :                                                                                               \
342     : [ulCriticalNesting] "i" (&ulCriticalNesting),                                                 \
343       [pxCurrentTCB] "i" (&pxCurrentTCB),                                                           \
344       [LINE] "i" (__LINE__)                                                                         \
345   );                                                                                                \
346 }
347 
348 /*
349  * portRESTORE_CONTEXT_OS_INT() for Tick exception.
350  */
351 #define portRESTORE_CONTEXT_OS_INT()                                                                \
352 {                                                                                                   \
353   extern volatile uint32_t ulCriticalNesting;                                               \
354   extern volatile void *volatile pxCurrentTCB;                                                      \
355                                                                                                     \
356   /* Check if INT0 or higher were being handled (case where the OS tick interrupted another */      \
357   /* interrupt handler (which was of a higher priority level but decided to lower its priority */   \
358   /* level and allow other lower interrupt level to occur). */                                      \
359   /* In this case we don't want to do a task switch because we don't know what the stack */         \
360   /* currently looks like (we don't know what the interrupted interrupt handler was doing). */      \
361   /* Saving SP in pxCurrentTCB and then later restoring it (thinking restoring the task) */         \
362   /* will just be restoring the interrupt handler, no way!!! */                                     \
363   __asm__ __volatile__ (                                                                            \
364     "ld.w    r0, sp[9*4]\n\t" /* Read SR in stack */                                                \
365     "bfextu  r0, r0, 22, 3\n\t" /* Extract the mode bits to R0. */                                  \
366     "cp.w    r0, 1\n\t" /* Compare the mode bits with supervisor mode(b'001) */                     \
367     "brhi    LABEL_INT_SKIP_RESTORE_CONTEXT_%[LINE]"                                                \
368     :                                                                                               \
369     : [LINE] "i" (__LINE__)                                                                         \
370   );                                                                                                \
371                                                                                                     \
372   /* Else */                                                                                        \
373   /* because it is here safe, always call vTaskSwitchContext() since an OS tick occurred. */        \
374   /* A critical section has to be used here because vTaskSwitchContext handles FreeRTOS linked lists. */\
375   portENTER_CRITICAL();                                                                             \
376   vTaskSwitchContext();                                                                             \
377   portEXIT_CRITICAL();                                                                              \
378                                                                                                     \
379   /* Restore all registers */                                                                       \
380                                                                                                     \
381   __asm__ __volatile__ (                                                                            \
382     /* Set SP to point to new stack */                                                              \
383     "mov     r8, LO(%[pxCurrentTCB])                                                                \n\t"\
384     "orh     r8, HI(%[pxCurrentTCB])                                                                \n\t"\
385     "ld.w    r0, r8[0]                                                                              \n\t"\
386     "ld.w    sp, r0[0]                                                                              \n"\
387                                                                                                     \
388     "LABEL_INT_SKIP_RESTORE_CONTEXT_%[LINE]:                                                        \n\t"\
389                                                                                                     \
390     /* Restore ulCriticalNesting variable */                                                        \
391     "ld.w    r0, sp++                                                                               \n\t"                                                                           \
392     "mov     r8, LO(%[ulCriticalNesting])                                                           \n\t"\
393     "orh     r8, HI(%[ulCriticalNesting])                                                           \n\t"\
394     "st.w    r8[0], r0                                                                              \n\t"\
395                                                                                                     \
396     /* Restore R0..R7 */                                                                            \
397     "ldm     sp++, r0-r7                                                                            \n\t"\
398                                                                                                     \
399     /* Now, the stack should be R8..R12, LR, PC and SR */                                           \
400     "rete"                                                                                          \
401     :                                                                                               \
402     : [ulCriticalNesting] "i" (&ulCriticalNesting),                                                 \
403       [pxCurrentTCB] "i" (&pxCurrentTCB),                                                           \
404       [LINE] "i" (__LINE__)                                                                         \
405   );                                                                                                \
406 }
407 
408 #endif
409 
410 
411 /*
412  * portSAVE_CONTEXT_SCALL() for SupervisorCALL exception.
413  *
414  * NOTE: taskYIELD()(== SCALL) MUST NOT be called in a mode > supervisor mode.
415  *
416  */
417 #define portSAVE_CONTEXT_SCALL()                                                            \
418 {                                                                                           \
419   extern volatile uint32_t ulCriticalNesting;                                       \
420   extern volatile void *volatile pxCurrentTCB;                                              \
421                                                                                             \
422   /* Warning: the stack layout after SCALL doesn't match the one after an interrupt. */     \
423   /* If SR[M2:M0] == 001 */                                                                 \
424   /*    PC and SR are on the stack.  */                                                     \
425   /* Else (other modes) */                                                                  \
426   /*    Nothing on the stack. */                                                            \
427                                                                                             \
428   /* WARNING NOTE: the else case cannot happen as it is strictly forbidden to call */       \
429   /* vTaskDelay() and vTaskDelayUntil() OS functions (that result in a taskYield()) */      \
430   /* in an interrupt|exception handler. */                                                  \
431                                                                                             \
432   __asm__ __volatile__ (                                                                    \
433     /* in order to save R0-R7 */                                                            \
434     "sub     sp, 6*4                                                                        \n\t"\
435     /* Save R0..R7 */                                                                       \
436     "stm     --sp, r0-r7                                                                    \n\t"\
437                                                                                             \
438     /* in order to save R8-R12 and LR */                                                    \
439     /* do not use SP if interrupts occurs, SP must be left at bottom of stack */            \
440     "sub     r7, sp,-16*4                                                                   \n\t"\
441     /* Copy PC and SR in other places in the stack. */                                      \
442     "ld.w    r0, r7[-2*4]                                                                   \n\t" /* Read SR */\
443     "st.w    r7[-8*4], r0                                                                   \n\t" /* Copy SR */\
444     "ld.w    r0, r7[-1*4]                                                                   \n\t" /* Read PC */\
445     "st.w    r7[-7*4], r0                                                                   \n\t" /* Copy PC */\
446                                                                                             \
447     /* Save R8..R12 and LR on the stack. */                                                 \
448     "stm     --r7, r8-r12, lr                                                               \n\t"\
449                                                                                             \
450     /* Arriving here we have the following stack organizations: */                          \
451     /* R8..R12, LR, PC, SR, R0..R7. */                                                      \
452                                                                                             \
453     /* Now we can finalize the save. */                                                     \
454                                                                                             \
455     /* Save ulCriticalNesting variable  - R0 is overwritten */                              \
456     "mov     r8, LO(%[ulCriticalNesting])                                                   \n\t"\
457     "orh     r8, HI(%[ulCriticalNesting])                                                   \n\t"\
458     "ld.w    r0, r8[0]                                                                      \n\t"\
459     "st.w    --sp, r0"                                                                      \
460     :                                                                                       \
461     : [ulCriticalNesting] "i" (&ulCriticalNesting)                                          \
462   );                                                                                        \
463                                                                                             \
464   /* Disable the its which may cause a context switch (i.e. cause a change of */            \
465   /* pxCurrentTCB). */                                                                      \
466   /* Basically, all accesses to the pxCurrentTCB structure should be put in a */            \
467   /* critical section because it is a global structure. */                                  \
468   portENTER_CRITICAL();                                                                     \
469                                                                                             \
470   /* Store SP in the first member of the structure pointed to by pxCurrentTCB */            \
471   __asm__ __volatile__ (                                                                    \
472     "mov     r8, LO(%[pxCurrentTCB])                                                        \n\t"\
473     "orh     r8, HI(%[pxCurrentTCB])                                                        \n\t"\
474     "ld.w    r0, r8[0]                                                                      \n\t"\
475     "st.w    r0[0], sp"                                                                     \
476     :                                                                                       \
477     : [pxCurrentTCB] "i" (&pxCurrentTCB)                                                    \
478   );                                                                                        \
479 }
480 
481 /*
482  * portRESTORE_CONTEXT() for SupervisorCALL exception.
483  */
484 #define portRESTORE_CONTEXT_SCALL()                                                         \
485 {                                                                                           \
486   extern volatile uint32_t ulCriticalNesting;                                       \
487   extern volatile void *volatile pxCurrentTCB;                                              \
488                                                                                             \
489   /* Restore all registers */                                                               \
490                                                                                             \
491   /* Set SP to point to new stack */                                                        \
492   __asm__ __volatile__ (                                                                    \
493     "mov     r8, LO(%[pxCurrentTCB])                                                        \n\t"\
494     "orh     r8, HI(%[pxCurrentTCB])                                                        \n\t"\
495     "ld.w    r0, r8[0]                                                                      \n\t"\
496     "ld.w    sp, r0[0]"                                                                     \
497     :                                                                                       \
498     : [pxCurrentTCB] "i" (&pxCurrentTCB)                                                    \
499   );                                                                                        \
500                                                                                             \
501   /* Leave pxCurrentTCB variable access critical section */                                 \
502   portEXIT_CRITICAL();                                                                      \
503                                                                                             \
504   __asm__ __volatile__ (                                                                    \
505     /* Restore ulCriticalNesting variable */                                                \
506     "ld.w    r0, sp++                                                                       \n\t"\
507     "mov     r8, LO(%[ulCriticalNesting])                                                   \n\t"\
508     "orh     r8, HI(%[ulCriticalNesting])                                                   \n\t"\
509     "st.w    r8[0], r0                                                                      \n\t"\
510                                                                                             \
511     /* skip PC and SR */                                                                    \
512     /* do not use SP if interrupts occurs, SP must be left at bottom of stack */            \
513     "sub     r7, sp, -10*4                                                                  \n\t"\
514     /* Restore r8-r12 and LR */                                                             \
515     "ldm     r7++, r8-r12, lr                                                               \n\t"\
516                                                                                             \
517     /* RETS will take care of the extra PC and SR restore. */                               \
518     /* So, we have to prepare the stack for this. */                                        \
519     "ld.w    r0, r7[-8*4]                                                                   \n\t" /* Read SR */\
520     "st.w    r7[-2*4], r0                                                                   \n\t" /* Copy SR */\
521     "ld.w    r0, r7[-7*4]                                                                   \n\t" /* Read PC */\
522     "st.w    r7[-1*4], r0                                                                   \n\t" /* Copy PC */\
523                                                                                             \
524     /* Restore R0..R7 */                                                                    \
525     "ldm     sp++, r0-r7                                                                    \n\t"\
526                                                                                             \
527     "sub     sp, -6*4                                                                       \n\t"\
528                                                                                             \
529     "rets"                                                                                  \
530     :                                                                                       \
531     : [ulCriticalNesting] "i" (&ulCriticalNesting)                                          \
532   );                                                                                        \
533 }
534 
535 
536 /*
537  * The ISR used depends on whether the cooperative or
538  * the preemptive scheduler is being used.
539  */
540 #if configUSE_PREEMPTION == 0
541 
542 /*
543  * ISR entry and exit macros.  These are only required if a task switch
544  * is required from the ISR.
545  */
546 #define portENTER_SWITCHING_ISR()                                                           \
547 {                                                                                           \
548   /* Save R0..R7 */                                                                         \
549   __asm__ __volatile__ ("stm     --sp, r0-r7");                                             \
550                                                                                             \
551   /* With the cooperative scheduler, as there is no context switch by interrupt, */         \
552   /* there is also no context save. */                                                      \
553 }
554 
555 /*
556  * Input parameter: in R12, boolean. Perform a vTaskSwitchContext() if 1
557  */
558 #define portEXIT_SWITCHING_ISR()                                                            \
559 {                                                                                           \
560   __asm__ __volatile__ (                                                                    \
561     /* Restore R0..R7 */                                                                    \
562     "ldm     sp++, r0-r7                                                                    \n\t"\
563                                                                                             \
564     /* With the cooperative scheduler, as there is no context switch by interrupt, */       \
565     /* there is also no context restore. */                                                 \
566     "rete"                                                                                  \
567   );                                                                                        \
568 }
569 
570 #else
571 
572 /*
573  * ISR entry and exit macros.  These are only required if a task switch
574  * is required from the ISR.
575  */
576 #define portENTER_SWITCHING_ISR()                                                           \
577 {                                                                                           \
578   extern volatile uint32_t ulCriticalNesting;                                       \
579   extern volatile void *volatile pxCurrentTCB;                                              \
580                                                                                             \
581   /* When we come here */                                                                   \
582   /* Registers R8..R12, LR, PC and SR had already been pushed to system stack */            \
583                                                                                             \
584   __asm__ __volatile__ (                                                                    \
585     /* Save R0..R7 */                                                                       \
586     "stm     --sp, r0-r7                                                                    \n\t"\
587                                                                                             \
588     /* Save ulCriticalNesting variable  - R0 is overwritten */                              \
589     "mov     r8, LO(%[ulCriticalNesting])                                                   \n\t"\
590     "orh     r8, HI(%[ulCriticalNesting])                                                   \n\t"\
591     "ld.w    r0, r8[0]                                                                      \n\t"\
592     "st.w    --sp, r0                                                                       \n\t"\
593                                                                                                     \
594     /* Check if INT0 or higher were being handled (case where the OS tick interrupted another */    \
595     /* interrupt handler (which was of a higher priority level but decided to lower its priority */ \
596     /* level and allow other lower interrupt level to occur). */                                    \
597     /* In this case we don't want to do a task switch because we don't know what the stack */       \
598     /* currently looks like (we don't know what the interrupted interrupt handler was doing). */    \
599     /* Saving SP in pxCurrentTCB and then later restoring it (thinking restoring the task) */       \
600     /* will just be restoring the interrupt handler, no way!!! */                                   \
601     /* So, since we won't do a vTaskSwitchContext(), it's of no use to save SP. */                  \
602     "ld.w    r0, sp[9*4]                                                                    \n\t" /* Read SR in stack */\
603     "bfextu  r0, r0, 22, 3                                                                  \n\t" /* Extract the mode bits to R0. */\
604     "cp.w    r0, 1                                                                          \n\t" /* Compare the mode bits with supervisor mode(b'001) */\
605     "brhi    LABEL_ISR_SKIP_SAVE_CONTEXT_%[LINE]                                            \n\t"\
606                                                                                             \
607     /* Store SP in the first member of the structure pointed to by pxCurrentTCB */          \
608     "mov     r8, LO(%[pxCurrentTCB])                                                        \n\t"\
609     "orh     r8, HI(%[pxCurrentTCB])                                                        \n\t"\
610     "ld.w    r0, r8[0]                                                                      \n\t"\
611     "st.w    r0[0], sp                                                                      \n"\
612                                                                                             \
613     "LABEL_ISR_SKIP_SAVE_CONTEXT_%[LINE]:"                                                  \
614     :                                                                                       \
615     : [ulCriticalNesting] "i" (&ulCriticalNesting),                                         \
616       [pxCurrentTCB] "i" (&pxCurrentTCB),                                                   \
617       [LINE] "i" (__LINE__)                                                                 \
618   );                                                                                        \
619 }
620 
621 /*
622  * Input parameter: in R12, boolean. Perform a vTaskSwitchContext() if 1
623  */
624 #define portEXIT_SWITCHING_ISR()                                                            \
625 {                                                                                           \
626   extern volatile uint32_t ulCriticalNesting;                                       \
627   extern volatile void *volatile pxCurrentTCB;                                              \
628                                                                                             \
629   __asm__ __volatile__ (                                                                    \
630     /* Check if INT0 or higher were being handled (case where the OS tick interrupted another */        \
631     /* interrupt handler (which was of a higher priority level but decided to lower its priority */     \
632     /* level and allow other lower interrupt level to occur). */                                        \
633     /* In this case it's of no use to switch context and restore a new SP because we purposedly */      \
634     /* did not previously save SP in its TCB. */                                                                                \
635     "ld.w    r0, sp[9*4]                                                                    \n\t" /* Read SR in stack */\
636     "bfextu  r0, r0, 22, 3                                                                  \n\t" /* Extract the mode bits to R0. */\
637     "cp.w    r0, 1                                                                          \n\t" /* Compare the mode bits with supervisor mode(b'001) */\
638     "brhi    LABEL_ISR_SKIP_RESTORE_CONTEXT_%[LINE]                                         \n\t"\
639                                                                                             \
640     /* If a switch is required then we just need to call */                                 \
641     /* vTaskSwitchContext() as the context has already been */                              \
642     /* saved. */                                                                            \
643     "cp.w    r12, 1                                                                         \n\t" /* Check if Switch context is required. */\
644     "brne    LABEL_ISR_RESTORE_CONTEXT_%[LINE]"                                             \
645     :                                                                                       \
646     : [LINE] "i" (__LINE__)                                                                 \
647   );                                                                                        \
648                                                                                             \
649   /* A critical section has to be used here because vTaskSwitchContext handles FreeRTOS linked lists. */    \
650   portENTER_CRITICAL();                                                                     \
651   vTaskSwitchContext();                                                                     \
652   portEXIT_CRITICAL();                                                                      \
653                                                                                             \
654   __asm__ __volatile__ (                                                                    \
655     "LABEL_ISR_RESTORE_CONTEXT_%[LINE]:                                                     \n\t"\
656     /* Restore the context of which ever task is now the highest */                         \
657     /* priority that is ready to run. */                                                    \
658                                                                                             \
659     /* Restore all registers */                                                             \
660                                                                                             \
661     /* Set SP to point to new stack */                                                      \
662     "mov     r8, LO(%[pxCurrentTCB])                                                        \n\t"\
663     "orh     r8, HI(%[pxCurrentTCB])                                                        \n\t"\
664     "ld.w    r0, r8[0]                                                                      \n\t"\
665     "ld.w    sp, r0[0]                                                                      \n"\
666                                                                                             \
667     "LABEL_ISR_SKIP_RESTORE_CONTEXT_%[LINE]:                                                \n\t"\
668                                                                                             \
669     /* Restore ulCriticalNesting variable */                                                \
670     "ld.w    r0, sp++                                                                       \n\t"\
671     "mov     r8, LO(%[ulCriticalNesting])                                                   \n\t"\
672     "orh     r8, HI(%[ulCriticalNesting])                                                   \n\t"\
673     "st.w    r8[0], r0                                                                      \n\t"\
674                                                                                             \
675     /* Restore R0..R7 */                                                                    \
676     "ldm     sp++, r0-r7                                                                    \n\t"\
677                                                                                             \
678     /* Now, the stack should be R8..R12, LR, PC and SR  */                                  \
679     "rete"                                                                                  \
680     :                                                                                       \
681     : [ulCriticalNesting] "i" (&ulCriticalNesting),                                         \
682       [pxCurrentTCB] "i" (&pxCurrentTCB),                                                   \
683       [LINE] "i" (__LINE__)                                                                 \
684   );                                                                                        \
685 }
686 
687 #endif
688 
689 
690 #define portYIELD()                 {__asm__ __volatile__ ("scall");}
691 
692 /* Task function macros as described on the FreeRTOS.org WEB site. */
693 #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
694 #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
695 
696 /* *INDENT-OFF* */
697 #ifdef __cplusplus
698     }
699 #endif
700 /* *INDENT-ON* */
701 
702 #endif /* PORTMACRO_H */
703