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