diff --git a/firmware/asm/arm/thread.c b/firmware/asm/arm/thread-classic.c similarity index 88% rename from firmware/asm/arm/thread.c rename to firmware/asm/arm/thread-classic.c index 1ef836b128..d2014fc951 100644 --- a/firmware/asm/arm/thread.c +++ b/firmware/asm/arm/thread-classic.c @@ -29,11 +29,7 @@ static void __attribute__((naked)) USED_ATTR start_thread(void) { /* r0 = context */ asm volatile ( -#if defined(CPU_ARM_MICRO) && ARCH_VERSION >= 7 - "ldr sp, [r0, #36] \n" /* Load initial sp */ -#else "ldr sp, [r0, #32] \n" /* Load initial sp */ -#endif "ldr r4, [r0, #40] \n" /* start in r4 since it's non-volatile */ "mov r1, #0 \n" /* Mark thread as running */ "str r1, [r0, #40] \n" @@ -65,12 +61,7 @@ static void __attribute__((naked)) USED_ATTR start_thread(void) static inline void store_context(void* addr) { asm volatile( -#if defined(CPU_ARM_MICRO) && ARCH_VERSION >= 7 - "stmia %0, { r4-r11, lr } \n" - "str sp, [%0, #36] \n" -#else "stmia %0, { r4-r11, sp, lr } \n" -#endif : : "r" (addr) ); } @@ -94,16 +85,8 @@ static inline void load_context(const void* addr) "ldmiane %0, { r0, pc } \n" #endif -#if defined(CPU_ARM_MICRO) && ARCH_VERSION >= 7 - "mov r0, %0 \n" - "ldmia r0, { r4-r11, lr } \n" - "ldr sp, [r0, #36] \n" -#else "ldmia %0, { r4-r11, sp, lr } \n" /* Load regs r4 to r14 from context */ -#endif END_ARM_ASM_SYNTAX_UNIFIED : : "r" (addr) : "r0" /* only! */ ); } - - diff --git a/firmware/asm/arm/thread.h b/firmware/asm/arm/thread-classic.h similarity index 75% rename from firmware/asm/arm/thread.h rename to firmware/asm/arm/thread-classic.h index 1cfc3741da..533a088979 100644 --- a/firmware/asm/arm/thread.h +++ b/firmware/asm/arm/thread-classic.h @@ -21,20 +21,6 @@ #include "config.h" -#if defined(CPU_ARM_MICRO) && ARCH_VERSION >= 7 -/* - * Cortex-M cannot load/store SP with ldm/stm so we need to store it - * separately. This makes it slightly more efficient to store SP last - * so as not to split the register list. - */ -struct regs -{ - uint32_t r[8]; /* 0-28 - Registers r4-r11 */ - uint32_t lr; /* 32 - r14 (lr) */ - uint32_t sp; /* 36 - Stack pointer (r13) */ - uint32_t start; /* 40 - Thread start address, or NULL when started */ -}; -#else struct regs { uint32_t r[8]; /* 0-28 - Registers r4-r11 */ @@ -42,7 +28,6 @@ struct regs uint32_t lr; /* 36 - r14 (lr) */ uint32_t start; /* 40 - Thread start address, or NULL when started */ }; -#endif #if (CONFIG_PLATFORM & PLATFORM_HOSTED) #include diff --git a/firmware/asm/arm/thread-micro.c b/firmware/asm/arm/thread-micro.c new file mode 100644 index 0000000000..9ad329b55d --- /dev/null +++ b/firmware/asm/arm/thread-micro.c @@ -0,0 +1,88 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Thom Johansen + * Copyright (C) 2026 by Aidan MacDonald + * + * Threading support for ARM Cortex-M targets + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/*--------------------------------------------------------------------------- + * Start the thread running and terminate it if it returns + *--------------------------------------------------------------------------- + */ +static void __attribute__((naked)) USED_ATTR start_thread(void) +{ + /* r0 = context */ + asm volatile ( + "ldr sp, [r0, #36] \n" /* Load initial sp */ + "ldr r4, [r0, #40] \n" /* start in r4 since it's non-volatile */ + "mov r1, #0 \n" /* Mark thread as running */ + "str r1, [r0, #40] \n" + "mov lr, pc \n" /* Call thread function */ + "bx r4 \n" + ); /* No clobber list - new thread doesn't care */ + thread_exit(); +} + +/* For startup, place context pointer in r4 slot, start_thread pointer in r5 + * slot, and thread function pointer in context.start. See load_context for + * what happens when thread is initially going to run. */ +#define THREAD_STARTUP_INIT(core, thread, function) \ + ({ (thread)->context.r[0] = (uint32_t)&(thread)->context, \ + (thread)->context.r[1] = (uint32_t)start_thread, \ + (thread)->context.start = (uint32_t)function; }) + + +/*--------------------------------------------------------------------------- + * Store non-volatile context. + *--------------------------------------------------------------------------- + */ +static inline void store_context(void* addr) +{ + asm volatile( + "stmia %0, { r4-r11, lr } \n" + "str sp, [%0, #36] \n" + : : "r" (addr) + ); +} + +/*--------------------------------------------------------------------------- + * Load non-volatile context. + *--------------------------------------------------------------------------- + */ +static inline void load_context(const void* addr) +{ + asm volatile( + BEGIN_ARM_ASM_SYNTAX_UNIFIED + + "ldr r0, [%0, #40] \n" /* Load start pointer */ + "cmp r0, #0 \n" /* Check for NULL */ + + /* If not already running, jump to start */ + "ldmiane %0, { r0, pc } \n" + + /* Load regs r4 to r14 from context */ + "mov r0, %0 \n" + "ldmia r0, { r4-r11, lr } \n" + "ldr sp, [r0, #36] \n" + + END_ARM_ASM_SYNTAX_UNIFIED + : : "r" (addr) : "r0" /* only! */ + ); +} diff --git a/firmware/asm/arm/thread-micro.h b/firmware/asm/arm/thread-micro.h new file mode 100644 index 0000000000..67c5b4de80 --- /dev/null +++ b/firmware/asm/arm/thread-micro.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Ulf Ralberg + * Copyright (C) 2026 by Aidan MacDonald + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" + +/* + * Cortex-M cannot load/store SP with ldm/stm so we need to store it + * separately. This makes it slightly more efficient to store SP last + * so as not to split the register list. + */ +struct regs +{ + uint32_t r[8]; /* 0-28 - Registers r4-r11 */ + uint32_t lr; /* 32 - r14 (lr) */ + uint32_t sp; /* 36 - Stack pointer (r13) */ + uint32_t start; /* 40 - Thread start address, or NULL when started */ +}; + +#if (CONFIG_PLATFORM & PLATFORM_HOSTED) +# include +#else +# define DEFAULT_STACK_SIZE 0x400 /* Bytes */ +#endif diff --git a/firmware/asm/thread.c b/firmware/asm/thread.c index c7779b3054..e639cadc73 100644 --- a/firmware/asm/thread.c +++ b/firmware/asm/thread.c @@ -5,8 +5,10 @@ #include "thread-unix.c" /* Now the CPU-specific implementations */ -#elif defined(CPU_ARM) - #include "arm/thread.c" +#elif defined(CPU_ARM_CLASSIC) || defined(CPU_ARM_APPLICATION) + #include "arm/thread-classic.c" +#elif defined(CPU_ARM_MICRO) + #include "arm/thread-micro.c" #elif defined(CPU_COLDFIRE) #include "m68k/thread.c" #elif defined(CPU_MIPS) diff --git a/firmware/asm/thread.h b/firmware/asm/thread.h index 831de9ae8d..6301b0cb05 100644 --- a/firmware/asm/thread.h +++ b/firmware/asm/thread.h @@ -59,8 +59,10 @@ struct regs #elif defined(HAVE_WIN32_FIBER_THREADS) #define DEFAULT_STACK_SIZE 0x1000 /* Bytes */ #endif -#elif defined(CPU_ARM) - #include "arm/thread.h" +#elif defined(CPU_ARM_CLASSIC) || defined(CPU_ARM_APPLICATION) + #include "arm/thread-classic.h" +#elif defined(CPU_ARM_MICRO) + #include "arm/thread-micro.h" #elif defined(CPU_COLDFIRE) #include "m68k/thread.h" #elif defined(CPU_MIPS)