diff options
Diffstat (limited to 'firmware/target/hosted/thread-arm.c')
-rw-r--r-- | firmware/target/hosted/thread-arm.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/firmware/target/hosted/thread-arm.c b/firmware/target/hosted/thread-arm.c new file mode 100644 index 0000000000..d2fa7d1e5d --- /dev/null +++ b/firmware/target/hosted/thread-arm.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 by Thom Johansen | ||
11 | * Copyright (C) 2010 by Thomas Martitz (Android-suitable core_sleep()) | ||
12 | * | ||
13 | * Generic ARM threading support | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version 2 | ||
18 | * of the License, or (at your option) any later version. | ||
19 | * | ||
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
21 | * KIND, either express or implied. | ||
22 | * | ||
23 | ****************************************************************************/ | ||
24 | |||
25 | #include <system.h> | ||
26 | /*--------------------------------------------------------------------------- | ||
27 | * Start the thread running and terminate it if it returns | ||
28 | *--------------------------------------------------------------------------- | ||
29 | */ | ||
30 | static void __attribute__((naked,used)) start_thread(void) | ||
31 | { | ||
32 | /* r0 = context */ | ||
33 | asm volatile ( | ||
34 | "ldr sp, [r0, #32] \n" /* Load initial sp */ | ||
35 | "ldr r4, [r0, #40] \n" /* start in r4 since it's non-volatile */ | ||
36 | "mov r1, #0 \n" /* Mark thread as running */ | ||
37 | "str r1, [r0, #40] \n" | ||
38 | "mov lr, pc \n" /* Call thread function */ | ||
39 | "bx r4 \n" | ||
40 | ); /* No clobber list - new thread doesn't care */ | ||
41 | thread_exit(); | ||
42 | } | ||
43 | |||
44 | /* For startup, place context pointer in r4 slot, start_thread pointer in r5 | ||
45 | * slot, and thread function pointer in context.start. See load_context for | ||
46 | * what happens when thread is initially going to run. */ | ||
47 | #define THREAD_STARTUP_INIT(core, thread, function) \ | ||
48 | ({ (thread)->context.r[0] = (uint32_t)&(thread)->context, \ | ||
49 | (thread)->context.r[1] = (uint32_t)start_thread, \ | ||
50 | (thread)->context.start = (uint32_t)function; }) | ||
51 | |||
52 | |||
53 | /*--------------------------------------------------------------------------- | ||
54 | * Store non-volatile context. | ||
55 | *--------------------------------------------------------------------------- | ||
56 | */ | ||
57 | static inline void store_context(void* addr) | ||
58 | { | ||
59 | asm volatile( | ||
60 | "stmia %0, { r4-r11, sp, lr } \n" | ||
61 | : : "r" (addr) | ||
62 | ); | ||
63 | } | ||
64 | |||
65 | /*--------------------------------------------------------------------------- | ||
66 | * Load non-volatile context. | ||
67 | *--------------------------------------------------------------------------- | ||
68 | */ | ||
69 | static inline void load_context(const void* addr) | ||
70 | { | ||
71 | asm volatile( | ||
72 | "ldr r0, [%0, #40] \n" /* Load start pointer */ | ||
73 | "cmp r0, #0 \n" /* Check for NULL */ | ||
74 | |||
75 | /* If not already running, jump to start */ | ||
76 | "ldmneia %0, { r0, pc } \n" | ||
77 | "ldmia %0, { r4-r11, sp, lr } \n" /* Load regs r4 to r14 from context */ | ||
78 | : : "r" (addr) : "r0" /* only! */ | ||
79 | ); | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * this core sleep suspends the OS thread rockbox runs under, which greatly | ||
84 | * reduces cpu usage (~100% to <10%) | ||
85 | * | ||
86 | * it returns when when the tick timer is called, other interrupt-like | ||
87 | * events occur | ||
88 | * | ||
89 | * wait_for_interrupt is implemented in kernel-<platform>.c | ||
90 | **/ | ||
91 | |||
92 | static inline void core_sleep(void) | ||
93 | { | ||
94 | enable_irq(); | ||
95 | wait_for_interrupt(); | ||
96 | } | ||
97 | |||
98 | |||