aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/arm-m/thread.c74
-rw-r--r--platform/stellaris/rules.mk4
2 files changed, 55 insertions, 23 deletions
diff --git a/arch/arm/arm-m/thread.c b/arch/arm/arm-m/thread.c
index 3aa1a748..247076ca 100644
--- a/arch/arm/arm-m/thread.c
+++ b/arch/arm/arm-m/thread.c
@@ -211,7 +211,7 @@ __NAKED static void _half_save_and_svc(struct thread *oldthread, struct thread *
__asm__ volatile(
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
/* see if we need to save fpu context */
- "cmp r2, #1;"
+ "tst r2, #1;"
"beq 0f;"
/* save part of the fpu context on the stack */
@@ -235,7 +235,7 @@ __NAKED static void _half_save_and_svc(struct thread *oldthread, struct thread *
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
/* see if we need to restore fpu context */
- "cmp r3, #1;"
+ "tst r3, #1;"
"beq 0f;"
/* restore the top part of the fpu context */
@@ -247,8 +247,16 @@ __NAKED static void _half_save_and_svc(struct thread *oldthread, struct thread *
"vldm r3!, { s0-s15 };"
"ldr r3, [r3];"
"vmsr fpscr, r3;"
+ "b 1f;"
+ /* disable fpu context if we're not restoring anything */
"0:"
+ "mrs r3, CONTROL;"
+ "bic r3, #(1<<2);" /* unset FPCA */
+ "msr CONTROL, r3;"
+ "isb;"
+
+ "1:"
#endif
CLREX
@@ -276,7 +284,7 @@ __NAKED static void _arch_non_preempt_context_switch(struct thread *oldthread, s
__asm__ volatile(
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
/* see if we need to save fpu context */
- "cmp r2, #1;"
+ "tst r2, #1;"
"beq 0f;"
/* save part of the fpu context on the stack */
@@ -296,12 +304,12 @@ __NAKED static void _arch_non_preempt_context_switch(struct thread *oldthread, s
SAVE_SP(r0, r2, %[sp_off])
/* restore new context */
- LOAD_SP(r0, r2, %[sp_off])
+ LOAD_SP(r1, r2, %[sp_off])
RESTORE_REGS
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
/* see if we need to restore fpu context */
- "cmp r3, #1;"
+ "tst r3, #1;"
"beq 0f;"
/* restore fpu context */
@@ -311,8 +319,16 @@ __NAKED static void _arch_non_preempt_context_switch(struct thread *oldthread, s
"vpop { s0-s15 };"
"pop { r3 };"
"vmsr fpscr, r3;"
+ "b 1f;"
+ /* disable fpu context if we're not restoring anything */
"0:"
+ "mrs r3, CONTROL;"
+ "bic r3, #(1<<2);" /* unset FPCA */
+ "msr CONTROL, r3;"
+ "isb;"
+
+ "1:"
#endif
CLREX
@@ -339,9 +355,19 @@ __NAKED static void _thread_mode_bounce(bool fpused)
"vpop { s0-s15 };"
"pop { r0 };"
"vmsr fpscr, r0;"
+ "b 1f;"
+
+ /* disable fpu context if we're not restoring anything */
+ "0:"
+ "mrs r3, CONTROL;"
+ "bic r3, #(1<<2);" /* unset FPCA */
+ "msr CONTROL, r3;"
+ "isb;"
+
+ "1:"
#endif
- "0: bx lr;"
+ "bx lr;"
);
__UNREACHABLE;
}
@@ -355,13 +381,9 @@ __NAKED static void _thread_mode_bounce(bool fpused)
*/
void arch_context_switch(struct thread *oldthread, struct thread *newthread)
{
- //LTRACE_ENTRY;
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
LTRACEF("FPCCR.LSPACT %lu, FPCAR 0x%x, CONTROL.FPCA %lu\n",
FPU->FPCCR & FPU_FPCCR_LSPACT_Msk, FPU->FPCAR, __get_CONTROL() & CONTROL_FPCA_Msk);
-
- // XXX why is this here?
- asm volatile("vmov s0, s0");
#endif
/* if preempt_frame is set, we are being preempted */
@@ -372,11 +394,10 @@ void arch_context_switch(struct thread *oldthread, struct thread *newthread)
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
/* see if extended fpu frame was pushed */
if ((preempt_frame->lr & (1<<4)) == 0) {
- /* force a context save if it hasn't already */
- asm volatile("vmov s0, s0" ::: "memory");
- asm volatile("isb");
+ LTRACEF("thread %s pushed fpu frame\n", oldthread->name);
/* save the top part of the context */
+ /* note this should also trigger a lazy fpu save if it hasn't already done so */
asm volatile("vstm %0, { s16-s31 }" :: "r" (&oldthread->arch.fpregs[0]));
oldthread->arch.fpused = true;
@@ -387,22 +408,29 @@ void arch_context_switch(struct thread *oldthread, struct thread *newthread)
DEBUG_ASSERT(oldthread->arch.fpused == false);
}
#endif
+
oldthread->arch.was_preempted = true;
oldthread->arch.sp = (addr_t)preempt_frame;
preempt_frame = NULL;
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+ /* if new thread has saved fpu state, restore it */
if (newthread->arch.fpused) {
- /* restore the old fpu state */
- DEBUG_ASSERT((FPU->FPCCR & FPU_FPCCR_LSPACT_Msk) == 0);
- DEBUG_ASSERT(__get_CONTROL() & CONTROL_FPCA_Msk);
-
LTRACEF("newthread FPCCR.LSPACT %lu, FPCAR 0x%x, CONTROL.FPCA %lu\n",
FPU->FPCCR & FPU_FPCCR_LSPACT_Msk, FPU->FPCAR, __get_CONTROL() & CONTROL_FPCA_Msk);
+ /* enable the fpu manually */
+ __set_CONTROL(__get_CONTROL() | CONTROL_FPCA_Msk);
+ asm volatile("isb");
+
+ DEBUG_ASSERT((FPU->FPCCR & FPU_FPCCR_LSPACT_Msk) == 0);
+ DEBUG_ASSERT(__get_CONTROL() & CONTROL_FPCA_Msk);
+
+ /* restore the top of the fpu state, the rest will happen below */
asm volatile("vldm %0, { s16-s31 }" :: "r" (&newthread->arch.fpregs[0]));
}
#endif
+
if (newthread->arch.was_preempted) {
/* return directly to the preempted thread's iframe */
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
@@ -427,6 +455,7 @@ void arch_context_switch(struct thread *oldthread, struct thread *newthread)
frame->psr = (1 << 24); /* thread bit set, IPSR 0 */
frame->r0 = frame->r1 = frame->r2 = frame->r3 = frame->r12 = frame->lr = 0;
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+ /* pass the fpused bool to _thread_mode_bounce */
frame->r0 = newthread->arch.fpused;
#endif
@@ -449,8 +478,9 @@ void arch_context_switch(struct thread *oldthread, struct thread *newthread)
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
/* see if we have fpu state we need to save */
- if (oldthread->arch.fpused || __get_CONTROL() & CONTROL_FPCA_Msk) {
+ if (!oldthread->arch.fpused && __get_CONTROL() & CONTROL_FPCA_Msk) {
/* mark this thread as using float */
+ LTRACEF("thread %s uses float\n", oldthread->name);
oldthread->arch.fpused = true;
}
#endif
@@ -466,7 +496,7 @@ void arch_context_switch(struct thread *oldthread, struct thread *newthread)
/* fast path, both sides did not preempt */
LTRACEF("both sides are not preempted newsp 0x%lx\n", newthread->arch.sp);
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
- _arch_non_preempt_context_switch(oldthread, newthread, oldthread->arch.fpused,newthread->arch.fpused);
+ _arch_non_preempt_context_switch(oldthread, newthread, oldthread->arch.fpused, newthread->arch.fpused);
#else
_arch_non_preempt_context_switch(oldthread, newthread);
#endif
@@ -479,11 +509,11 @@ void arch_dump_thread(thread_t *t)
{
if (t->state != THREAD_RUNNING) {
dprintf(INFO, "\tarch: ");
- dprintf(INFO, "sp 0x%lx, was preempted %u\n", t->arch.sp, t->arch.was_preempted);
+ dprintf(INFO, "sp 0x%lx, was preempted %u", t->arch.sp, t->arch.was_preempted);
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
- dprintf(INFO, "\tfpused %u\n", t->arch.fpused);
-
+ dprintf(INFO, ", fpused %u", t->arch.fpused);
#endif
+ dprintf(INFO, "\n");
}
}
diff --git a/platform/stellaris/rules.mk b/platform/stellaris/rules.mk
index 9c5cf39b..b602342c 100644
--- a/platform/stellaris/rules.mk
+++ b/platform/stellaris/rules.mk
@@ -11,7 +11,9 @@ MEMSIZE ?= 32768
MEMBASE := 0x20000000
ROMBASE := 0x00000000
ARM_CPU := cortex-m4f
-GLOBAL_DEFINES += TARGET_IS_BLIZZARD_RA1
+GLOBAL_DEFINES += \
+ TARGET_IS_BLIZZARD_RA1 \
+ __FPU_PRESENT=1
endif
ifeq ($(STELLARIS_CHIP),LM3S6965)
MEMSIZE ?= 65536