xref: /Kernel-v10.6.2/portable/CCS/ARM_Cortex-R4/port.c (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
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 /* FreeRTOS includes. */
30 #include "FreeRTOS.h"
31 #include "task.h"
32 
33 /*-----------------------------------------------------------*/
34 
35 /* Count of the critical section nesting depth. */
36 uint32_t ulCriticalNesting = 9999;
37 
38 /*-----------------------------------------------------------*/
39 
40 /* Registers required to configure the RTI. */
41 #define portRTI_GCTRL_REG       ( * ( ( volatile uint32_t * ) 0xFFFFFC00 ) )
42 #define portRTI_TBCTRL_REG      ( * ( ( volatile uint32_t * ) 0xFFFFFC04 ) )
43 #define portRTI_COMPCTRL_REG    ( * ( ( volatile uint32_t * ) 0xFFFFFC0C ) )
44 #define portRTI_CNT0_FRC0_REG   ( * ( ( volatile uint32_t * ) 0xFFFFFC10 ) )
45 #define portRTI_CNT0_UC0_REG    ( * ( ( volatile uint32_t * ) 0xFFFFFC14 ) )
46 #define portRTI_CNT0_CPUC0_REG  ( * ( ( volatile uint32_t * ) 0xFFFFFC18 ) )
47 #define portRTI_CNT0_COMP0_REG  ( * ( ( volatile uint32_t * ) 0xFFFFFC50 ) )
48 #define portRTI_CNT0_UDCP0_REG  ( * ( ( volatile uint32_t * ) 0xFFFFFC54 ) )
49 #define portRTI_SETINTENA_REG   ( * ( ( volatile uint32_t * ) 0xFFFFFC80 ) )
50 #define portRTI_CLEARINTENA_REG ( * ( ( volatile uint32_t * ) 0xFFFFFC84 ) )
51 #define portRTI_INTFLAG_REG     ( * ( ( volatile uint32_t * ) 0xFFFFFC88 ) )
52 
53 
54 /* Constants required to set up the initial stack of each task. */
55 #define portINITIAL_SPSR        ( ( StackType_t ) 0x1F )
56 #define portINITIAL_FPSCR       ( ( StackType_t ) 0x00 )
57 #define portINSTRUCTION_SIZE    ( ( StackType_t ) 0x04 )
58 #define portTHUMB_MODE_BIT      ( ( StackType_t ) 0x20 )
59 
60 /* The number of words on the stack frame between the saved Top Of Stack and
61 R0 (in which the parameters are passed. */
62 #define portSPACE_BETWEEN_TOS_AND_PARAMETERS    ( 12 )
63 
64 /*-----------------------------------------------------------*/
65 
66 /* vPortStartFirstSTask() is defined in portASM.asm */
67 extern void vPortStartFirstTask( void );
68 
69 /*-----------------------------------------------------------*/
70 
71 /* Saved as part of the task context.  Set to pdFALSE if the task does not
72 require an FPU context. */
73 uint32_t ulTaskHasFPUContext = 0;
74 
75 /*-----------------------------------------------------------*/
76 
77 
78 /*
79  * See header file for description.
80  */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters)81 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
82 {
83 StackType_t *pxOriginalTOS;
84 
85     pxOriginalTOS = pxTopOfStack;
86 
87     #if __TI_VFP_SUPPORT__
88     {
89         /* Ensure the stack is correctly aligned on exit. */
90         pxTopOfStack--;
91     }
92     #endif
93 
94     /* Setup the initial stack of the task.  The stack is set exactly as
95     expected by the portRESTORE_CONTEXT() macro. */
96 
97     /* First on the stack is the return address - which is the start of the as
98     the task has not executed yet.  The offset is added to make the return
99     address appear as it would within an IRQ ISR. */
100     *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;
101     pxTopOfStack--;
102 
103     *pxTopOfStack = ( StackType_t ) 0x00000000; /* R14 */
104     pxTopOfStack--;
105     *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
106     pxTopOfStack--;
107 
108     #ifdef portPRELOAD_TASK_REGISTERS
109     {
110         *pxTopOfStack = ( StackType_t ) 0x12121212; /* R12 */
111         pxTopOfStack--;
112         *pxTopOfStack = ( StackType_t ) 0x11111111; /* R11 */
113         pxTopOfStack--;
114         *pxTopOfStack = ( StackType_t ) 0x10101010; /* R10 */
115         pxTopOfStack--;
116         *pxTopOfStack = ( StackType_t ) 0x09090909; /* R9 */
117         pxTopOfStack--;
118         *pxTopOfStack = ( StackType_t ) 0x08080808; /* R8 */
119         pxTopOfStack--;
120         *pxTopOfStack = ( StackType_t ) 0x07070707; /* R7 */
121         pxTopOfStack--;
122         *pxTopOfStack = ( StackType_t ) 0x06060606; /* R6 */
123         pxTopOfStack--;
124         *pxTopOfStack = ( StackType_t ) 0x05050505; /* R5 */
125         pxTopOfStack--;
126         *pxTopOfStack = ( StackType_t ) 0x04040404; /* R4 */
127         pxTopOfStack--;
128         *pxTopOfStack = ( StackType_t ) 0x03030303; /* R3 */
129         pxTopOfStack--;
130         *pxTopOfStack = ( StackType_t ) 0x02020202; /* R2 */
131         pxTopOfStack--;
132         *pxTopOfStack = ( StackType_t ) 0x01010101; /* R1 */
133         pxTopOfStack--;
134     }
135     #else
136     {
137         pxTopOfStack -= portSPACE_BETWEEN_TOS_AND_PARAMETERS;
138     }
139     #endif
140 
141     /* Function parameters are passed in R0. */
142     *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
143     pxTopOfStack--;
144 
145     /* Set the status register for system mode, with interrupts enabled. */
146     *pxTopOfStack = ( StackType_t ) ( ( _get_CPSR() & ~0xFF ) | portINITIAL_SPSR );
147 
148     if( ( ( uint32_t ) pxCode & 0x01UL ) != 0x00 )
149     {
150         /* The task will start in thumb mode. */
151         *pxTopOfStack |= portTHUMB_MODE_BIT;
152     }
153 
154     #ifdef __TI_VFP_SUPPORT__
155     {
156         pxTopOfStack--;
157 
158         /* The last thing on the stack is the tasks ulUsingFPU value, which by
159         default is set to indicate that the stack frame does not include FPU
160         registers. */
161         *pxTopOfStack = pdFALSE;
162     }
163     #endif
164 
165     return pxTopOfStack;
166 }
167 /*-----------------------------------------------------------*/
168 
prvSetupTimerInterrupt(void)169 static void prvSetupTimerInterrupt(void)
170 {
171     /* Disable timer 0. */
172     portRTI_GCTRL_REG &= 0xFFFFFFFEUL;
173 
174     /* Use the internal counter. */
175     portRTI_TBCTRL_REG = 0x00000000U;
176 
177     /* COMPSEL0 will use the RTIFRC0 counter. */
178     portRTI_COMPCTRL_REG = 0x00000000U;
179 
180     /* Initialise the counter and the prescale counter registers. */
181     portRTI_CNT0_UC0_REG =  0x00000000U;
182     portRTI_CNT0_FRC0_REG =  0x00000000U;
183 
184     /* Set Prescalar for RTI clock. */
185     portRTI_CNT0_CPUC0_REG = 0x00000001U;
186     portRTI_CNT0_COMP0_REG = ( configCPU_CLOCK_HZ / 2 ) / configTICK_RATE_HZ;
187     portRTI_CNT0_UDCP0_REG = ( configCPU_CLOCK_HZ / 2 ) / configTICK_RATE_HZ;
188 
189     /* Clear interrupts. */
190     portRTI_INTFLAG_REG =  0x0007000FU;
191     portRTI_CLEARINTENA_REG = 0x00070F0FU;
192 
193     /* Enable the compare 0 interrupt. */
194     portRTI_SETINTENA_REG = 0x00000001U;
195     portRTI_GCTRL_REG |= 0x00000001U;
196 }
197 /*-----------------------------------------------------------*/
198 
199 /*
200  * See header file for description.
201  */
xPortStartScheduler(void)202 BaseType_t xPortStartScheduler(void)
203 {
204     /* Start the timer that generates the tick ISR. */
205     prvSetupTimerInterrupt();
206 
207     /* Reset the critical section nesting count read to execute the first task. */
208     ulCriticalNesting = 0;
209 
210     /* Start the first task.  This is done from portASM.asm as ARM mode must be
211     used. */
212     vPortStartFirstTask();
213 
214     /* Should not get here! */
215     return pdFAIL;
216 }
217 /*-----------------------------------------------------------*/
218 
219 /*
220  * See header file for description.
221  */
vPortEndScheduler(void)222 void vPortEndScheduler(void)
223 {
224     /* Not implemented in ports where there is nothing to return to.
225     Artificially force an assert. */
226     configASSERT( ulCriticalNesting == 1000UL );
227 }
228 /*-----------------------------------------------------------*/
229 
230 #if configUSE_PREEMPTION == 0
231 
232     /* The cooperative scheduler requires a normal IRQ service routine to
233      * simply increment the system tick. */
vPortNonPreemptiveTick(void)234     __interrupt void vPortNonPreemptiveTick( void )
235     {
236         /* clear clock interrupt flag */
237         portRTI_INTFLAG_REG = 0x00000001;
238 
239         /* Increment the tick count - this may make a delaying task ready
240         to run - but a context switch is not performed. */
241         xTaskIncrementTick();
242     }
243 
244  #else
245 
246     /*
247      **************************************************************************
248      * The preemptive scheduler ISR is written in assembler and can be found
249      * in the portASM.asm file. This will only get used if portUSE_PREEMPTION
250      * is set to 1 in portmacro.h
251      **************************************************************************
252      */
253     void vPortPreemptiveTick( void );
254 
255 #endif
256 /*-----------------------------------------------------------*/
257 
258 
259 /*
260  * Disable interrupts, and keep a count of the nesting depth.
261  */
vPortEnterCritical(void)262 void vPortEnterCritical( void )
263 {
264     /* Disable interrupts as per portDISABLE_INTERRUPTS(); */
265     portDISABLE_INTERRUPTS();
266 
267     /* Now interrupts are disabled ulCriticalNesting can be accessed
268     directly.  Increment ulCriticalNesting to keep a count of how many times
269     portENTER_CRITICAL() has been called. */
270     ulCriticalNesting++;
271 }
272 /*-----------------------------------------------------------*/
273 
274 /*
275  * Decrement the critical nesting count, and if it has reached zero, re-enable
276  * interrupts.
277  */
vPortExitCritical(void)278 void vPortExitCritical( void )
279 {
280     if( ulCriticalNesting > 0 )
281     {
282         /* Decrement the nesting count as we are leaving a critical section. */
283         ulCriticalNesting--;
284 
285         /* If the nesting level has reached zero then interrupts should be
286         re-enabled. */
287         if( ulCriticalNesting == 0 )
288         {
289             /* Enable interrupts as per portENABLE_INTERRUPTS(). */
290             portENABLE_INTERRUPTS();
291         }
292     }
293 }
294 /*-----------------------------------------------------------*/
295 
296 #if __TI_VFP_SUPPORT__
297 
vPortTaskUsesFPU(void)298     void vPortTaskUsesFPU( void )
299     {
300     extern void vPortInitialiseFPSCR( void );
301 
302         /* A task is registering the fact that it needs an FPU context.  Set the
303         FPU flag (saved as part of the task context. */
304         ulTaskHasFPUContext = pdTRUE;
305 
306         /* Initialise the floating point status register. */
307         vPortInitialiseFPSCR();
308     }
309 
310 #endif /* __TI_VFP_SUPPORT__ */
311 
312 /*-----------------------------------------------------------*/
313