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
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 /*-----------------------------------------------------------
30 * Implementation of functions defined in portable.h for the SH2A port.
31 *----------------------------------------------------------*/
32
33 /* Scheduler includes. */
34 #include "FreeRTOS.h"
35 #include "task.h"
36
37 /* Library includes. */
38 #include "string.h"
39
40 /*-----------------------------------------------------------*/
41
42 /* The SR assigned to a newly created task. The only important thing in this
43 * value is for all interrupts to be enabled. */
44 #define portINITIAL_SR ( 0UL )
45
46 /* Dimensions the array into which the floating point context is saved.
47 * Allocate enough space for FPR0 to FPR15, FPUL and FPSCR, each of which is 4
48 * bytes big. If this number is changed then the 72 in portasm.src also needs
49 * changing. */
50 #define portFLOP_REGISTERS_TO_STORE ( 18 )
51 #define portFLOP_STORAGE_SIZE ( portFLOP_REGISTERS_TO_STORE * 4 )
52
53 #if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
54 #error configSUPPORT_DYNAMIC_ALLOCATION must be 1 to use this port.
55 #endif
56
57 /*-----------------------------------------------------------*/
58
59 /*
60 * The TRAPA handler used to force a context switch.
61 */
62 void vPortYield( void );
63
64 /*
65 * Function to start the first task executing - defined in portasm.src.
66 */
67 extern void vPortStartFirstTask( void );
68
69 /*
70 * Obtains the current GBR value - defined in portasm.src.
71 */
72 extern uint32_t ulPortGetGBR( void );
73
74 /*-----------------------------------------------------------*/
75
76 /*
77 * See header file for description.
78 */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters)79 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
80 TaskFunction_t pxCode,
81 void * pvParameters )
82 {
83 /* Mark the end of the stack - used for debugging only and can be removed. */
84 *pxTopOfStack = 0x11111111UL;
85 pxTopOfStack--;
86 *pxTopOfStack = 0x22222222UL;
87 pxTopOfStack--;
88 *pxTopOfStack = 0x33333333UL;
89 pxTopOfStack--;
90
91 /* SR. */
92 *pxTopOfStack = portINITIAL_SR;
93 pxTopOfStack--;
94
95 /* PC. */
96 *pxTopOfStack = ( uint32_t ) pxCode;
97 pxTopOfStack--;
98
99 /* PR. */
100 *pxTopOfStack = 15;
101 pxTopOfStack--;
102
103 /* 14. */
104 *pxTopOfStack = 14;
105 pxTopOfStack--;
106
107 /* R13. */
108 *pxTopOfStack = 13;
109 pxTopOfStack--;
110
111 /* R12. */
112 *pxTopOfStack = 12;
113 pxTopOfStack--;
114
115 /* R11. */
116 *pxTopOfStack = 11;
117 pxTopOfStack--;
118
119 /* R10. */
120 *pxTopOfStack = 10;
121 pxTopOfStack--;
122
123 /* R9. */
124 *pxTopOfStack = 9;
125 pxTopOfStack--;
126
127 /* R8. */
128 *pxTopOfStack = 8;
129 pxTopOfStack--;
130
131 /* R7. */
132 *pxTopOfStack = 7;
133 pxTopOfStack--;
134
135 /* R6. */
136 *pxTopOfStack = 6;
137 pxTopOfStack--;
138
139 /* R5. */
140 *pxTopOfStack = 5;
141 pxTopOfStack--;
142
143 /* R4. */
144 *pxTopOfStack = ( uint32_t ) pvParameters;
145 pxTopOfStack--;
146
147 /* R3. */
148 *pxTopOfStack = 3;
149 pxTopOfStack--;
150
151 /* R2. */
152 *pxTopOfStack = 2;
153 pxTopOfStack--;
154
155 /* R1. */
156 *pxTopOfStack = 1;
157 pxTopOfStack--;
158
159 /* R0 */
160 *pxTopOfStack = 0;
161 pxTopOfStack--;
162
163 /* MACL. */
164 *pxTopOfStack = 16;
165 pxTopOfStack--;
166
167 /* MACH. */
168 *pxTopOfStack = 17;
169 pxTopOfStack--;
170
171 /* GBR. */
172 *pxTopOfStack = ulPortGetGBR();
173
174 /* GBR = global base register.
175 * VBR = vector base register.
176 * TBR = jump table base register.
177 * R15 is the stack pointer. */
178
179 return pxTopOfStack;
180 }
181 /*-----------------------------------------------------------*/
182
xPortStartScheduler(void)183 BaseType_t xPortStartScheduler( void )
184 {
185 extern void vApplicationSetupTimerInterrupt( void );
186
187 /* Call an application function to set up the timer that will generate the
188 * tick interrupt. This way the application can decide which peripheral to
189 * use. A demo application is provided to show a suitable example. */
190 vApplicationSetupTimerInterrupt();
191
192 /* Start the first task. This will only restore the standard registers and
193 * not the flop registers. This does not really matter though because the only
194 * flop register that is initialised to a particular value is fpscr, and it is
195 * only initialised to the current value, which will still be the current value
196 * when the first task starts executing. */
197 trapa( portSTART_SCHEDULER_TRAP_NO );
198
199 /* Should not get here. */
200 return pdFAIL;
201 }
202 /*-----------------------------------------------------------*/
203
vPortEndScheduler(void)204 void vPortEndScheduler( void )
205 {
206 /* Not implemented as there is nothing to return to. */
207 }
208 /*-----------------------------------------------------------*/
209
vPortYield(void)210 void vPortYield( void )
211 {
212 int32_t lInterruptMask;
213
214 /* Ensure the yield trap runs at the same priority as the other interrupts
215 * that can cause a context switch. */
216 lInterruptMask = get_imask();
217
218 /* taskYIELD() can only be called from a task, not an interrupt, so the
219 * current interrupt mask can only be 0 or portKERNEL_INTERRUPT_PRIORITY and
220 * the mask can be set without risk of accidentally lowering the mask value. */
221 set_imask( portKERNEL_INTERRUPT_PRIORITY );
222
223 trapa( portYIELD_TRAP_NO );
224
225 /* Restore the interrupt mask to whatever it was previously (when the
226 * function was entered). */
227 set_imask( ( int ) lInterruptMask );
228 }
229 /*-----------------------------------------------------------*/
230
xPortUsesFloatingPoint(TaskHandle_t xTask)231 BaseType_t xPortUsesFloatingPoint( TaskHandle_t xTask )
232 {
233 uint32_t * pulFlopBuffer;
234 BaseType_t xReturn;
235 extern void * volatile pxCurrentTCB;
236
237 /* This function tells the kernel that the task referenced by xTask is
238 * going to use the floating point registers and therefore requires the
239 * floating point registers saved as part of its context. */
240
241 /* Passing NULL as xTask is used to indicate that the calling task is the
242 * subject task - so pxCurrentTCB is the task handle. */
243 if( xTask == NULL )
244 {
245 xTask = ( TaskHandle_t ) pxCurrentTCB;
246 }
247
248 /* Allocate a buffer large enough to hold all the flop registers. */
249 pulFlopBuffer = ( uint32_t * ) pvPortMalloc( portFLOP_STORAGE_SIZE );
250
251 if( pulFlopBuffer != NULL )
252 {
253 /* Start with the registers in a benign state. */
254 memset( ( void * ) pulFlopBuffer, 0x00, portFLOP_STORAGE_SIZE );
255
256 /* The first thing to get saved in the buffer is the FPSCR value -
257 * initialise this to the current FPSCR value. */
258 *pulFlopBuffer = get_fpscr();
259
260 /* Use the task tag to point to the flop buffer. Pass pointer to just
261 * above the buffer because the flop save routine uses a pre-decrement. */
262 vTaskSetApplicationTaskTag( xTask, ( void * ) ( pulFlopBuffer + portFLOP_REGISTERS_TO_STORE ) );
263 xReturn = pdPASS;
264 }
265 else
266 {
267 xReturn = pdFAIL;
268 }
269
270 return xReturn;
271 }
272 /*-----------------------------------------------------------*/
273