]> git.sur5r.net Git - freertos/blob - Source/portable/Softune/MB91460/port.c
969f3982606eb03cefd67e80ade6bd1f3912beca
[freertos] / Source / portable / Softune / MB91460 / port.c
1 /*\r
2         FreeRTOS.org V4.7.1 - Copyright (C) 2003-2008 Richard Barry.\r
3 \r
4         This file is part of the FreeRTOS.org distribution.\r
5 \r
6         FreeRTOS.org is free software; you can redistribute it and/or modify\r
7         it under the terms of the GNU General Public License as published by\r
8         the Free Software Foundation; either version 2 of the License, or\r
9         (at your option) any later version.\r
10 \r
11         FreeRTOS.org is distributed in the hope that it will be useful,\r
12         but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14         GNU General Public License for more details.\r
15 \r
16         You should have received a copy of the GNU General Public License\r
17         along with FreeRTOS.org; if not, write to the Free Software\r
18         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
19 \r
20         A special exception to the GPL can be applied should you wish to distribute\r
21         a combined work that includes FreeRTOS.org, without being obliged to provide\r
22         the source code for any proprietary components.  See the licensing section\r
23         of http://www.FreeRTOS.org for full details of how and when the exception\r
24         can be applied.\r
25 \r
26         ***************************************************************************\r
27 \r
28         Please ensure to read the configuration and relevant port sections of the \r
29         online documentation.\r
30 \r
31         +++ http://www.FreeRTOS.org +++\r
32         Documentation, latest information, license and contact details.  \r
33 \r
34         +++ http://www.SafeRTOS.com +++\r
35         A version that is certified for use in safety critical systems.\r
36 \r
37         +++ http://www.OpenRTOS.com +++\r
38         Commercial support, development, porting, licensing and training services.\r
39 \r
40         ***************************************************************************\r
41 */\r
42 \r
43 #include "FreeRTOS.h"\r
44 #include "task.h"\r
45 #include "mb91467d.h"\r
46 \r
47 /*-----------------------------------------------------------*/\r
48 \r
49 /* We require the address of the pxCurrentTCB variable, but don't want to know\r
50 any details of its type. */\r
51 typedef void tskTCB;\r
52 extern volatile tskTCB * volatile pxCurrentTCB;\r
53 \r
54 /* Constants required to handle critical sections. */\r
55 #define portNO_CRITICAL_NESTING         ( ( unsigned portBASE_TYPE ) 0 )\r
56 volatile unsigned portLONG ulCriticalNesting = 9999UL;\r
57 \r
58 /*-----------------------------------------------------------*/\r
59 \r
60 \r
61  \r
62 #pragma asm\r
63 #macro  SaveContext\r
64          ORCCR #0x20                                                            ;Switch to user stack\r
65          ST RP,@-R15                                                            ;Store RP\r
66          STM0 (R7,R6,R5,R4,R3,R2,R1,R0)                         ;Store R7-R0\r
67          STM1 (R14,R13,R12,R11,R10,R9,R8)                       ;Store R14-R8\r
68          ST MDH, @-R15                                                          ;Store MDH\r
69          ST MDL, @-R15                                                          ;Store MDL\r
70 \r
71          LDI #_ulCriticalNesting, R0                            ;Get the address of the critical nesting counter\r
72          LD @R0, R0                                                                     ;Get the value of the critical nesting counter\r
73          ST R0, @-R15                                                           ;Store the critical nesting value to the user stack.\r
74          \r
75          ANDCCR #0xDF                                                           ;Switch back to system stack\r
76          LD @R15+,R0                                                            ;Store PC to R0 \r
77          ORCCR #0x20                                                            ;Switch to user stack\r
78          ST R0,@-R15                                                            ;Store PC to User stack\r
79          \r
80          ANDCCR #0xDF                                                           ;Switch back to system stack\r
81          LD @R15+,R0                                                            ;Store PS to R0\r
82          ORCCR #0x20                                                            ;Switch to user stack\r
83          ST R0,@-R15                                                            ;Store PS to User stack\r
84          \r
85          LDI #_pxCurrentTCB, R0                                         ;Get pxCurrentTCB address\r
86          LD @R0, R0                                                                     ;Get the pxCurrentTCB->pxTopOfStack address\r
87          ST R15,@R0                                                                     ;Store USP to pxCurrentTCB->pxTopOfStack\r
88          \r
89          ANDCCR #0xDF                                                           ;Switch back to system stack for the rest of tick ISR\r
90 #endm\r
91 \r
92 #macro RestoreContext\r
93          LDI #_pxCurrentTCB, R0                                         ;Get pxCurrentTCB address\r
94          LD @R0, R0                                                                     ;Get the pxCurrentTCB->pxTopOfStack address\r
95          ORCCR #0x20                                                            ;Switch to user stack\r
96          LD @R0, R15                                                            ;Restore USP from pxCurrentTCB->pxTopOfStack\r
97 \r
98          LD @R15+,R0                                                            ;Store PS to R0\r
99          ANDCCR #0xDF                                                           ;Switch to system stack\r
100          ST R0,@-R15                                                            ;Store PS to system stack\r
101 \r
102          ORCCR #0x20                                                            ;Switch to user stack\r
103          LD @R15+,R0                                                            ;Store PC to R0\r
104          ANDCCR #0xDF                                                           ;Switch to system stack\r
105          ST R0,@-R15                                                            ;Store PC to system stack\r
106 \r
107          ORCCR #0x20                                                            ;Switch back to retreive the remaining context\r
108 \r
109          LDI #_ulCriticalNesting, R0                            ;Get the address of the critical nesting counter\r
110          LD @R15+, R1                                                           ;Get the saved critical nesting value\r
111          ST R1, @R0                                                                     ;Save the critical nesting value into the ulCriticalNesting variable\r
112 \r
113          LD @R15+, MDL                                                          ;Restore MDL\r
114          LD @R15+, MDH                                                          ;Restore MDH\r
115          LDM1 (R14,R13,R12,R11,R10,R9,R8)                       ;Restore R14-R8\r
116          LDM0 (R7,R6,R5,R4,R3,R2,R1,R0)                         ;Restore R7-R0\r
117          LD @R15+, RP                                                           ;Restore RP\r
118          \r
119          ANDCCR #0xDF                                                           ;Switch back to system stack for the rest of tick ISR\r
120 #endm\r
121 #pragma endasm\r
122 \r
123 /*-----------------------------------------------------------*/\r
124 \r
125 /*\r
126  * Perform hardware setup to enable ticks from timer 1,\r
127  */\r
128 static void prvSetupTimerInterrupt( void );\r
129 /*-----------------------------------------------------------*/\r
130 \r
131 /* \r
132  * Initialise the stack of a task to look exactly as if a call to \r
133  * portSAVE_CONTEXT had been called.\r
134  * \r
135  * See the header file portable.h.\r
136  */\r
137 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )\r
138 {\r
139         /* Place a few bytes of known values on the bottom of the stack. \r
140         This is just useful for debugging. */\r
141 \r
142         *pxTopOfStack = 0x11111111;\r
143         pxTopOfStack--;\r
144         *pxTopOfStack = 0x22222222;\r
145         pxTopOfStack--;\r
146         *pxTopOfStack = 0x33333333;\r
147         pxTopOfStack--;\r
148 \r
149         /* This is a redundant push to the stack, it may be required if in some implentation of the compiler\r
150         the parameter to the task is passed on to the stack rather than in R4 register*/\r
151         *pxTopOfStack = (portSTACK_TYPE)(pvParameters);\r
152         pxTopOfStack--;                  \r
153     \r
154         *pxTopOfStack = ( portSTACK_TYPE ) 0x00000000;  /* RP */\r
155         pxTopOfStack--;\r
156 \r
157         *pxTopOfStack = ( portSTACK_TYPE ) 0x00007777;  /* R7 */\r
158         pxTopOfStack--;\r
159         *pxTopOfStack = ( portSTACK_TYPE ) 0x00006666;  /* R6 */\r
160         pxTopOfStack--;\r
161         *pxTopOfStack = ( portSTACK_TYPE ) 0x00005555;  /* R5 */\r
162         pxTopOfStack--;\r
163         \r
164         /* In the current implemention of the compiler the first \r
165         parameter to the task(or function) is passed via R4 parameter \r
166         to the task, hennce the pvParameters pointer is copied in R4 \r
167         regsiter. See compiler manual section 4.6.2 for more information.*/\r
168         *pxTopOfStack = ( portSTACK_TYPE ) (pvParameters);      /* R4 */\r
169         pxTopOfStack--;\r
170         *pxTopOfStack = ( portSTACK_TYPE ) 0x00003333;  /* R3 */\r
171         pxTopOfStack--;\r
172         *pxTopOfStack = ( portSTACK_TYPE ) 0x00002222;  /* R2 */\r
173         pxTopOfStack--;\r
174         *pxTopOfStack = ( portSTACK_TYPE ) 0x00001111;  /* R1 */\r
175         pxTopOfStack--;\r
176         *pxTopOfStack = ( portSTACK_TYPE ) 0x00000001;  /* R0 */\r
177         pxTopOfStack--;\r
178         \r
179         *pxTopOfStack = ( portSTACK_TYPE ) 0x0000EEEE;  /* R14 */\r
180         pxTopOfStack--;\r
181         *pxTopOfStack = ( portSTACK_TYPE ) 0x0000DDDD;  /* R13 */\r
182         pxTopOfStack--;\r
183         *pxTopOfStack = ( portSTACK_TYPE ) 0x0000CCCC;  /* R12 */\r
184         pxTopOfStack--;\r
185         *pxTopOfStack = ( portSTACK_TYPE ) 0x0000BBBB;  /* R11 */\r
186         pxTopOfStack--;\r
187         *pxTopOfStack = ( portSTACK_TYPE ) 0x0000AAAA;  /* R10 */\r
188         pxTopOfStack--;\r
189         *pxTopOfStack = ( portSTACK_TYPE ) 0x00009999;  /* R9 */\r
190         pxTopOfStack--;\r
191         *pxTopOfStack = ( portSTACK_TYPE ) 0x00008888;  /* R8 */\r
192         pxTopOfStack--;\r
193         \r
194         *pxTopOfStack = ( portSTACK_TYPE ) 0x11110000;  /* MDH */\r
195         pxTopOfStack--;\r
196         *pxTopOfStack = ( portSTACK_TYPE ) 0x22220000;  /* MDL */\r
197         pxTopOfStack--;\r
198 \r
199         /* The task starts with its ulCriticalNesting variable set to 0, interrupts\r
200         being enabled. */\r
201         *pxTopOfStack = portNO_CRITICAL_NESTING;\r
202         pxTopOfStack--;\r
203 \r
204         /* The start of the task code. */\r
205         *pxTopOfStack = ( portSTACK_TYPE ) pxCode;      /* PC */\r
206         pxTopOfStack--;\r
207          \r
208     /* PS - User Mode, USP, ILM=31, Interrupts enabled */\r
209         *pxTopOfStack = ( portSTACK_TYPE ) 0x001F0030;  /* PS */\r
210 \r
211         return pxTopOfStack;\r
212 }\r
213 /*-----------------------------------------------------------*/\r
214 \r
215 portBASE_TYPE xPortStartScheduler( void )\r
216 {\r
217         /* Setup the hardware to generate the tick. */\r
218         prvSetupTimerInterrupt();\r
219 \r
220         /* Restore the context of the first task that is going to run. */\r
221 #pragma asm\r
222         RestoreContext\r
223 #pragma endasm\r
224 \r
225         /* Simulate a function call end as generated by the compiler.  We will now\r
226         jump to the start of the task the context of which we have just restored. */\r
227         \r
228         __asm(" reti ");\r
229 \r
230 \r
231         /* Should not get here. */\r
232         return pdTRUE;\r
233 }\r
234 /*-----------------------------------------------------------*/\r
235 \r
236 void vPortEndScheduler( void )\r
237 {\r
238         /* Not implemented - unlikely to ever be required as there is nothing to\r
239         return to. */\r
240 }\r
241 /*-----------------------------------------------------------*/\r
242 \r
243 /*\r
244  * Setup RLT0 to generate a tick interrupt.\r
245  */\r
246 static void prvSetupTimerInterrupt( void )\r
247 {\r
248 /* The peripheral clock divided by 32 is used by the timer. */\r
249 const unsigned portSHORT usReloadValue = ( unsigned portSHORT ) ( ( ( configPER_CLOCK_HZ / configTICK_RATE_HZ ) / 32UL ) - 1UL );\r
250 \r
251         TMCSR0_CNTE=0;          /* Count Disable */\r
252     TMCSR0_CSL=0x2;             /* CLKP/32 */\r
253     TMCSR0_MOD=0;               /* Software trigger */\r
254     TMCSR0_RELD=1;              /* Reload */\r
255     \r
256     TMCSR0_UF=0;                /* Clear underflow flag */\r
257         TMRLR0=usReloadValue;\r
258         TMCSR0_INTE=1;          /* Interrupt Enable */\r
259         TMCSR0_CNTE=1;          /* Count Enable */\r
260         TMCSR0_TRG=1;           /* Trigger */\r
261         \r
262     PORTEN = 0x3;               /* Port Enable */\r
263 }\r
264 /*-----------------------------------------------------------*/\r
265 \r
266 #if configUSE_PREEMPTION == 1\r
267 \r
268         /* \r
269          * Tick ISR for preemptive scheduler. The tick count is incremented \r
270          * after the context is saved. Then the context is switched if required,\r
271          * at last the context of the task which is to be resume is restored.\r
272          */\r
273 \r
274         #pragma asm\r
275 \r
276         .global _ReloadTimer0_IRQHandler\r
277         _ReloadTimer0_IRQHandler:\r
278 \r
279         ANDCCR #0xEF                                                    ;Disable Interrupts\r
280 \r
281         SaveContext                                                             ;Save context\r
282 \r
283         ORCCR #0x10                                                             ;Re-enable Interrupts\r
284 \r
285         LDI #0xFFFB,R1\r
286         LDI #_tmcsr0, R0\r
287         AND R1,@R0                                                              ;Clear RLT0 interrupt flag\r
288 \r
289         CALL32   _vTaskIncrementTick,R12                ;Increment Tick\r
290 \r
291         CALL32   _vTaskSwitchContext,R12                ;Switch context if required\r
292 \r
293         ANDCCR #0xEF                                                    ;Disable Interrupts\r
294 \r
295         RestoreContext                                                  ;Restore context\r
296 \r
297         ORCCR #0x10                                                             ;Re-enable Interrupts\r
298 \r
299         RETI\r
300 \r
301         #pragma endasm\r
302         \r
303 #else\r
304         \r
305         /* \r
306          * Tick ISR for the cooperative scheduler.  All this does is increment the\r
307          * tick count.  We don't need to switch context, this can only be done by\r
308          * manual calls to taskYIELD();\r
309          */\r
310         __interrupt void ReloadTimer0_IRQHandler( void )\r
311         {\r
312                 /* Clear RLT0 interrupt flag */\r
313                 TMCSR0_UF = 0; \r
314                 vTaskIncrementTick();\r
315         }\r
316 \r
317 #endif\r
318 \r
319         /*\r
320          * Manual context switch. We can use a __nosavereg attribute  as the context \r
321          * would be saved by PortSAVE_CONTEXT().  The context is switched and then \r
322          * the context of the new task is restored saved. \r
323          */\r
324 #pragma asm\r
325 \r
326         .global _vPortYieldDelayed\r
327         _vPortYieldDelayed:\r
328 \r
329         ANDCCR #0xEF                                                    ;Disable Interrupts\r
330 \r
331         SaveContext                                                             ;Save context\r
332 \r
333         ORCCR #0x10                                                             ;Re-enable Interrupts\r
334 \r
335         LDI #_dicr, R0\r
336         BANDL #0x0E, @R0                                                ;Clear Delayed interrupt flag\r
337 \r
338         CALL32   _vTaskSwitchContext,R12                ;Switch context if required\r
339 \r
340         ANDCCR #0xEF                                                    ;Disable Interrupts\r
341 \r
342         RestoreContext                                                  ;Restore context\r
343 \r
344         ORCCR #0x10                                                             ;Re-enable Interrupts\r
345 \r
346         RETI\r
347 \r
348 #pragma endasm\r
349 \r
350         /*\r
351          * Manual context switch. We can use a __nosavereg attribute  as the context \r
352          * would be saved by PortSAVE_CONTEXT().  The context is switched and then \r
353          * the context of the new task is restored saved. \r
354          */\r
355          \r
356 #pragma asm\r
357 \r
358         .global _vPortYield\r
359         _vPortYield:\r
360 \r
361         SaveContext                                                             ;Save context\r
362 \r
363         CALL32   _vTaskSwitchContext,R12                ;Switch context if required\r
364 \r
365         RestoreContext                                                  ;Restore context\r
366         \r
367         RETI\r
368 \r
369 #pragma endasm\r
370 \r
371 /*-----------------------------------------------------------*/\r
372 \r
373 void vPortEnterCritical( void )\r
374 {\r
375         /* Disable interrupts */\r
376         portDISABLE_INTERRUPTS();\r
377 \r
378         /* Now interrupts are disabled ulCriticalNesting can be accessed\r
379          directly.  Increment ulCriticalNesting to keep a count of how many times\r
380          portENTER_CRITICAL() has been called. */\r
381         ulCriticalNesting++;\r
382 }\r
383 /*-----------------------------------------------------------*/\r
384 \r
385 void vPortExitCritical( void )\r
386 {\r
387         if( ulCriticalNesting > portNO_CRITICAL_NESTING )\r
388         {\r
389                 ulCriticalNesting--;\r
390                 if( ulCriticalNesting == portNO_CRITICAL_NESTING )\r
391                 {\r
392                         /* Enable all interrupt/exception. */\r
393                         portENABLE_INTERRUPTS();\r
394                 }\r
395         }\r
396 }\r
397 /*-----------------------------------------------------------*/\r