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