SPARC: add FPU support
This change adds full shared floating point support for the SPARC architecture. All SPARC floating point registers are scratch registers with respect to function call boundaries. That means we only have to save floating point registers when switching threads in ISR. The registers are stored to the corresponding thread stack. FPU is disabled when calling ISR. Any attempt to use FPU in ISR will generate the fp_disabled trap which causes Zephyr fatal error. - This commit adds no new thread state. - All FPU contest save/restore is synchronous and lazy FPU context switch is not implemented. Signed-off-by: Martin Åberg <martin.aberg@gaisler.com>
This commit is contained in:
parent
356d37fb7f
commit
53a4acb2dc
5 changed files with 145 additions and 7 deletions
|
@ -730,7 +730,7 @@ menu "Floating Point Options"
|
|||
config FPU
|
||||
bool "Enable floating point unit (FPU)"
|
||||
depends on CPU_HAS_FPU
|
||||
depends on ARC || ARM || RISCV || X86
|
||||
depends on ARC || ARM || RISCV || SPARC || X86
|
||||
help
|
||||
This option enables the hardware Floating Point Unit (FPU), in order to
|
||||
support using the floating point registers and instructions.
|
||||
|
|
|
@ -117,8 +117,30 @@ __sparc_trap_interrupt:
|
|||
*/
|
||||
|
||||
/* Enable traps, raise PIL to mask all maskable interrupts. */
|
||||
or %l0, PSR_PIL, %o0
|
||||
wr %o0, PSR_ET, %psr
|
||||
or %l0, PSR_PIL, %l6
|
||||
|
||||
#if defined(CONFIG_FPU)
|
||||
/*
|
||||
* We now check if the interrupted context was using the FPU. The
|
||||
* result is stored in register l5 which will either get the value 0
|
||||
* (FPU not used) or PSR_EF (FPU used).
|
||||
*
|
||||
* If the FPU was used by the interrupted context, then we do two
|
||||
* things:
|
||||
* 1. Store FSR to memory. This has the side-effect of completing all
|
||||
* pending FPU operations.
|
||||
* 2. Disable FPU. Floating point instructions in the ISR will trap.
|
||||
*
|
||||
* The FPU is be enabled again if needed after the ISR has returned.
|
||||
*/
|
||||
set PSR_EF, %l5
|
||||
andcc %l0, %l5, %l5
|
||||
bne,a 1f
|
||||
st %fsr, [%sp]
|
||||
1:
|
||||
andn %l6, %l5, %l6
|
||||
#endif
|
||||
wr %l6, PSR_ET, %psr
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
@ -159,7 +181,69 @@ __sparc_trap_interrupt:
|
|||
*/
|
||||
cmp %o0, %o1
|
||||
beq .Lno_reschedule
|
||||
/* z_sparc_context_switch() is a leaf function not using stack. */
|
||||
add %sp, (96+8-64), %sp
|
||||
|
||||
#if defined(CONFIG_FPU_SHARING)
|
||||
/* IF PSR_EF at trap time then store the FP context. */
|
||||
cmp %l5, 0
|
||||
be .Lno_fp_context
|
||||
nop
|
||||
|
||||
/*
|
||||
* PSR_EF was 1 at trap time so save the FP registers on stack.
|
||||
* - Set PSR_EF so we can access the FP registers.
|
||||
* - Allocate space for the FP registers above the save area used for
|
||||
* the z_sparc_context_switch() call.
|
||||
*/
|
||||
wr %l6, %l5, %psr
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
sub %sp, 34 * 4, %sp
|
||||
std %f0, [%sp + 64 + 0x00]
|
||||
std %f2, [%sp + 64 + 0x08]
|
||||
std %f4, [%sp + 64 + 0x10]
|
||||
std %f6, [%sp + 64 + 0x18]
|
||||
std %f8, [%sp + 64 + 0x20]
|
||||
std %f10, [%sp + 64 + 0x28]
|
||||
std %f12, [%sp + 64 + 0x30]
|
||||
std %f14, [%sp + 64 + 0x38]
|
||||
std %f16, [%sp + 64 + 0x40]
|
||||
std %f18, [%sp + 64 + 0x48]
|
||||
std %f20, [%sp + 64 + 0x50]
|
||||
std %f22, [%sp + 64 + 0x58]
|
||||
std %f24, [%sp + 64 + 0x60]
|
||||
std %f26, [%sp + 64 + 0x68]
|
||||
std %f28, [%sp + 64 + 0x70]
|
||||
std %f30, [%sp + 64 + 0x78]
|
||||
|
||||
call z_sparc_context_switch
|
||||
st %fsr, [%sp + 64 + 0x80]
|
||||
|
||||
ldd [%sp + 64 + 0x00], %f0
|
||||
ldd [%sp + 64 + 0x08], %f2
|
||||
ldd [%sp + 64 + 0x10], %f4
|
||||
ldd [%sp + 64 + 0x18], %f6
|
||||
ldd [%sp + 64 + 0x20], %f8
|
||||
ldd [%sp + 64 + 0x28], %f10
|
||||
ldd [%sp + 64 + 0x30], %f12
|
||||
ldd [%sp + 64 + 0x38], %f14
|
||||
ldd [%sp + 64 + 0x40], %f16
|
||||
ldd [%sp + 64 + 0x48], %f18
|
||||
ldd [%sp + 64 + 0x50], %f20
|
||||
ldd [%sp + 64 + 0x58], %f22
|
||||
ldd [%sp + 64 + 0x60], %f24
|
||||
ldd [%sp + 64 + 0x68], %f26
|
||||
ldd [%sp + 64 + 0x70], %f28
|
||||
ldd [%sp + 64 + 0x78], %f30
|
||||
ld [%sp + 64 + 0x80], %fsr
|
||||
ba .Lno_reschedule
|
||||
add %sp, 34 * 4, %sp
|
||||
.Lno_fp_context:
|
||||
#endif /* CONFIG_FPU_SHARING */
|
||||
|
||||
call z_sparc_context_switch
|
||||
nop
|
||||
.Lno_reschedule:
|
||||
|
|
|
@ -27,6 +27,12 @@ struct init_stack_frame {
|
|||
uint32_t pad[8];
|
||||
};
|
||||
|
||||
#if defined(CONFIG_FPU_SHARING)
|
||||
#define USER_FP_MASK K_FP_REGS
|
||||
#else
|
||||
#define USER_FP_MASK 0
|
||||
#endif
|
||||
|
||||
void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
|
||||
char *stack_ptr, k_thread_entry_t entry,
|
||||
void *p1, void *p2, void *p3)
|
||||
|
@ -47,6 +53,16 @@ void arch_new_thread(struct k_thread *thread, k_thread_stack_t *stack,
|
|||
thread->callee_saved.o7 = (uint32_t) z_thread_entry_wrapper - 8;
|
||||
thread->callee_saved.psr = PSR_S | PSR_PS | PSR_ET;
|
||||
|
||||
if (IS_ENABLED(CONFIG_FPU_SHARING)) {
|
||||
/* Selected threads can use the FPU */
|
||||
if (thread->base.user_options & USER_FP_MASK) {
|
||||
thread->callee_saved.psr |= PSR_EF;
|
||||
}
|
||||
} else if (IS_ENABLED(CONFIG_FPU)) {
|
||||
/* Any thread can use the FPU */
|
||||
thread->callee_saved.psr |= PSR_EF;
|
||||
}
|
||||
|
||||
thread->switch_handle = thread;
|
||||
}
|
||||
|
||||
|
@ -56,3 +72,10 @@ void *z_arch_get_next_switch_handle(struct k_thread **old_thread)
|
|||
|
||||
return z_get_next_switch_handle(*old_thread);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FPU_SHARING)
|
||||
int arch_float_disable(struct k_thread *thread)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif /* CONFIG_FPU_SHARING */
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
list(APPEND TOOLCHAIN_C_FLAGS -msoft-float)
|
||||
list(APPEND TOOLCHAIN_LD_FLAGS -msoft-float)
|
||||
if(NOT CONFIG_FPU)
|
||||
list(APPEND TOOLCHAIN_C_FLAGS -msoft-float)
|
||||
list(APPEND TOOLCHAIN_LD_FLAGS -msoft-float)
|
||||
endif()
|
||||
|
||||
if(CONFIG_SPARC_CASA)
|
||||
# SPARC V8, mul/div, casa
|
||||
|
|
|
@ -9,8 +9,9 @@ configurations that support these registers.
|
|||
.. note::
|
||||
Floating point services are currently available only for boards
|
||||
based on ARM Cortex-M SoCs supporting the Floating Point Extension,
|
||||
the Intel x86 architecture and ARCv2 SoCs supporting the Floating
|
||||
Point Extension. The services provided are architecture specific.
|
||||
the Intel x86 architecture, the SPARC architecture and ARCv2 SoCs
|
||||
supporting the Floating Point Extension. The services provided
|
||||
are architecture specific.
|
||||
|
||||
The kernel does not support the use of floating point registers by ISRs.
|
||||
|
||||
|
@ -176,6 +177,34 @@ FP context of threads that are not using the FP registers. An extra 84 bytes
|
|||
(single floating point hardware) or 164 bytes (double floating point hardware)
|
||||
of stack space is required to load and store floating point registers.
|
||||
|
||||
SPARC architecture
|
||||
------------------
|
||||
|
||||
On the SPARC architecture, the kernel treats each thread as a non-user
|
||||
or FPU user and the thread must be tagged by one of the
|
||||
following techniques:
|
||||
|
||||
* A statically-created thread can be tagged by passing the
|
||||
:c:macro:`K_FP_REGS` option to :c:macro:`K_THREAD_DEFINE`.
|
||||
|
||||
* A dynamically-created thread can be tagged by passing the
|
||||
:c:macro:`K_FP_REGS` to :c:func:`k_thread_create`.
|
||||
|
||||
During thread context switch at exit from interrupt handler, the SPARC
|
||||
kernel saves *all* floating point registers, if the FPU was enabled in
|
||||
the switched-out thread. Floating point registers are saved on the thread's
|
||||
stack. Floating point registers are restored when a thread context is restored
|
||||
iff they were saved at the context save. Saving and restoring of the floating
|
||||
point registers is synchronous and thus not lazy. The FPU is always disabled
|
||||
when an ISR is called (independent of :option:`CONFIG_FPU_SHARING`).
|
||||
|
||||
Floating point disabling with :c:func:`k_float_disable` is not implemented.
|
||||
|
||||
When :option:`CONFIG_FPU_SHARING` is used, then 136 bytes of stack space
|
||||
is required for each FPU user thread to load and store floating point
|
||||
registers. No extra stack is required if :option:`CONFIG_FPU_SHARING` is
|
||||
not used.
|
||||
|
||||
x86 architecture
|
||||
----------------
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue