]> git.sur5r.net Git - freertos/blob - Source/portable/Softune/MB91460/port.c
90ad448026655e484a07a03122ac7be200f69f9b
[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 #pragma asm\r
61 #macro  SaveContext\r
62          ORCCR #0x20                                                            ;Switch to user stack\r
63          ST RP,@-R15                                                            ;Store RP\r
64          STM0 (R7,R6,R5,R4,R3,R2,R1,R0)                         ;Store R7-R0\r
65          STM1 (R14,R13,R12,R11,R10,R9,R8)                       ;Store R14-R8\r
66          ST MDH, @-R15                                                          ;Store MDH\r
67          ST MDL, @-R15                                                          ;Store MDL\r
68 \r
69          LDI #_ulCriticalNesting, R0                            ;Get the address of the critical nesting counter\r
70          LD @R0, R0                                                                     ;Get the value of the critical nesting counter\r
71          ST R0, @-R15                                                           ;Store the critical nesting value to the user stack.\r
72          \r
73          ANDCCR #0xDF                                                           ;Switch back to system stack\r
74          LD @R15+,R0                                                            ;Store PC to R0 \r
75          ORCCR #0x20                                                            ;Switch to user stack\r
76          ST R0,@-R15                                                            ;Store PC to User stack\r
77          \r
78          ANDCCR #0xDF                                                           ;Switch back to system stack\r
79          LD @R15+,R0                                                            ;Store PS to R0\r
80          ORCCR #0x20                                                            ;Switch to user stack\r
81          ST R0,@-R15                                                            ;Store PS to User stack\r
82          \r
83          LDI #_pxCurrentTCB, R0                                         ;Get pxCurrentTCB address\r
84          LD @R0, R0                                                                     ;Get the pxCurrentTCB->pxTopOfStack address\r
85          ST R15,@R0                                                                     ;Store USP to pxCurrentTCB->pxTopOfStack\r
86          \r
87          ANDCCR #0xDF                                                           ;Switch back to system stack for the rest of tick ISR\r
88 #endm\r
89 \r
90 #macro RestoreContext\r
91          LDI #_pxCurrentTCB, R0                                         ;Get pxCurrentTCB address\r
92          LD @R0, R0                                                                     ;Get the pxCurrentTCB->pxTopOfStack address\r
93          ORCCR #0x20                                                            ;Switch to user stack\r
94          LD @R0, R15                                                            ;Restore USP from pxCurrentTCB->pxTopOfStack\r
95 \r
96          LD @R15+,R0                                                            ;Store PS to R0\r
97          ANDCCR #0xDF                                                           ;Switch to system stack\r
98          ST R0,@-R15                                                            ;Store PS to system stack\r
99 \r
100          ORCCR #0x20                                                            ;Switch to user stack\r
101          LD @R15+,R0                                                            ;Store PC to R0\r
102          ANDCCR #0xDF                                                           ;Switch to system stack\r
103          ST R0,@-R15                                                            ;Store PC to system stack\r
104 \r
105          ORCCR #0x20                                                            ;Switch back to retrieve the remaining context\r
106 \r
107          LDI #_ulCriticalNesting, R0                            ;Get the address of the critical nesting counter\r
108          LD @R15+, R1                                                           ;Get the saved critical nesting value\r
109          ST R1, @R0                                                                     ;Save the critical nesting value into the ulCriticalNesting variable\r
110 \r
111          LD @R15+, MDL                                                          ;Restore MDL\r
112          LD @R15+, MDH                                                          ;Restore MDH\r
113          LDM1 (R14,R13,R12,R11,R10,R9,R8)                       ;Restore R14-R8\r
114          LDM0 (R7,R6,R5,R4,R3,R2,R1,R0)                         ;Restore R7-R0\r
115          LD @R15+, RP                                                           ;Restore RP\r
116          \r
117          ANDCCR #0xDF                                                           ;Switch back to system stack for the rest of tick ISR\r
118 #endm\r
119 #pragma endasm\r
120 \r
121 /*-----------------------------------------------------------*/\r
122 \r
123 /*\r
124  * Perform hardware setup to enable ticks from timer 1,\r
125  */\r
126 static void prvSetupTimerInterrupt( void );\r
127 /*-----------------------------------------------------------*/\r
128 \r
129 /* \r
130  * Initialise the stack of a task to look exactly as if a call to \r
131  * portSAVE_CONTEXT had been called.\r
132  * \r
133  * See the header file portable.h.\r
134  */\r
135 portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )\r
136 {\r
137         /* Place a few bytes of known values on the bottom of the stack. \r
138         This is just useful for debugging. */\r
139 \r
140         *pxTopOfStack = 0x11111111;\r
141         pxTopOfStack--;\r
142         *pxTopOfStack = 0x22222222;\r
143         pxTopOfStack--;\r
144         *pxTopOfStack = 0x33333333;\r
145         pxTopOfStack--;\r
146 \r
147         /* This is a redundant push to the stack, it may be required if \r
148         in some implementations of the compiler the parameter to the task \r
149         is passed on to the stack rather than in R4 register. */\r
150         *pxTopOfStack = (portSTACK_TYPE)(pvParameters);\r
151         pxTopOfStack--;                  \r
152     \r
153         *pxTopOfStack = ( portSTACK_TYPE ) 0x00000000;  /* RP */\r
154         pxTopOfStack--;\r
155         *pxTopOfStack = ( portSTACK_TYPE ) 0x00007777;  /* R7 */\r
156         pxTopOfStack--;\r
157         *pxTopOfStack = ( portSTACK_TYPE ) 0x00006666;  /* R6 */\r
158         pxTopOfStack--;\r
159         *pxTopOfStack = ( portSTACK_TYPE ) 0x00005555;  /* R5 */\r
160         pxTopOfStack--;\r
161         \r
162         /* In the current implementation of the compiler the first \r
163         parameter to the task (or function) is passed via R4 parameter \r
164         to the task, hence the pvParameters pointer is copied into the R4 \r
165         register. See compiler manual section 4.6.2 for more information. */\r
166         *pxTopOfStack = ( portSTACK_TYPE ) (pvParameters);      /* R4 */\r
167         pxTopOfStack--;\r
168         *pxTopOfStack = ( portSTACK_TYPE ) 0x00003333;  /* R3 */\r
169         pxTopOfStack--;\r
170         *pxTopOfStack = ( portSTACK_TYPE ) 0x00002222;  /* R2 */\r
171         pxTopOfStack--;\r
172         *pxTopOfStack = ( portSTACK_TYPE ) 0x00001111;  /* R1 */\r
173         pxTopOfStack--;\r
174         *pxTopOfStack = ( portSTACK_TYPE ) 0x00000001;  /* R0 */\r
175         pxTopOfStack--; \r
176         *pxTopOfStack = ( portSTACK_TYPE ) 0x0000EEEE;  /* R14 */\r
177         pxTopOfStack--;\r
178         *pxTopOfStack = ( portSTACK_TYPE ) 0x0000DDDD;  /* R13 */\r
179         pxTopOfStack--;\r
180         *pxTopOfStack = ( portSTACK_TYPE ) 0x0000CCCC;  /* R12 */\r
181         pxTopOfStack--;\r
182         *pxTopOfStack = ( portSTACK_TYPE ) 0x0000BBBB;  /* R11 */\r
183         pxTopOfStack--;\r
184         *pxTopOfStack = ( portSTACK_TYPE ) 0x0000AAAA;  /* R10 */\r
185         pxTopOfStack--;\r
186         *pxTopOfStack = ( portSTACK_TYPE ) 0x00009999;  /* R9 */\r
187         pxTopOfStack--;\r
188         *pxTopOfStack = ( portSTACK_TYPE ) 0x00008888;  /* R8 */\r
189         pxTopOfStack--; \r
190         *pxTopOfStack = ( portSTACK_TYPE ) 0x11110000;  /* MDH */\r
191         pxTopOfStack--;\r
192         *pxTopOfStack = ( portSTACK_TYPE ) 0x22220000;  /* MDL */\r
193         pxTopOfStack--;\r
194 \r
195         /* The task starts with its ulCriticalNesting variable set to 0, \r
196         interrupts being enabled. */\r
197         *pxTopOfStack = portNO_CRITICAL_NESTING;\r
198         pxTopOfStack--;\r
199 \r
200         /* The start of the task code. */\r
201         *pxTopOfStack = ( portSTACK_TYPE ) pxCode;      /* PC */\r
202         pxTopOfStack--;\r
203          \r
204     /* PS - User Mode, USP, ILM=31, Interrupts enabled */\r
205         *pxTopOfStack = ( portSTACK_TYPE ) 0x001F0030;  /* PS */\r
206 \r
207         return pxTopOfStack;\r
208 }\r
209 /*-----------------------------------------------------------*/\r
210 \r
211 portBASE_TYPE xPortStartScheduler( void )\r
212 {\r
213         /* Setup the hardware to generate the tick. */\r
214         prvSetupTimerInterrupt();\r
215 \r
216         /* Restore the context of the first task that is going to run. */\r
217         #pragma asm\r
218                 RestoreContext\r
219         #pragma endasm\r
220 \r
221         /* Simulate a function call end as generated by the compiler.  We will now\r
222         jump to the start of the task the context of which we have just restored. */    \r
223         __asm(" reti ");\r
224 \r
225         /* Should not get here. */\r
226         return pdFAIL;\r
227 }\r
228 /*-----------------------------------------------------------*/\r
229 \r
230 void vPortEndScheduler( void )\r
231 {\r
232         /* Not implemented - unlikely to ever be required as there is nothing to\r
233         return to. */\r
234 }\r
235 /*-----------------------------------------------------------*/\r
236 \r
237 static void prvSetupTimerInterrupt( void )\r
238 {\r
239 /* The peripheral clock divided by 32 is used by the timer. */\r
240 const unsigned portSHORT usReloadValue = ( unsigned portSHORT ) ( ( ( configPER_CLOCK_HZ / configTICK_RATE_HZ ) / 32UL ) - 1UL );\r
241 \r
242         /* Setup RLT0 to generate a tick interrupt. */\r
243 \r
244         TMCSR0_CNTE = 0;                /* Count Disable */\r
245     TMCSR0_CSL = 0x2;           /* CLKP/32 */\r
246     TMCSR0_MOD = 0;                     /* Software trigger */\r
247     TMCSR0_RELD = 1;            /* Reload */\r
248     \r
249     TMCSR0_UF = 0;                      /* Clear underflow flag */\r
250         TMRLR0 = usReloadValue;\r
251         TMCSR0_INTE = 1;                /* Interrupt Enable */\r
252         TMCSR0_CNTE = 1;                /* Count Enable */\r
253         TMCSR0_TRG = 1;                 /* Trigger */\r
254         \r
255     PORTEN = 0x3;                       /* Port Enable */\r
256 }\r
257 /*-----------------------------------------------------------*/\r
258 \r
259 #if configUSE_PREEMPTION == 1\r
260 \r
261         /* \r
262          * Tick ISR for preemptive scheduler. The tick count is incremented \r
263          * after the context is saved. Then the context is switched if required,\r
264          * and last the context of the task which is to be resumed is restored.\r
265          */\r
266 \r
267         #pragma asm\r
268 \r
269         .global _ReloadTimer0_IRQHandler\r
270         _ReloadTimer0_IRQHandler:\r
271 \r
272         ANDCCR #0xEF                                                    ;Disable Interrupts\r
273         SaveContext                                                             ;Save context\r
274         ORCCR #0x10                                                             ;Re-enable Interrupts\r
275 \r
276         LDI #0xFFFB,R1\r
277         LDI #_tmcsr0, R0\r
278         AND R1,@R0                                                              ;Clear RLT0 interrupt flag\r
279 \r
280         CALL32   _vTaskIncrementTick,R12                ;Increment Tick\r
281         CALL32   _vTaskSwitchContext,R12                ;Switch context if required\r
282 \r
283         ANDCCR #0xEF                                                    ;Disable Interrupts\r
284         RestoreContext                                                  ;Restore context\r
285         ORCCR #0x10                                                             ;Re-enable Interrupts\r
286 \r
287         RETI\r
288 \r
289         #pragma endasm\r
290         \r
291 #else\r
292         \r
293         /* \r
294          * Tick ISR for the cooperative scheduler.  All this does is increment the\r
295          * tick count.  We don't need to switch context, this can only be done by\r
296          * manual calls to taskYIELD();\r
297          */\r
298         __interrupt void ReloadTimer0_IRQHandler( void )\r
299         {\r
300                 /* Clear RLT0 interrupt flag */\r
301                 TMCSR0_UF = 0; \r
302                 vTaskIncrementTick();\r
303         }\r
304 \r
305 #endif\r
306 \r
307 /*\r
308  * Manual context switch. We can use a __nosavereg attribute  as the context \r
309  * would be saved by PortSAVE_CONTEXT().  The context is switched and then \r
310  * the context of the new task is restored saved. \r
311  */\r
312 #pragma asm\r
313 \r
314         .global _vPortYieldDelayed\r
315         _vPortYieldDelayed:\r
316 \r
317         ANDCCR #0xEF                                                    ;Disable Interrupts\r
318         SaveContext                                                             ;Save context\r
319         ORCCR #0x10                                                             ;Re-enable Interrupts\r
320 \r
321         LDI #_dicr, R0\r
322         BANDL #0x0E, @R0                                                ;Clear Delayed interrupt flag\r
323 \r
324         CALL32   _vTaskSwitchContext,R12                ;Switch context if required\r
325 \r
326         ANDCCR #0xEF                                                    ;Disable Interrupts\r
327         RestoreContext                                                  ;Restore context\r
328         ORCCR #0x10                                                             ;Re-enable Interrupts\r
329 \r
330         RETI\r
331 \r
332 #pragma endasm\r
333 /*-----------------------------------------------------------*/\r
334 \r
335 /*\r
336  * Manual context switch. We can use a __nosavereg attribute  as the context \r
337  * would be saved by PortSAVE_CONTEXT().  The context is switched and then \r
338  * the context of the new task is restored saved. \r
339  */      \r
340 #pragma asm\r
341 \r
342         .global _vPortYield\r
343         _vPortYield:\r
344 \r
345         SaveContext                                                             ;Save context\r
346         CALL32   _vTaskSwitchContext,R12                ;Switch context if required\r
347         RestoreContext                                                  ;Restore context\r
348         \r
349         RETI\r
350 \r
351 #pragma endasm\r
352 /*-----------------------------------------------------------*/\r
353 \r
354 void vPortEnterCritical( void )\r
355 {\r
356         /* Disable interrupts upto level 30. */\r
357         #if configKERNEL_INTERRUPT_PRIORITY != 30\r
358                 #error configKERNEL_INTERRUPT_PRIORITY (set in FreeRTOSConfig.h) must match the ILM value set in the following line - 30 (0x1e) being the default.\r
359         #endif\r
360 \r
361         __asm(" STILM #1Eh ");\r
362  \r
363 \r
364         /* Now interrupts are disabled ulCriticalNesting can be accessed\r
365         directly. Increment ulCriticalNesting to keep a count of how many times\r
366         portENTER_CRITICAL() has been called. */\r
367         ulCriticalNesting++;\r
368 }\r
369 /*-----------------------------------------------------------*/ \r
370 \r
371 void vPortExitCritical( void )\r
372 {\r
373         if( ulCriticalNesting > portNO_CRITICAL_NESTING )\r
374         {\r
375                 ulCriticalNesting--;\r
376                 if( ulCriticalNesting == portNO_CRITICAL_NESTING )\r
377                 {\r
378                         /* Enable all interrupts */\r
379                         __asm(" STILM #1Fh ");\r
380                 }\r
381         }\r
382 }\r