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