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 ****************************************************************************/
24 unsigned int r
[7]; /* Registers r8 thru r14 */
25 void *sp
; /* Stack pointer (r15) */
28 unsigned int sr
; /* Status register */
29 void* pr
; /* Procedure register */
33 static int current_thread
;
34 static struct regs thread_contexts
[MAXTHREADS
] __attribute__ ((section(".idata")));
35 char *thread_name
[MAXTHREADS
];
36 void *thread_stack
[MAXTHREADS
];
37 int thread_stack_size
[MAXTHREADS
];
38 static char main_thread_name
[] = "main";
40 extern int stackbegin
[];
41 extern int stackend
[];
43 void switch_thread(void) __attribute__ ((section(".icode")));
45 /*---------------------------------------------------------------------------
46 * Store non-volatile context.
47 *---------------------------------------------------------------------------
49 static inline void store_context(void* addr
)
51 asm volatile ("add #48, %0\n\t"
63 "mov.l r8, @-%0" : : "r" (addr
));
66 /*---------------------------------------------------------------------------
67 * Load non-volatile context.
68 *---------------------------------------------------------------------------
70 static inline void load_context(void* addr
)
72 asm volatile ("mov.l @%0+,r8\n\t"
85 "mov.l %0, @(0, r15)" : "+r" (addr
));
88 /*---------------------------------------------------------------------------
89 * Switch thread in round robin fashion.
90 *---------------------------------------------------------------------------
92 void switch_thread(void)
96 unsigned int *stackptr
;
98 next
= current
= current_thread
;
99 if (++next
>= num_threads
)
101 current_thread
= next
;
102 store_context(&thread_contexts
[current
]);
103 load_context(&thread_contexts
[next
]);
105 stackptr
= thread_stack
[next
];
107 if(stackptr
[0] != 0xdeadbeef)
108 panicf("Stkov %s", thread_name
[next
]);
111 /*---------------------------------------------------------------------------
113 * Return 0 if context area could be allocated, else -1.
114 *---------------------------------------------------------------------------
116 int create_thread(void* function
, void* stack
, int stack_size
, char *name
)
119 unsigned int stacklen
;
120 unsigned int *stackptr
;
123 if (num_threads
>= MAXTHREADS
)
127 /* Munge the stack to make it easy to spot stack overflows */
128 stacklen
= stack_size
/ 4;
130 for(i
= 0;i
< stacklen
;i
++)
132 stackptr
[i
] = 0xdeadbeef;
135 /* Store interesting information */
136 thread_name
[num_threads
] = name
;
137 thread_stack
[num_threads
] = stack
;
138 thread_stack_size
[num_threads
] = stack_size
;
139 regs
= &thread_contexts
[num_threads
++];
141 /* Subtract 4 to leave room for the PR push in load_context()
142 Align it on an even 32 bit boundary */
143 regs
->sp
= (void*)(((unsigned int)stack
+ stack_size
- 4) & ~3);
150 void init_threads(void)
152 num_threads
= 1; /* We have 1 thread to begin with */
153 current_thread
= 0; /* The current thread is number 0 */
154 thread_name
[0] = main_thread_name
;
155 thread_stack
[0] = stackbegin
;
156 thread_stack_size
[0] = (int)stackend
- (int)stackbegin
;
159 int thread_stack_usage(int threadnum
)
162 unsigned int *stackptr
= thread_stack
[threadnum
];
164 if(threadnum
>= num_threads
)
167 for(i
= 0;i
< thread_stack_size
[threadnum
]/sizeof(int);i
++)
169 if(stackptr
[i
] != 0xdeadbeef)
173 return ((thread_stack_size
[threadnum
] - i
* 4) * 100) /
174 thread_stack_size
[threadnum
];