1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Ulf Ralberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
26 #if CONFIG_CPU == MCF5249
29 unsigned int d
[6]; /* d2-d7 */
30 unsigned int a
[5]; /* a2-a6 */
31 void *sp
; /* Stack pointer (a7) */
33 #elif CONFIG_CPU == SH7034
36 unsigned int r
[7]; /* Registers r8 thru r14 */
37 void *sp
; /* Stack pointer (r15) */
38 void* pr
; /* Procedure register */
43 static volatile int num_sleepers
;
44 static int current_thread
;
45 static struct regs thread_contexts
[MAXTHREADS
] __attribute__ ((section(".idata")));
46 const char *thread_name
[MAXTHREADS
];
47 void *thread_stack
[MAXTHREADS
];
48 int thread_stack_size
[MAXTHREADS
];
49 static const char main_thread_name
[] = "main";
51 extern int stackbegin
[];
52 extern int stackend
[];
54 void switch_thread(void) __attribute__ ((section(".icode")));
56 #if CONFIG_CPU == MCF5249
57 /*---------------------------------------------------------------------------
58 * Store non-volatile context.
59 *---------------------------------------------------------------------------
61 static inline void store_context(void* addr
)
63 asm volatile ("movem.l %%d2-%%d7/%%a2-%%a7,(%0)\n\t" : : "a" (addr
));
66 /*---------------------------------------------------------------------------
67 * Load non-volatile context.
68 *---------------------------------------------------------------------------
70 static inline void load_context(const void* addr
)
72 asm volatile ("movem.l (%0),%%d2-%%d7/%%a2-%%a7\n\t" : : "a" (addr
));
75 #elif CONFIG_CPU == SH7034
76 /*---------------------------------------------------------------------------
77 * Store non-volatile context.
78 *---------------------------------------------------------------------------
80 static inline void store_context(void* addr
)
82 asm volatile ("add #36, %0\n\t"
91 "mov.l r8, @-%0" : : "r" (addr
));
94 /*---------------------------------------------------------------------------
95 * Load non-volatile context.
96 *---------------------------------------------------------------------------
98 static inline void load_context(const void* addr
)
100 asm volatile ("mov.l @%0+,r8\n\t"
110 "mov.l %0, @(0, r15)" : "+r" (addr
));
114 /*---------------------------------------------------------------------------
115 * Switch thread in round robin fashion.
116 *---------------------------------------------------------------------------
118 void switch_thread(void)
122 unsigned int *stackptr
;
128 while (num_sleepers
== num_threads
)
130 /* Enter sleep mode, woken up on interrupt */
131 #if CONFIG_CPU == MCF5249
132 asm volatile ("stop #0x2000");
135 asm volatile ("sleep");
140 next
= current
= current_thread
;
142 if (++next
>= num_threads
)
144 current_thread
= next
;
145 store_context(&thread_contexts
[current
]);
147 /* Check if the current thread stack is overflown */
148 stackptr
= thread_stack
[current
];
150 if(stackptr
[0] != 0xdeadbeef)
151 panicf("Stkov %s", thread_name
[current
]);
154 load_context(&thread_contexts
[next
]);
157 void sleep_thread(void)
163 void wake_up_thread(void)
168 /*---------------------------------------------------------------------------
170 * Return ID if context area could be allocated, else -1.
171 *---------------------------------------------------------------------------
173 int create_thread(void* function
, void* stack
, int stack_size
,
177 unsigned int stacklen
;
178 unsigned int *stackptr
;
181 if (num_threads
>= MAXTHREADS
)
184 /* Munge the stack to make it easy to spot stack overflows */
185 stacklen
= stack_size
/ 4;
187 for(i
= 0;i
< stacklen
;i
++)
189 stackptr
[i
] = 0xdeadbeef;
192 /* Store interesting information */
193 thread_name
[num_threads
] = name
;
194 thread_stack
[num_threads
] = stack
;
195 thread_stack_size
[num_threads
] = stack_size
;
196 regs
= &thread_contexts
[num_threads
];
198 #if CONFIG_CPU == MCF5249
199 regs
->sp
= (void*)(((unsigned int)stack
+ stack_size
- 4) & ~3);
200 /* Put the return address on the stack */
201 *(unsigned long *)(regs
->sp
) = (int)function
;
202 #elif CONFIG_CPU == SH7034
203 /* Subtract 4 to leave room for the PR push in load_context()
204 Align it on an even 32 bit boundary */
205 regs
->sp
= (void*)(((unsigned int)stack
+ stack_size
- 4) & ~3);
210 return num_threads
++; /* return the current ID, e.g for remove_thread() */
213 /*---------------------------------------------------------------------------
214 * Remove a thread from the scheduler.
215 * Parameter is the ID as returned from create_thread().
216 *---------------------------------------------------------------------------
218 void remove_thread(int threadnum
)
222 if(threadnum
>= num_threads
)
226 for (i
=threadnum
; i
<num_threads
-1; i
++)
227 { /* move all entries which are behind */
228 thread_name
[i
] = thread_name
[i
+1];
229 thread_stack
[i
] = thread_stack
[i
+1];
230 thread_stack_size
[i
] = thread_stack_size
[i
+1];
231 thread_contexts
[i
] = thread_contexts
[i
+1];
234 if (current_thread
== threadnum
) /* deleting the current one? */
235 current_thread
= num_threads
; /* set beyond last, avoid store harm */
236 else if (current_thread
> threadnum
) /* within the moved positions? */
237 current_thread
--; /* adjust it, point to same context again */
240 void init_threads(void)
242 num_threads
= 1; /* We have 1 thread to begin with */
243 current_thread
= 0; /* The current thread is number 0 */
244 thread_name
[0] = main_thread_name
;
245 thread_stack
[0] = stackbegin
;
246 thread_stack_size
[0] = (int)stackend
- (int)stackbegin
;
250 int thread_stack_usage(int threadnum
)
253 unsigned int *stackptr
= thread_stack
[threadnum
];
255 if(threadnum
>= num_threads
)
258 for(i
= 0;i
< thread_stack_size
[threadnum
]/sizeof(int);i
++)
260 if(stackptr
[i
] != 0xdeadbeef)
264 return ((thread_stack_size
[threadnum
] - i
* 4) * 100) /
265 thread_stack_size
[threadnum
];