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 /* Scheduler includes. */
30 #include "FreeRTOS.h"
31 #include "task.h"
32
33
34 /*-----------------------------------------------------------
35 * Implementation of functions defined in portable.h for the H8S port.
36 *----------------------------------------------------------*/
37
38
39 /*-----------------------------------------------------------*/
40
41 /* When the task starts interrupts should be enabled. */
42 #define portINITIAL_CCR ( ( StackType_t ) 0x00 )
43
44 /* Hardware specific constants used to generate the RTOS tick from the TPU. */
45 #define portCLEAR_ON_TGRA_COMPARE_MATCH ( ( uint8_t ) 0x20 )
46 #define portCLOCK_DIV_64 ( ( uint8_t ) 0x03 )
47 #define portCLOCK_DIV ( ( uint32_t ) 64 )
48 #define portTGRA_INTERRUPT_ENABLE ( ( uint8_t ) 0x01 )
49 #define portTIMER_CHANNEL ( ( uint8_t ) 0x02 )
50 #define portMSTP13 ( ( uint16_t ) 0x2000 )
51
52 /*
53 * Setup TPU channel one for the RTOS tick at the requested frequency.
54 */
55 static void prvSetupTimerInterrupt( void );
56
57 /*
58 * The ISR used by portYIELD(). This is installed as a trap handler.
59 */
60 void vPortYield( void ) __attribute__( ( saveall, interrupt_handler ) );
61
62 /*-----------------------------------------------------------*/
63
64 /*
65 * See header file for description.
66 */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters)67 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
68 TaskFunction_t pxCode,
69 void * pvParameters )
70 {
71 uint32_t ulValue;
72
73 /* This requires an even address. */
74 ulValue = ( uint32_t ) pxTopOfStack;
75
76 if( ulValue & 1UL )
77 {
78 pxTopOfStack = pxTopOfStack - 1;
79 }
80
81 /* Place a few bytes of known values on the bottom of the stack.
82 * This is just useful for debugging. */
83 pxTopOfStack--;
84 *pxTopOfStack = 0xaa;
85 pxTopOfStack--;
86 *pxTopOfStack = 0xbb;
87 pxTopOfStack--;
88 *pxTopOfStack = 0xcc;
89 pxTopOfStack--;
90 *pxTopOfStack = 0xdd;
91
92 /* The initial stack mimics an interrupt stack. First there is the program
93 * counter (24 bits). */
94 ulValue = ( uint32_t ) pxCode;
95
96 pxTopOfStack--;
97 *pxTopOfStack = ( StackType_t ) ( ulValue & 0xff );
98 pxTopOfStack--;
99 ulValue >>= 8UL;
100 *pxTopOfStack = ( StackType_t ) ( ulValue & 0xff );
101 pxTopOfStack--;
102 ulValue >>= 8UL;
103 *pxTopOfStack = ( StackType_t ) ( ulValue & 0xff );
104
105 /* Followed by the CCR. */
106 pxTopOfStack--;
107 *pxTopOfStack = portINITIAL_CCR;
108
109 /* Next all the general purpose registers - with the parameters being passed
110 * in ER0. The parameter order must match that used by the compiler when the
111 * "saveall" function attribute is used. */
112
113 /* ER6 */
114 pxTopOfStack--;
115 *pxTopOfStack = 0x66;
116 pxTopOfStack--;
117 *pxTopOfStack = 0x66;
118 pxTopOfStack--;
119 *pxTopOfStack = 0x66;
120 pxTopOfStack--;
121 *pxTopOfStack = 0x66;
122
123 /* ER0 */
124 ulValue = ( uint32_t ) pvParameters;
125
126 pxTopOfStack--;
127 *pxTopOfStack = ( StackType_t ) ( ulValue & 0xff );
128 pxTopOfStack--;
129 ulValue >>= 8UL;
130 *pxTopOfStack = ( StackType_t ) ( ulValue & 0xff );
131 pxTopOfStack--;
132 ulValue >>= 8UL;
133 *pxTopOfStack = ( StackType_t ) ( ulValue & 0xff );
134 pxTopOfStack--;
135 ulValue >>= 8UL;
136 *pxTopOfStack = ( StackType_t ) ( ulValue & 0xff );
137
138 /* ER1 */
139 pxTopOfStack--;
140 *pxTopOfStack = 0x11;
141 pxTopOfStack--;
142 *pxTopOfStack = 0x11;
143 pxTopOfStack--;
144 *pxTopOfStack = 0x11;
145 pxTopOfStack--;
146 *pxTopOfStack = 0x11;
147
148 /* ER2 */
149 pxTopOfStack--;
150 *pxTopOfStack = 0x22;
151 pxTopOfStack--;
152 *pxTopOfStack = 0x22;
153 pxTopOfStack--;
154 *pxTopOfStack = 0x22;
155 pxTopOfStack--;
156 *pxTopOfStack = 0x22;
157
158 /* ER3 */
159 pxTopOfStack--;
160 *pxTopOfStack = 0x33;
161 pxTopOfStack--;
162 *pxTopOfStack = 0x33;
163 pxTopOfStack--;
164 *pxTopOfStack = 0x33;
165 pxTopOfStack--;
166 *pxTopOfStack = 0x33;
167
168 /* ER4 */
169 pxTopOfStack--;
170 *pxTopOfStack = 0x44;
171 pxTopOfStack--;
172 *pxTopOfStack = 0x44;
173 pxTopOfStack--;
174 *pxTopOfStack = 0x44;
175 pxTopOfStack--;
176 *pxTopOfStack = 0x44;
177
178 /* ER5 */
179 pxTopOfStack--;
180 *pxTopOfStack = 0x55;
181 pxTopOfStack--;
182 *pxTopOfStack = 0x55;
183 pxTopOfStack--;
184 *pxTopOfStack = 0x55;
185 pxTopOfStack--;
186 *pxTopOfStack = 0x55;
187
188 return pxTopOfStack;
189 }
190 /*-----------------------------------------------------------*/
191
xPortStartScheduler(void)192 BaseType_t xPortStartScheduler( void )
193 {
194 extern void * pxCurrentTCB;
195
196 /* Setup the hardware to generate the tick. */
197 prvSetupTimerInterrupt();
198
199 /* Restore the context of the first task that is going to run. This
200 * mirrors the function epilogue code generated by the compiler when the
201 * "saveall" function attribute is used. */
202 asm volatile (
203 "MOV.L @_pxCurrentTCB, ER6 \n\t"
204 "MOV.L @ER6, ER7 \n\t"
205 "LDM.L @SP+, (ER4-ER5) \n\t"
206 "LDM.L @SP+, (ER0-ER3) \n\t"
207 "MOV.L @ER7+, ER6 \n\t"
208 "RTE \n\t"
209 );
210
211 ( void ) pxCurrentTCB;
212
213 /* Should not get here. */
214 return pdTRUE;
215 }
216 /*-----------------------------------------------------------*/
217
vPortEndScheduler(void)218 void vPortEndScheduler( void )
219 {
220 /* It is unlikely that the h8 port will get stopped. */
221 }
222 /*-----------------------------------------------------------*/
223
224 /*
225 * Manual context switch. This is a trap handler. The "saveall" function
226 * attribute is used so the context is saved by the compiler prologue. All
227 * we have to do is save the stack pointer.
228 */
vPortYield(void)229 void vPortYield( void )
230 {
231 portSAVE_STACK_POINTER();
232 vTaskSwitchContext();
233 portRESTORE_STACK_POINTER();
234 }
235 /*-----------------------------------------------------------*/
236
237 /*
238 * The interrupt handler installed for the RTOS tick depends on whether the
239 * preemptive or cooperative scheduler is being used.
240 */
241 #if ( configUSE_PREEMPTION == 1 )
242
243 /*
244 * The preemptive scheduler is used so the ISR calls vTaskSwitchContext().
245 * The function prologue saves the context so all we have to do is save
246 * the stack pointer.
247 */
248 void vTickISR( void ) __attribute__( ( saveall, interrupt_handler ) );
vTickISR(void)249 void vTickISR( void )
250 {
251 portSAVE_STACK_POINTER();
252
253 if( xTaskIncrementTick() != pdFALSE )
254 {
255 vTaskSwitchContext();
256 }
257
258 /* Clear the interrupt. */
259 TSR1 &= ~0x01;
260
261 portRESTORE_STACK_POINTER();
262 }
263
264 #else /* if ( configUSE_PREEMPTION == 1 ) */
265
266 /*
267 * The cooperative scheduler is being used so all we have to do is
268 * periodically increment the tick. This can just be a normal ISR and
269 * the "saveall" attribute is not required.
270 */
271 void vTickISR( void ) __attribute__( ( interrupt_handler ) );
vTickISR(void)272 void vTickISR( void )
273 {
274 xTaskIncrementTick();
275
276 /* Clear the interrupt. */
277 TSR1 &= ~0x01;
278 }
279
280 #endif /* if ( configUSE_PREEMPTION == 1 ) */
281 /*-----------------------------------------------------------*/
282
283 /*
284 * Setup timer 1 compare match to generate a tick interrupt.
285 */
prvSetupTimerInterrupt(void)286 static void prvSetupTimerInterrupt( void )
287 {
288 const uint32_t ulCompareMatch = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) / portCLOCK_DIV;
289
290 /* Turn the module on. */
291 MSTPCR &= ~portMSTP13;
292
293 /* Configure timer 1. */
294 TCR1 = portCLEAR_ON_TGRA_COMPARE_MATCH | portCLOCK_DIV_64;
295
296 /* Configure the compare match value for a tick of configTICK_RATE_HZ. */
297 TGR1A = ulCompareMatch;
298
299 /* Start the timer and enable the interrupt - we can do this here as
300 * interrupts are globally disabled when this function is called. */
301 TIER1 |= portTGRA_INTERRUPT_ENABLE;
302 TSTR |= portTIMER_CHANNEL;
303 }
304 /*-----------------------------------------------------------*/
305