summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2012-01-04 18:07:21 +0100
committerThomas Martitz <kugel@rockbox.org>2012-01-22 18:46:44 +0100
commit991ae1e39553172a7dd6cd8c634aebfce892e261 (patch)
tree672a4583af663def399c4fefdbad060605397fbc /firmware/target
parenteaa83bd64775b87e943d345e2810deed44408776 (diff)
downloadrockbox-991ae1e39553172a7dd6cd8c634aebfce892e261.tar.gz
rockbox-991ae1e39553172a7dd6cd8c634aebfce892e261.zip
Create fimrware/asm directory for assembly optimized stuff.
This dir is suitable for stuff that doesn't fit the target tree, e.g. because it also builds on hosted or otherwise. It also has a generic subfolder for fallback C implementations so that not all archs need to provide asm files. SOURCES should only contain "foo.c" where foo.c includes the specific <arch>/foo.c files from the subdirs using the preprocessor. This way automatic selection of asm versions or generic C verion is possible. For the start, the thread support files are moved, since ASM threads can be used on hosted platforms as well. Since core_sleep() remains platform specific it's moved to the corresponding system.h headers. Change-Id: Iebff272f3407a6eaafeb7656ceb0ae9eca3f7cb9
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/system-arm.h27
-rw-r--r--firmware/target/arm/thread-arm.c121
-rw-r--r--firmware/target/coldfire/system-target.h10
-rw-r--r--firmware/target/coldfire/thread-coldfire.c111
-rw-r--r--firmware/target/hosted/android/system-target.h5
-rw-r--r--firmware/target/hosted/sdl/system-sdl.h9
-rw-r--r--firmware/target/hosted/system-hosted.h37
-rw-r--r--firmware/target/hosted/thread-arm.c99
-rw-r--r--firmware/target/hosted/thread-unix.c316
-rw-r--r--firmware/target/hosted/thread-win32.c85
-rw-r--r--firmware/target/hosted/ypr0/system-target.h5
-rw-r--r--firmware/target/mips/ingenic_jz47xx/system-target.h24
-rw-r--r--firmware/target/mips/thread-mips32.c133
-rw-r--r--firmware/target/sh/system-target.h14
-rw-r--r--firmware/target/sh/thread-sh.c109
15 files changed, 116 insertions, 989 deletions
diff --git a/firmware/target/arm/system-arm.h b/firmware/target/arm/system-arm.h
index ffce77a176..719ec82f1b 100644
--- a/firmware/target/arm/system-arm.h
+++ b/firmware/target/arm/system-arm.h
@@ -347,4 +347,31 @@ static inline uint32_t swaw32_hw(uint32_t value)
347 347
348} 348}
349 349
350#if defined(CPU_TCC780X) || defined(CPU_TCC77X) /* Single core only for now */ \
351|| CONFIG_CPU == IMX31L || CONFIG_CPU == DM320 || CONFIG_CPU == AS3525 \
352|| CONFIG_CPU == S3C2440 || CONFIG_CPU == S5L8701 || CONFIG_CPU == AS3525v2 \
353|| CONFIG_CPU == S5L8702
354/* Use the generic ARMv4/v5/v6 wait for IRQ */
355static inline void core_sleep(void)
356{
357 asm volatile (
358 "mcr p15, 0, %0, c7, c0, 4 \n" /* Wait for interrupt */
359#if CONFIG_CPU == IMX31L
360 "nop\n nop\n nop\n nop\n nop\n" /* Clean out the pipes */
361#endif
362 : : "r"(0)
363 );
364 enable_irq();
365}
366#else
367/* Skip this if special code is required and implemented */
368#if !(defined(CPU_PP)) && CONFIG_CPU != RK27XX && CONFIG_CPU != IMX233
369static inline void core_sleep(void)
370{
371 /* TODO: core_sleep not implemented, battery life will be decreased */
372 enable_irq();
373}
374#endif /* CPU_PP */
375#endif
376
350#endif /* SYSTEM_ARM_H */ 377#endif /* SYSTEM_ARM_H */
diff --git a/firmware/target/arm/thread-arm.c b/firmware/target/arm/thread-arm.c
deleted file mode 100644
index 88dac2542a..0000000000
--- a/firmware/target/arm/thread-arm.c
+++ /dev/null
@@ -1,121 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 by Thom Johansen
11 *
12 * Generic ARM threading support
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24/*---------------------------------------------------------------------------
25 * Start the thread running and terminate it if it returns
26 *---------------------------------------------------------------------------
27 */
28static void __attribute__((naked)) USED_ATTR start_thread(void)
29{
30 /* r0 = context */
31 asm volatile (
32 "ldr sp, [r0, #32] \n" /* Load initial sp */
33 "ldr r4, [r0, #40] \n" /* start in r4 since it's non-volatile */
34 "mov r1, #0 \n" /* Mark thread as running */
35 "str r1, [r0, #40] \n"
36#if NUM_CORES > 1
37 "ldr r0, =commit_discard_idcache \n" /* Invalidate this core's cache. */
38 "mov lr, pc \n" /* This could be the first entry into */
39 "bx r0 \n" /* plugin or codec code for this core. */
40#endif
41 "mov lr, pc \n" /* Call thread function */
42 "bx r4 \n"
43 ); /* No clobber list - new thread doesn't care */
44 thread_exit();
45#if 0
46 asm volatile (".ltorg"); /* Dump constant pool */
47#endif
48}
49
50/* For startup, place context pointer in r4 slot, start_thread pointer in r5
51 * slot, and thread function pointer in context.start. See load_context for
52 * what happens when thread is initially going to run. */
53#define THREAD_STARTUP_INIT(core, thread, function) \
54 ({ (thread)->context.r[0] = (uint32_t)&(thread)->context, \
55 (thread)->context.r[1] = (uint32_t)start_thread, \
56 (thread)->context.start = (uint32_t)function; })
57
58
59/*---------------------------------------------------------------------------
60 * Store non-volatile context.
61 *---------------------------------------------------------------------------
62 */
63static inline void store_context(void* addr)
64{
65 asm volatile(
66 "stmia %0, { r4-r11, sp, lr } \n"
67 : : "r" (addr)
68 );
69}
70
71/*---------------------------------------------------------------------------
72 * Load non-volatile context.
73 *---------------------------------------------------------------------------
74 */
75static inline void load_context(const void* addr)
76{
77 asm volatile(
78 "ldr r0, [%0, #40] \n" /* Load start pointer */
79 "cmp r0, #0 \n" /* Check for NULL */
80
81 /* If not already running, jump to start */
82#if ARM_ARCH == 4 && defined(USE_THUMB)
83 "ldmneia %0, { r0, r12 } \n"
84 "bxne r12 \n"
85#else
86 "ldmneia %0, { r0, pc } \n"
87#endif
88
89 "ldmia %0, { r4-r11, sp, lr } \n" /* Load regs r4 to r14 from context */
90 : : "r" (addr) : "r0" /* only! */
91 );
92}
93
94#if defined(CPU_TCC780X) || defined(CPU_TCC77X) /* Single core only for now */ \
95|| CONFIG_CPU == IMX31L || CONFIG_CPU == DM320 || CONFIG_CPU == AS3525 \
96|| CONFIG_CPU == S3C2440 || CONFIG_CPU == S5L8701 || CONFIG_CPU == AS3525v2 \
97|| CONFIG_CPU == S5L8702
98/* Use the generic ARMv4/v5/v6 wait for IRQ */
99static inline void core_sleep(void)
100{
101 asm volatile (
102 "mcr p15, 0, %0, c7, c0, 4 \n" /* Wait for interrupt */
103#if CONFIG_CPU == IMX31L
104 "nop\n nop\n nop\n nop\n nop\n" /* Clean out the pipes */
105#endif
106 : : "r"(0)
107 );
108 enable_irq();
109}
110#else
111/* Skip this if special code is required and implemented */
112#if !(defined(CPU_PP)) && CONFIG_CPU != RK27XX && CONFIG_CPU != IMX233
113static inline void core_sleep(void)
114{
115 /* TODO: core_sleep not implemented, battery life will be decreased */
116 enable_irq();
117}
118#endif /* CPU_PP */
119#endif
120
121
diff --git a/firmware/target/coldfire/system-target.h b/firmware/target/coldfire/system-target.h
index 74767c4583..5c810eb9b1 100644
--- a/firmware/target/coldfire/system-target.h
+++ b/firmware/target/coldfire/system-target.h
@@ -223,4 +223,14 @@ void commit_discard_idcache(void);
223static inline void commit_discard_dcache(void) {} 223static inline void commit_discard_dcache(void) {}
224static inline void commit_dcache(void) {} 224static inline void commit_dcache(void) {}
225 225
226/*---------------------------------------------------------------------------
227 * Put core in a power-saving state if waking list wasn't repopulated.
228 *---------------------------------------------------------------------------
229 */
230static inline void core_sleep(void)
231{
232 /* Supervisor mode, interrupts enabled upon wakeup */
233 asm volatile ("stop #0x2000");
234};
235
226#endif /* SYSTEM_TARGET_H */ 236#endif /* SYSTEM_TARGET_H */
diff --git a/firmware/target/coldfire/thread-coldfire.c b/firmware/target/coldfire/thread-coldfire.c
deleted file mode 100644
index e59a9390ba..0000000000
--- a/firmware/target/coldfire/thread-coldfire.c
+++ /dev/null
@@ -1,111 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 by Linus Nielsen Feltzing
11 *
12 * Coldfire processor threading support
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24/*---------------------------------------------------------------------------
25 * Start the thread running and terminate it if it returns
26 *---------------------------------------------------------------------------
27 */
28void start_thread(void); /* Provide C access to ASM label */
29static void USED_ATTR __start_thread(void)
30{
31 /* a0=macsr, a1=context */
32 asm volatile (
33 "start_thread: \n" /* Start here - no naked attribute */
34 "move.l %a0, %macsr \n" /* Set initial mac status reg */
35 "lea.l 48(%a1), %a1 \n"
36 "move.l (%a1)+, %sp \n" /* Set initial stack */
37 "move.l (%a1), %a2 \n" /* Fetch thread function pointer */
38 "clr.l (%a1) \n" /* Mark thread running */
39 "jsr (%a2) \n" /* Call thread function */
40 );
41 thread_exit();
42}
43
44/* Set EMAC unit to fractional mode with saturation for each new thread,
45 * since that's what'll be the most useful for most things which the dsp
46 * will do. Codecs should still initialize their preferred modes
47 * explicitly. Context pointer is placed in d2 slot and start_thread
48 * pointer in d3 slot. thread function pointer is placed in context.start.
49 * See load_context for what happens when thread is initially going to
50 * run.
51 */
52#define THREAD_STARTUP_INIT(core, thread, function) \
53 ({ (thread)->context.macsr = EMAC_FRACTIONAL | EMAC_SATURATE, \
54 (thread)->context.d[0] = (uint32_t)&(thread)->context, \
55 (thread)->context.d[1] = (uint32_t)start_thread, \
56 (thread)->context.start = (uint32_t)(function); })
57
58/*---------------------------------------------------------------------------
59 * Store non-volatile context.
60 *---------------------------------------------------------------------------
61 */
62static inline void store_context(void* addr)
63{
64 asm volatile (
65 "move.l %%macsr,%%d0 \n"
66 "movem.l %%d0/%%d2-%%d7/%%a2-%%a7,(%0) \n"
67 : : "a" (addr) : "d0" /* only! */
68 );
69}
70
71/*---------------------------------------------------------------------------
72 * Load non-volatile context.
73 *---------------------------------------------------------------------------
74 */
75static inline void load_context(const void* addr)
76{
77 asm volatile (
78 "move.l 52(%0), %%d0 \n" /* Get start address */
79 "beq.b 1f \n" /* NULL -> already running */
80 "movem.l (%0), %%a0-%%a2 \n" /* a0=macsr, a1=context, a2=start_thread */
81 "jmp (%%a2) \n" /* Start the thread */
82 "1: \n"
83 "movem.l (%0), %%d0/%%d2-%%d7/%%a2-%%a7 \n" /* Load context */
84 "move.l %%d0, %%macsr \n"
85 : : "a" (addr) : "d0" /* only! */
86 );
87}
88
89/*---------------------------------------------------------------------------
90 * Put core in a power-saving state if waking list wasn't repopulated.
91 *---------------------------------------------------------------------------
92 */
93static inline void core_sleep(void)
94{
95 /* Supervisor mode, interrupts enabled upon wakeup */
96 asm volatile ("stop #0x2000");
97};
98
99/*---------------------------------------------------------------------------
100 * Call this from asm to make sure the sp is pointing to the
101 * correct place before the context is saved.
102 *---------------------------------------------------------------------------
103 */
104static inline void _profile_thread_stopped(int current_thread)
105{
106 asm volatile ("move.l %[id], -(%%sp)\n\t"
107 "jsr profile_thread_stopped\n\t"
108 "addq.l #4, %%sp\n\t"
109 :: [id] "r" (current_thread)
110 : "cc", "memory");
111}
diff --git a/firmware/target/hosted/android/system-target.h b/firmware/target/hosted/android/system-target.h
index aba7e6d6c0..fd81b6661e 100644
--- a/firmware/target/hosted/android/system-target.h
+++ b/firmware/target/hosted/android/system-target.h
@@ -23,10 +23,7 @@
23#define __SYSTEM_TARGET_H__ 23#define __SYSTEM_TARGET_H__
24 24
25#include "kernel-unix.h" 25#include "kernel-unix.h"
26 26#include "system-hosted.h"
27static inline void commit_dcache(void) {}
28static inline void commit_discard_dcache(void) {}
29static inline void commit_discard_idcache(void) {}
30 27
31 /* don't pull in jni.h for every user of this file, it should be only needed 28 /* don't pull in jni.h for every user of this file, it should be only needed
32 * within the target tree (if at all) 29 * within the target tree (if at all)
diff --git a/firmware/target/hosted/sdl/system-sdl.h b/firmware/target/hosted/sdl/system-sdl.h
index d607e5e0a6..a20cbe5fac 100644
--- a/firmware/target/hosted/sdl/system-sdl.h
+++ b/firmware/target/hosted/sdl/system-sdl.h
@@ -41,6 +41,8 @@ int set_irq_level(int level);
41#define restore_irq(level) \ 41#define restore_irq(level) \
42 ((void)set_irq_level(level)) 42 ((void)set_irq_level(level))
43 43
44#include "system-hosted.h"
45
44void sim_enter_irq_handler(void); 46void sim_enter_irq_handler(void);
45void sim_exit_irq_handler(void); 47void sim_exit_irq_handler(void);
46void sim_kernel_shutdown(void); 48void sim_kernel_shutdown(void);
@@ -48,17 +50,10 @@ void sys_poweroff(void);
48void sys_handle_argv(int argc, char *argv[]); 50void sys_handle_argv(int argc, char *argv[]);
49void gui_message_loop(void); 51void gui_message_loop(void);
50void sim_do_exit(void) NORETURN_ATTR; 52void sim_do_exit(void) NORETURN_ATTR;
51#ifndef HAVE_SDL_THREADS
52void wait_for_interrupt(void);
53#endif
54 53
55extern bool background; /* True if the background image is enabled */ 54extern bool background; /* True if the background image is enabled */
56extern bool showremote; 55extern bool showremote;
57extern int display_zoom; 56extern int display_zoom;
58extern long start_tick; 57extern long start_tick;
59 58
60static inline void commit_dcache(void) {}
61static inline void commit_discard_dcache(void) {}
62static inline void commit_discard_idcache(void) {}
63
64#endif /* _SYSTEM_SDL_H_ */ 59#endif /* _SYSTEM_SDL_H_ */
diff --git a/firmware/target/hosted/system-hosted.h b/firmware/target/hosted/system-hosted.h
new file mode 100644
index 0000000000..e60803fde0
--- /dev/null
+++ b/firmware/target/hosted/system-hosted.h
@@ -0,0 +1,37 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 by Thomas Martitz
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef __SYSTEM_HOSTED_H__
23#define __SYSTEM_HOSTED_H__
24
25#include "system.h"
26
27static inline void commit_dcache(void) {}
28static inline void commit_discard_dcache(void) {}
29static inline void commit_discard_idcache(void) {}
30
31static inline void core_sleep(void)
32{
33 enable_irq();
34 wait_for_interrupt();
35}
36
37#endif
diff --git a/firmware/target/hosted/thread-arm.c b/firmware/target/hosted/thread-arm.c
deleted file mode 100644
index 8815f063d7..0000000000
--- a/firmware/target/hosted/thread-arm.c
+++ /dev/null
@@ -1,99 +0,0 @@
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/*---------------------------------------------------------------------------
28 * Start the thread running and terminate it if it returns
29 *---------------------------------------------------------------------------
30 */
31static void __attribute__((naked)) USED_ATTR start_thread(void)
32{
33 /* r0 = context */
34 asm volatile (
35 "ldr sp, [r0, #32] \n" /* Load initial sp */
36 "ldr r4, [r0, #40] \n" /* start in r4 since it's non-volatile */
37 "mov r1, #0 \n" /* Mark thread as running */
38 "str r1, [r0, #40] \n"
39 "mov lr, pc \n" /* Call thread function */
40 "bx r4 \n"
41 ); /* No clobber list - new thread doesn't care */
42 thread_exit();
43}
44
45/* For startup, place context pointer in r4 slot, start_thread pointer in r5
46 * slot, and thread function pointer in context.start. See load_context for
47 * what happens when thread is initially going to run. */
48#define THREAD_STARTUP_INIT(core, thread, function) \
49 ({ (thread)->context.r[0] = (uint32_t)&(thread)->context, \
50 (thread)->context.r[1] = (uint32_t)start_thread, \
51 (thread)->context.start = (uint32_t)function; })
52
53
54/*---------------------------------------------------------------------------
55 * Store non-volatile context.
56 *---------------------------------------------------------------------------
57 */
58static inline void store_context(void* addr)
59{
60 asm volatile(
61 "stmia %0, { r4-r11, sp, lr } \n"
62 : : "r" (addr)
63 );
64}
65
66/*---------------------------------------------------------------------------
67 * Load non-volatile context.
68 *---------------------------------------------------------------------------
69 */
70static inline void load_context(const void* addr)
71{
72 asm volatile(
73 "ldr r0, [%0, #40] \n" /* Load start pointer */
74 "cmp r0, #0 \n" /* Check for NULL */
75
76 /* If not already running, jump to start */
77 "ldmneia %0, { r0, pc } \n"
78 "ldmia %0, { r4-r11, sp, lr } \n" /* Load regs r4 to r14 from context */
79 : : "r" (addr) : "r0" /* only! */
80 );
81}
82
83/*
84 * this core sleep suspends the OS thread rockbox runs under, which greatly
85 * reduces cpu usage (~100% to <10%)
86 *
87 * it returns when when the tick timer is called, other interrupt-like
88 * events occur
89 *
90 * wait_for_interrupt is implemented in kernel-<platform>.c
91 **/
92
93static inline void core_sleep(void)
94{
95 enable_irq();
96 wait_for_interrupt();
97}
98
99
diff --git a/firmware/target/hosted/thread-unix.c b/firmware/target/hosted/thread-unix.c
deleted file mode 100644
index 79310e0600..0000000000
--- a/firmware/target/hosted/thread-unix.c
+++ /dev/null
@@ -1,316 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Thomas Martitz
11 *
12 * Generic unix threading support
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24#include <stdlib.h>
25#include <stdbool.h>
26#include <signal.h>
27#include <stdio.h>
28#include <setjmp.h>
29#include <unistd.h>
30#include <pthread.h>
31#include <errno.h>
32#include "debug.h"
33
34static volatile bool sig_handler_called;
35static volatile jmp_buf tramp_buf;
36static volatile jmp_buf bootstrap_buf;
37static void (*thread_func)(void);
38static const int trampoline_sig = SIGUSR1;
39static pthread_t main_thread;
40
41static struct ctx {
42 jmp_buf thread_buf;
43} thread_bufs[MAXTHREADS];
44static struct ctx* thread_context, *target_context;
45static int curr_uc;
46
47static void trampoline(int sig);
48static void bootstrap_context(void) __attribute__((noinline));
49
50/* The *_context functions are heavily based on Gnu pth
51 * http://www.gnu.org/software/pth/
52 *
53 * adjusted to work in a multi-thread environment to
54 * offer a ucontext-like API
55 */
56
57/*
58 * VARIANT 2: THE SIGNAL STACK TRICK
59 *
60 * This uses sigstack/sigaltstack() and friends and is really the
61 * most tricky part of Pth. When you understand the following
62 * stuff you're a good Unix hacker and then you've already
63 * understood the gory ingredients of Pth. So, either welcome to
64 * the club of hackers, or do yourself a favor and skip this ;)
65 *
66 * The ingenious fact is that this variant runs really on _all_ POSIX
67 * compliant systems without special platform kludges. But be _VERY_
68 * carefully when you change something in the following code. The slightest
69 * change or reordering can lead to horribly broken code. Really every
70 * function call in the following case is intended to be how it is, doubt
71 * me...
72 *
73 * For more details we strongly recommend you to read the companion
74 * paper ``Portable Multithreading -- The Signal Stack Trick for
75 * User-Space Thread Creation'' from Ralf S. Engelschall. A copy of the
76 * draft of this paper you can find in the file rse-pmt.ps inside the
77 * GNU Pth distribution.
78 */
79
80static int make_context(struct ctx *ctx, void (*f)(void), char *sp, size_t stack_size)
81{
82 struct sigaction sa;
83 struct sigaction osa;
84 stack_t ss;
85 stack_t oss;
86 sigset_t osigs;
87 sigset_t sigs;
88
89 disable_irq();
90 /*
91 * Preserve the trampoline_sig signal state, block trampoline_sig,
92 * and establish our signal handler. The signal will
93 * later transfer control onto the signal stack.
94 */
95 sigemptyset(&sigs);
96 sigaddset(&sigs, trampoline_sig);
97 sigprocmask(SIG_BLOCK, &sigs, &osigs);
98 sa.sa_handler = trampoline;
99 sigemptyset(&sa.sa_mask);
100 sa.sa_flags = SA_ONSTACK;
101 if (sigaction(trampoline_sig, &sa, &osa) != 0)
102 {
103 DEBUGF("%s(): %s\n", __func__, strerror(errno));
104 return false;
105 }
106 /*
107 * Set the new stack.
108 *
109 * For sigaltstack we're lucky [from sigaltstack(2) on
110 * FreeBSD 3.1]: ``Signal stacks are automatically adjusted
111 * for the direction of stack growth and alignment
112 * requirements''
113 *
114 * For sigstack we have to decide ourself [from sigstack(2)
115 * on Solaris 2.6]: ``The direction of stack growth is not
116 * indicated in the historical definition of struct sigstack.
117 * The only way to portably establish a stack pointer is for
118 * the application to determine stack growth direction.''
119 */
120 ss.ss_sp = sp;
121 ss.ss_size = stack_size;
122 ss.ss_flags = 0;
123 if (sigaltstack(&ss, &oss) < 0)
124 {
125 DEBUGF("%s(): %s\n", __func__, strerror(errno));
126 return false;
127 }
128
129 /*
130 * Now transfer control onto the signal stack and set it up.
131 * It will return immediately via "return" after the setjmp()
132 * was performed. Be careful here with race conditions. The
133 * signal can be delivered the first time sigsuspend() is
134 * called.
135 */
136 sig_handler_called = false;
137 main_thread = pthread_self();
138 sigfillset(&sigs);
139 sigdelset(&sigs, trampoline_sig);
140 pthread_kill(main_thread, trampoline_sig);
141 while(!sig_handler_called)
142 sigsuspend(&sigs);
143
144 /*
145 * Inform the system that we are back off the signal stack by
146 * removing the alternative signal stack. Be careful here: It
147 * first has to be disabled, before it can be removed.
148 */
149 sigaltstack(NULL, &ss);
150 ss.ss_flags = SS_DISABLE;
151 if (sigaltstack(&ss, NULL) < 0)
152 {
153 DEBUGF("%s(): %s\n", __func__, strerror(errno));
154 return false;
155 }
156 sigaltstack(NULL, &ss);
157 if (!(ss.ss_flags & SS_DISABLE))
158 {
159 DEBUGF("%s(): %s\n", __func__, strerror(errno));
160 return false;
161 }
162 if (!(oss.ss_flags & SS_DISABLE))
163 sigaltstack(&oss, NULL);
164
165 /*
166 * Restore the old trampoline_sig signal handler and mask
167 */
168 sigaction(trampoline_sig, &osa, NULL);
169 sigprocmask(SIG_SETMASK, &osigs, NULL);
170
171 /*
172 * Tell the trampoline and bootstrap function where to dump
173 * the new machine context, and what to do afterwards...
174 */
175 thread_func = f;
176 thread_context = ctx;
177
178 /*
179 * Now enter the trampoline again, but this time not as a signal
180 * handler. Instead we jump into it directly. The functionally
181 * redundant ping-pong pointer arithmentic is neccessary to avoid
182 * type-conversion warnings related to the `volatile' qualifier and
183 * the fact that `jmp_buf' usually is an array type.
184 */
185 if (setjmp(*((jmp_buf *)&bootstrap_buf)) == 0)
186 longjmp(*((jmp_buf *)&tramp_buf), 1);
187
188 /*
189 * Ok, we returned again, so now we're finished
190 */
191 enable_irq();
192 return true;
193}
194
195static void trampoline(int sig)
196{
197 (void)sig;
198 /* sanity check, no other thread should be here */
199 if (pthread_self() != main_thread)
200 return;
201
202 if (setjmp(*((jmp_buf *)&tramp_buf)) == 0)
203 {
204 sig_handler_called = true;
205 return;
206 }
207 /* longjump'd back in */
208 bootstrap_context();
209}
210
211void bootstrap_context(void)
212{
213 /* copy to local storage so we can spawn further threads
214 * in the meantime */
215 void (*thread_entry)(void) = thread_func;
216 struct ctx *t = thread_context;
217
218 /*
219 * Save current machine state (on new stack) and
220 * go back to caller until we're scheduled for real...
221 */
222 if (setjmp(t->thread_buf) == 0)
223 longjmp(*((jmp_buf *)&bootstrap_buf), 1);
224
225 /*
226 * The new thread is now running: GREAT!
227 * Now we just invoke its init function....
228 */
229 thread_entry();
230 DEBUGF("thread left\n");
231 thread_exit();
232}
233
234static inline void set_context(struct ctx *c)
235{
236 longjmp(c->thread_buf, 1);
237}
238
239static inline void swap_context(struct ctx *old, struct ctx *new)
240{
241 if (setjmp(old->thread_buf) == 0)
242 longjmp(new->thread_buf, 1);
243}
244
245static inline void get_context(struct ctx *c)
246{
247 setjmp(c->thread_buf);
248}
249
250
251static void setup_thread(struct regs *context);
252
253#define INIT_MAIN_THREAD
254static void init_main_thread(void *addr)
255{
256 /* get a context for the main thread so that we can jump to it from
257 * other threads */
258 struct regs *context = (struct regs*)addr;
259 context->uc = &thread_bufs[curr_uc++];
260 get_context(context->uc);
261}
262
263#define THREAD_STARTUP_INIT(core, thread, function) \
264 ({ (thread)->context.stack_size = (thread)->stack_size, \
265 (thread)->context.stack = (uintptr_t)(thread)->stack; \
266 (thread)->context.start = function; })
267
268
269
270/*
271 * Prepare context to make the thread runnable by calling swapcontext on it
272 */
273static void setup_thread(struct regs *context)
274{
275 void (*fn)(void) = context->start;
276 context->uc = &thread_bufs[curr_uc++];
277 while (!make_context(context->uc, fn, (char*)context->stack, context->stack_size))
278 DEBUGF("Thread creation failed. Retrying");
279}
280
281
282/*
283 * Save the ucontext_t pointer for later use in swapcontext()
284 *
285 * Cannot do getcontext() here, because jumping back to the context
286 * resumes after the getcontext call (i.e. store_context), but we need
287 * to resume from load_context()
288 */
289static inline void store_context(void* addr)
290{
291 struct regs *r = (struct regs*)addr;
292 target_context = r->uc;
293}
294
295/*
296 * Perform context switch
297 */
298static inline void load_context(const void* addr)
299{
300 struct regs *r = (struct regs*)addr;
301 if (UNLIKELY(r->start))
302 {
303 setup_thread(r);
304 r->start = NULL;
305 }
306 swap_context(target_context, r->uc);
307}
308
309/*
310 * play nice with the host and sleep while waiting for the tick */
311extern void wait_for_interrupt(void);
312static inline void core_sleep(void)
313{
314 enable_irq();
315 wait_for_interrupt();
316}
diff --git a/firmware/target/hosted/thread-win32.c b/firmware/target/hosted/thread-win32.c
deleted file mode 100644
index a60198494a..0000000000
--- a/firmware/target/hosted/thread-win32.c
+++ /dev/null
@@ -1,85 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 by Thomas Martitz
11 *
12 * Generic ARM threading support
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24
25#include <windows.h>
26#include "system.h"
27
28#define INIT_MAIN_THREAD
29
30#define THREAD_STARTUP_INIT(core, thread, function) \
31 ({ (thread)->context.stack_size = (thread)->stack_size, \
32 (thread)->context.stack = (uintptr_t)(thread)->stack; \
33 (thread)->context.start = function; })
34
35static void init_main_thread(void *addr)
36{
37 struct regs *context = (struct regs*)addr;
38 /* we must convert the current main thread to a fiber to be able to
39 * schedule other fibers */
40 context->uc = ConvertThreadToFiber(NULL);
41 context->stack_size = 0;
42}
43
44static inline void store_context(void* addr)
45{
46 (void)addr;
47 /* nothing to do here, Fibers continue after the SwitchToFiber call */
48}
49
50static void start_thread(void)
51{
52 void (*func)(void) = GetFiberData();
53 func();
54 /* go out if thread function returns */
55 thread_exit();
56}
57
58/*
59 * Load context and run it
60 *
61 * Resume execution from the last load_context call for the thread
62 */
63
64static inline void load_context(const void* addr)
65{
66 struct regs *context = (struct regs*)addr;
67 if (UNLIKELY(context->start))
68 { /* need setup before switching to it */
69 context->uc = CreateFiber(context->stack_size,
70 (LPFIBER_START_ROUTINE)start_thread, context->start);
71 /* can't assign stack pointer, only stack size */
72 context->stack_size = 0;
73 context->start = NULL;
74 }
75 SwitchToFiber(context->uc);
76}
77
78/*
79 * play nice with the host and sleep while waiting for the tick */
80static inline void core_sleep(void)
81{
82 enable_irq();
83 wait_for_interrupt();
84}
85
diff --git a/firmware/target/hosted/ypr0/system-target.h b/firmware/target/hosted/ypr0/system-target.h
index efd235282e..1ef8b9aeda 100644
--- a/firmware/target/hosted/ypr0/system-target.h
+++ b/firmware/target/hosted/ypr0/system-target.h
@@ -22,10 +22,7 @@
22#define __SYSTEM_TARGET_H__ 22#define __SYSTEM_TARGET_H__
23 23
24#include "kernel-unix.h" 24#include "kernel-unix.h"
25 25#include "system-hosted.h"
26static inline void commit_dcache(void) {}
27static inline void commit_discard_dcache(void) {}
28static inline void commit_discard_idcache(void) {}
29 26
30#define NEED_GENERIC_BYTESWAPS 27#define NEED_GENERIC_BYTESWAPS
31#endif /* __SYSTEM_TARGET_H__ */ 28#endif /* __SYSTEM_TARGET_H__ */
diff --git a/firmware/target/mips/ingenic_jz47xx/system-target.h b/firmware/target/mips/ingenic_jz47xx/system-target.h
index caf1733158..1c2e7d7173 100644
--- a/firmware/target/mips/ingenic_jz47xx/system-target.h
+++ b/firmware/target/mips/ingenic_jz47xx/system-target.h
@@ -97,4 +97,28 @@ void dma_disable(void);
97#define DMA_IRQ(n) (IRQ_DMA_0 + (n)) 97#define DMA_IRQ(n) (IRQ_DMA_0 + (n))
98#define GPIO_IRQ(n) (IRQ_GPIO_0 + (n)) 98#define GPIO_IRQ(n) (IRQ_GPIO_0 + (n))
99 99
100/*---------------------------------------------------------------------------
101 * Put core in a power-saving state.
102 *---------------------------------------------------------------------------
103 */
104static inline void core_sleep(void)
105{
106#if CONFIG_CPU == JZ4732
107 __cpm_idle_mode();
108#endif
109 asm volatile(".set mips32r2 \n"
110 "mfc0 $8, $12 \n" /* mfc t0, $12 */
111 "move $9, $8 \n" /* move t1, t0 */
112 "la $10, 0x8000000 \n" /* la t2, 0x8000000 */
113 "or $8, $8, $10 \n" /* Enable reduced power mode */
114 "mtc0 $8, $12 \n" /* mtc t0, $12 */
115 "wait \n"
116 "mtc0 $9, $12 \n" /* mtc t1, $12 */
117 ".set mips0 \n"
118 ::: "t0", "t1", "t2"
119 );
120 enable_irq();
121}
122
123
100#endif /* __SYSTEM_TARGET_H_ */ 124#endif /* __SYSTEM_TARGET_H_ */
diff --git a/firmware/target/mips/thread-mips32.c b/firmware/target/mips/thread-mips32.c
deleted file mode 100644
index ba90c8965b..0000000000
--- a/firmware/target/mips/thread-mips32.c
+++ /dev/null
@@ -1,133 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 by Maurus Cuelenaere
11 *
12 * 32-bit MIPS threading support
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24/*---------------------------------------------------------------------------
25 * Start the thread running and terminate it if it returns
26 *---------------------------------------------------------------------------
27 */
28
29void start_thread(void); /* Provide C access to ASM label */
30static void USED_ATTR _start_thread(void)
31{
32 /* t1 = context */
33 asm volatile (
34 "start_thread: \n"
35 ".set noreorder \n"
36 ".set noat \n"
37 "lw $8, 4($9) \n" /* Fetch thread function pointer ($8 = t0, $9 = t1) */
38 "lw $29, 36($9) \n" /* Set initial sp(=$29) */
39 "jalr $8 \n" /* Start the thread */
40 "sw $0, 44($9) \n" /* Clear start address */
41 ".set at \n"
42 ".set reorder \n"
43 );
44 thread_exit();
45}
46
47/* Place context pointer in s0 slot, function pointer in s1 slot, and
48 * start_thread pointer in context_start */
49#define THREAD_STARTUP_INIT(core, thread, function) \
50 ({ (thread)->context.r[0] = (uint32_t)&(thread)->context, \
51 (thread)->context.r[1] = (uint32_t)(function), \
52 (thread)->context.start = (uint32_t)start_thread; })
53
54/*---------------------------------------------------------------------------
55 * Store non-volatile context.
56 *---------------------------------------------------------------------------
57 */
58static inline void store_context(void* addr)
59{
60 asm volatile (
61 ".set noreorder \n"
62 ".set noat \n"
63 "sw $16, 0(%0) \n" /* s0 */
64 "sw $17, 4(%0) \n" /* s1 */
65 "sw $18, 8(%0) \n" /* s2 */
66 "sw $19, 12(%0) \n" /* s3 */
67 "sw $20, 16(%0) \n" /* s4 */
68 "sw $21, 20(%0) \n" /* s5 */
69 "sw $22, 24(%0) \n" /* s6 */
70 "sw $23, 28(%0) \n" /* s7 */
71 "sw $30, 32(%0) \n" /* fp */
72 "sw $29, 36(%0) \n" /* sp */
73 "sw $31, 40(%0) \n" /* ra */
74 ".set at \n"
75 ".set reorder \n"
76 : : "r" (addr)
77 );
78}
79
80/*---------------------------------------------------------------------------
81 * Load non-volatile context.
82 *---------------------------------------------------------------------------
83 */
84static inline void load_context(const void* addr)
85{
86 asm volatile (
87 ".set noat \n"
88 ".set noreorder \n"
89 "lw $8, 44(%0) \n" /* Get start address ($8 = t0) */
90 "beqz $8, running \n" /* NULL -> already running */
91 "nop \n"
92 "jr $8 \n"
93 "move $9, %0 \n" /* t1 = context */
94 "running: \n"
95 "lw $16, 0(%0) \n" /* s0 */
96 "lw $17, 4(%0) \n" /* s1 */
97 "lw $18, 8(%0) \n" /* s2 */
98 "lw $19, 12(%0) \n" /* s3 */
99 "lw $20, 16(%0) \n" /* s4 */
100 "lw $21, 20(%0) \n" /* s5 */
101 "lw $22, 24(%0) \n" /* s6 */
102 "lw $23, 28(%0) \n" /* s7 */
103 "lw $30, 32(%0) \n" /* fp */
104 "lw $29, 36(%0) \n" /* sp */
105 "lw $31, 40(%0) \n" /* ra */
106 ".set at \n"
107 ".set reorder \n"
108 : : "r" (addr) : "t0", "t1"
109 );
110}
111
112/*---------------------------------------------------------------------------
113 * Put core in a power-saving state.
114 *---------------------------------------------------------------------------
115 */
116static inline void core_sleep(void)
117{
118#if CONFIG_CPU == JZ4732
119 __cpm_idle_mode();
120#endif
121 asm volatile(".set mips32r2 \n"
122 "mfc0 $8, $12 \n" /* mfc t0, $12 */
123 "move $9, $8 \n" /* move t1, t0 */
124 "la $10, 0x8000000 \n" /* la t2, 0x8000000 */
125 "or $8, $8, $10 \n" /* Enable reduced power mode */
126 "mtc0 $8, $12 \n" /* mtc t0, $12 */
127 "wait \n"
128 "mtc0 $9, $12 \n" /* mtc t1, $12 */
129 ".set mips0 \n"
130 ::: "t0", "t1", "t2"
131 );
132 enable_irq();
133}
diff --git a/firmware/target/sh/system-target.h b/firmware/target/sh/system-target.h
index 5db9cc071f..a62a024823 100644
--- a/firmware/target/sh/system-target.h
+++ b/firmware/target/sh/system-target.h
@@ -137,4 +137,18 @@ static inline void commit_dcache(void) {}
137static inline void commit_discard_dcache(void) {} 137static inline void commit_discard_dcache(void) {}
138static inline void commit_discard_idcache(void) {} 138static inline void commit_discard_idcache(void) {}
139 139
140/*---------------------------------------------------------------------------
141 * Put core in a power-saving state.
142 *---------------------------------------------------------------------------
143 */
144static inline void core_sleep(void)
145{
146 asm volatile (
147 "and.b #0x7f, @(r0, gbr) \n" /* Clear SBY (bit 7) in SBYCR */
148 "mov #0, r1 \n" /* Enable interrupts */
149 "ldc r1, sr \n" /* Following instruction cannot be interrupted */
150 "sleep \n" /* Execute standby */
151 : : "z"(&SBYCR-GBR) : "r1");
152}
153
140#endif /* SYSTEM_TARGET_H */ 154#endif /* SYSTEM_TARGET_H */
diff --git a/firmware/target/sh/thread-sh.c b/firmware/target/sh/thread-sh.c
deleted file mode 100644
index 0f844f204b..0000000000
--- a/firmware/target/sh/thread-sh.c
+++ /dev/null
@@ -1,109 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Ulf Ralberg
11 *
12 * SH processor threading support
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 ****************************************************************************/
23
24/*---------------------------------------------------------------------------
25 * Start the thread running and terminate it if it returns
26 *---------------------------------------------------------------------------
27 */
28void start_thread(void); /* Provide C access to ASM label */
29static void USED_ATTR __start_thread(void)
30{
31 /* r8 = context */
32 asm volatile (
33 "_start_thread: \n" /* Start here - no naked attribute */
34 "mov.l @(4, r8), r0 \n" /* Fetch thread function pointer */
35 "mov.l @(28, r8), r15 \n" /* Set initial sp */
36 "mov #0, r1 \n" /* Start the thread */
37 "jsr @r0 \n"
38 "mov.l r1, @(36, r8) \n" /* Clear start address */
39 );
40 thread_exit();
41}
42
43/* Place context pointer in r8 slot, function pointer in r9 slot, and
44 * start_thread pointer in context_start */
45#define THREAD_STARTUP_INIT(core, thread, function) \
46 ({ (thread)->context.r[0] = (uint32_t)&(thread)->context, \
47 (thread)->context.r[1] = (uint32_t)(function), \
48 (thread)->context.start = (uint32_t)start_thread; })
49
50/*---------------------------------------------------------------------------
51 * Store non-volatile context.
52 *---------------------------------------------------------------------------
53 */
54static inline void store_context(void* addr)
55{
56 asm volatile (
57 "add #36, %0 \n" /* Start at last reg. By the time routine */
58 "sts.l pr, @-%0 \n" /* is done, %0 will have the original value */
59 "mov.l r15,@-%0 \n"
60 "mov.l r14,@-%0 \n"
61 "mov.l r13,@-%0 \n"
62 "mov.l r12,@-%0 \n"
63 "mov.l r11,@-%0 \n"
64 "mov.l r10,@-%0 \n"
65 "mov.l r9, @-%0 \n"
66 "mov.l r8, @-%0 \n"
67 : : "r" (addr)
68 );
69}
70
71/*---------------------------------------------------------------------------
72 * Load non-volatile context.
73 *---------------------------------------------------------------------------
74 */
75static inline void load_context(const void* addr)
76{
77 asm volatile (
78 "mov.l @(36, %0), r0 \n" /* Get start address */
79 "tst r0, r0 \n"
80 "bt .running \n" /* NULL -> already running */
81 "jmp @r0 \n" /* r8 = context */
82 ".running: \n"
83 "mov.l @%0+, r8 \n" /* Executes in delay slot and outside it */
84 "mov.l @%0+, r9 \n"
85 "mov.l @%0+, r10 \n"
86 "mov.l @%0+, r11 \n"
87 "mov.l @%0+, r12 \n"
88 "mov.l @%0+, r13 \n"
89 "mov.l @%0+, r14 \n"
90 "mov.l @%0+, r15 \n"
91 "lds.l @%0+, pr \n"
92 : : "r" (addr) : "r0" /* only! */
93 );
94}
95
96/*---------------------------------------------------------------------------
97 * Put core in a power-saving state.
98 *---------------------------------------------------------------------------
99 */
100static inline void core_sleep(void)
101{
102 asm volatile (
103 "and.b #0x7f, @(r0, gbr) \n" /* Clear SBY (bit 7) in SBYCR */
104 "mov #0, r1 \n" /* Enable interrupts */
105 "ldc r1, sr \n" /* Following instruction cannot be interrupted */
106 "sleep \n" /* Execute standby */
107 : : "z"(&SBYCR-GBR) : "r1");
108}
109