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