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 ****************************************************************************/
27 unsigned int r
[7]; /* Registers r8 thru r14 */
28 void *sp
; /* Stack pointer (r15) */
31 unsigned int sr
; /* Status register */
32 void* pr
; /* Procedure register */
36 static volatile int num_sleepers
;
37 static int current_thread
;
38 static struct regs thread_contexts
[MAXTHREADS
] __attribute__ ((section(".idata")));
39 char *thread_name
[MAXTHREADS
];
40 void *thread_stack
[MAXTHREADS
];
41 int thread_stack_size
[MAXTHREADS
];
42 static char main_thread_name
[] = "main";
44 extern int stackbegin
[];
45 extern int stackend
[];
47 void switch_thread(void) __attribute__ ((section(".icode")));
49 /*---------------------------------------------------------------------------
50 * Store non-volatile context.
51 *---------------------------------------------------------------------------
53 static inline void store_context(void* addr
)
55 asm volatile ("add #48, %0\n\t"
67 "mov.l r8, @-%0" : : "r" (addr
));
70 /*---------------------------------------------------------------------------
71 * Load non-volatile context.
72 *---------------------------------------------------------------------------
74 static inline void load_context(void* addr
)
76 asm volatile ("mov.l @%0+,r8\n\t"
89 "mov.l %0, @(0, r15)" : "+r" (addr
));
92 /*---------------------------------------------------------------------------
93 * Switch thread in round robin fashion.
94 *---------------------------------------------------------------------------
96 void switch_thread(void)
100 unsigned int *stackptr
;
106 while (num_sleepers
== num_threads
)
108 /* Enter sleep mode, woken up on interrupt */
110 asm volatile ("sleep");
114 next
= current
= current_thread
;
116 if (++next
>= num_threads
)
118 current_thread
= next
;
119 store_context(&thread_contexts
[current
]);
121 /* Check if the current thread stack is overflown */
122 stackptr
= thread_stack
[current
];
123 if(stackptr
[0] != 0xdeadbeef)
124 panicf("Stkov %s", thread_name
[current
]);
126 load_context(&thread_contexts
[next
]);
129 void sleep_thread(void)
135 void wake_up_thread(void)
140 /*---------------------------------------------------------------------------
142 * Return ID if context area could be allocated, else -1.
143 *---------------------------------------------------------------------------
145 int create_thread(void* function
, void* stack
, int stack_size
, char *name
)
148 unsigned int stacklen
;
149 unsigned int *stackptr
;
152 if (num_threads
>= MAXTHREADS
)
155 /* Munge the stack to make it easy to spot stack overflows */
156 stacklen
= stack_size
/ 4;
158 for(i
= 0;i
< stacklen
;i
++)
160 stackptr
[i
] = 0xdeadbeef;
163 /* Store interesting information */
164 thread_name
[num_threads
] = name
;
165 thread_stack
[num_threads
] = stack
;
166 thread_stack_size
[num_threads
] = stack_size
;
167 regs
= &thread_contexts
[num_threads
];
169 /* Subtract 4 to leave room for the PR push in load_context()
170 Align it on an even 32 bit boundary */
171 regs
->sp
= (void*)(((unsigned int)stack
+ stack_size
- 4) & ~3);
176 return num_threads
++; /* return the current ID, e.g for remove_thread() */
179 /*---------------------------------------------------------------------------
180 * Remove a thread from the scheduler.
181 * Parameter is the ID as returned from create_thread().
182 *---------------------------------------------------------------------------
184 void remove_thread(int threadnum
)
188 if(threadnum
>= num_threads
)
192 for (i
=threadnum
; i
<num_threads
-1; i
++)
193 { /* move all entries which are behind */
194 thread_name
[i
] = thread_name
[i
+1];
195 thread_stack
[i
] = thread_stack
[i
+1];
196 thread_stack_size
[i
] = thread_stack_size
[i
+1];
197 thread_contexts
[i
] = thread_contexts
[i
+1];
200 if (current_thread
== threadnum
) /* deleting the current one? */
201 current_thread
= num_threads
; /* set beyond last, avoid store harm */
202 else if (current_thread
> threadnum
) /* within the moved positions? */
203 current_thread
--; /* adjust it, point to same context again */
206 void init_threads(void)
208 num_threads
= 1; /* We have 1 thread to begin with */
209 current_thread
= 0; /* The current thread is number 0 */
210 thread_name
[0] = main_thread_name
;
211 thread_stack
[0] = stackbegin
;
212 thread_stack_size
[0] = (int)stackend
- (int)stackbegin
;
216 int thread_stack_usage(int threadnum
)
219 unsigned int *stackptr
= thread_stack
[threadnum
];
221 if(threadnum
>= num_threads
)
224 for(i
= 0;i
< thread_stack_size
[threadnum
]/sizeof(int);i
++)
226 if(stackptr
[i
] != 0xdeadbeef)
230 return ((thread_stack_size
[threadnum
] - i
* 4) * 100) /
231 thread_stack_size
[threadnum
];