284 lines
16 KiB
ArmAsm
284 lines
16 KiB
ArmAsm
/***************************************************************************
|
|
* Copyright (c) 2024 Microsoft Corporation
|
|
*
|
|
* This program and the accompanying materials are made available under the
|
|
* terms of the MIT License which is available at
|
|
* https://opensource.org/licenses/MIT.
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
**************************************************************************/
|
|
|
|
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
/** */
|
|
/** ThreadX Component */
|
|
/** */
|
|
/** Thread */
|
|
/** */
|
|
/**************************************************************************/
|
|
/**************************************************************************/
|
|
|
|
#include "tx_port.h"
|
|
|
|
.section .text
|
|
/**************************************************************************/
|
|
/* */
|
|
/* FUNCTION RELEASE */
|
|
/* */
|
|
/* _tx_thread_context_save RISC-V64/GNU */
|
|
/* 6.2.1 */
|
|
/* AUTHOR */
|
|
/* */
|
|
/* Scott Larson, Microsoft Corporation */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* */
|
|
/* This function saves the context of an executing thread in the */
|
|
/* beginning of interrupt processing. The function also ensures that */
|
|
/* the system stack is used upon return to the calling ISR. */
|
|
/* */
|
|
/* INPUT */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* OUTPUT */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* CALLS */
|
|
/* */
|
|
/* None */
|
|
/* */
|
|
/* CALLED BY */
|
|
/* */
|
|
/* ISRs */
|
|
/* */
|
|
/* RELEASE HISTORY */
|
|
/* */
|
|
/* DATE NAME DESCRIPTION */
|
|
/* */
|
|
/* 03-08-2023 Scott Larson Initial Version 6.2.1 */
|
|
/* */
|
|
/**************************************************************************/
|
|
/* VOID _tx_thread_context_save(VOID)
|
|
{ */
|
|
.global _tx_thread_context_save
|
|
_tx_thread_context_save:
|
|
|
|
/* Upon entry to this routine, it is assumed that interrupts are locked
|
|
out and the interrupt stack fame has been allocated and x1 (ra) has
|
|
been saved on the stack. */
|
|
|
|
STORE t0, 19*REGBYTES(sp) // First store t0 and t1
|
|
STORE t1, 18*REGBYTES(sp)
|
|
|
|
la t0, _tx_thread_system_state // Pickup address of system state
|
|
lw t1, 0(t0) // Pickup system state
|
|
|
|
/* Check for a nested interrupt condition. */
|
|
/* if (_tx_thread_system_state++)
|
|
{ */
|
|
beqz t1, _tx_thread_not_nested_save // If 0, first interrupt condition
|
|
addi t1, t1, 1 // Increment the interrupt counter
|
|
sw t1, 0(t0) // Store the interrupt counter
|
|
|
|
/* Nested interrupt condition.
|
|
Save the reset of the scratch registers on the stack and return to the
|
|
calling ISR. */
|
|
|
|
STORE x7, 17*REGBYTES(sp) // Store t2
|
|
STORE x8, 12*REGBYTES(sp) // Store s0
|
|
STORE x10, 27*REGBYTES(sp) // Store a0
|
|
STORE x11, 26*REGBYTES(sp) // Store a1
|
|
STORE x12, 25*REGBYTES(sp) // Store a2
|
|
STORE x13, 24*REGBYTES(sp) // Store a3
|
|
STORE x14, 23*REGBYTES(sp) // Store a4
|
|
STORE x15, 22*REGBYTES(sp) // Store a5
|
|
STORE x16, 21*REGBYTES(sp) // Store a6
|
|
STORE x17, 20*REGBYTES(sp) // Store a7
|
|
STORE x28, 16*REGBYTES(sp) // Store t3
|
|
STORE x29, 15*REGBYTES(sp) // Store t4
|
|
STORE x30, 14*REGBYTES(sp) // Store t5
|
|
STORE x31, 13*REGBYTES(sp) // Store t6
|
|
csrr t0, mepc // Load exception program counter
|
|
STORE t0, 30*REGBYTES(sp) // Save it on the stack
|
|
|
|
/* Save floating point scratch registers. */
|
|
#if defined(__riscv_float_abi_single)
|
|
fsw f0, 31*REGBYTES(sp) // Store ft0
|
|
fsw f1, 32*REGBYTES(sp) // Store ft1
|
|
fsw f2, 33*REGBYTES(sp) // Store ft2
|
|
fsw f3, 34*REGBYTES(sp) // Store ft3
|
|
fsw f4, 35*REGBYTES(sp) // Store ft4
|
|
fsw f5, 36*REGBYTES(sp) // Store ft5
|
|
fsw f6, 37*REGBYTES(sp) // Store ft6
|
|
fsw f7, 38*REGBYTES(sp) // Store ft7
|
|
fsw f10,41*REGBYTES(sp) // Store fa0
|
|
fsw f11,42*REGBYTES(sp) // Store fa1
|
|
fsw f12,43*REGBYTES(sp) // Store fa2
|
|
fsw f13,44*REGBYTES(sp) // Store fa3
|
|
fsw f14,45*REGBYTES(sp) // Store fa4
|
|
fsw f15,46*REGBYTES(sp) // Store fa5
|
|
fsw f16,47*REGBYTES(sp) // Store fa6
|
|
fsw f17,48*REGBYTES(sp) // Store fa7
|
|
fsw f28,59*REGBYTES(sp) // Store ft8
|
|
fsw f29,60*REGBYTES(sp) // Store ft9
|
|
fsw f30,61*REGBYTES(sp) // Store ft10
|
|
fsw f31,62*REGBYTES(sp) // Store ft11
|
|
csrr t0, fcsr
|
|
STORE t0, 63*REGBYTES(sp) // Store fcsr
|
|
#elif defined(__riscv_float_abi_double)
|
|
fsd f0, 31*REGBYTES(sp) // Store ft0
|
|
fsd f1, 32*REGBYTES(sp) // Store ft1
|
|
fsd f2, 33*REGBYTES(sp) // Store ft2
|
|
fsd f3, 34*REGBYTES(sp) // Store ft3
|
|
fsd f4, 35*REGBYTES(sp) // Store ft4
|
|
fsd f5, 36*REGBYTES(sp) // Store ft5
|
|
fsd f6, 37*REGBYTES(sp) // Store ft6
|
|
fsd f7, 38*REGBYTES(sp) // Store ft7
|
|
fsd f10,41*REGBYTES(sp) // Store fa0
|
|
fsd f11,42*REGBYTES(sp) // Store fa1
|
|
fsd f12,43*REGBYTES(sp) // Store fa2
|
|
fsd f13,44*REGBYTES(sp) // Store fa3
|
|
fsd f14,45*REGBYTES(sp) // Store fa4
|
|
fsd f15,46*REGBYTES(sp) // Store fa5
|
|
fsd f16,47*REGBYTES(sp) // Store fa6
|
|
fsd f17,48*REGBYTES(sp) // Store fa7
|
|
fsd f28,59*REGBYTES(sp) // Store ft8
|
|
fsd f29,60*REGBYTES(sp) // Store ft9
|
|
fsd f30,61*REGBYTES(sp) // Store ft10
|
|
fsd f31,62*REGBYTES(sp) // Store ft11
|
|
csrr t0, fcsr
|
|
STORE t0, 63*REGBYTES(sp) // Store fcsr
|
|
#endif
|
|
|
|
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
|
call _tx_execution_isr_enter // Call the ISR execution enter function
|
|
#endif
|
|
|
|
ret // Return to calling ISR
|
|
|
|
_tx_thread_not_nested_save:
|
|
/* } */
|
|
|
|
/* Otherwise, not nested, check to see if a thread was running. */
|
|
/* else if (_tx_thread_current_ptr)
|
|
{ */
|
|
addi t1, t1, 1 // Increment the interrupt counter
|
|
sw t1, 0(t0) // Store the interrupt counter
|
|
|
|
/* Not nested: Find the user thread that was running and load our SP */
|
|
|
|
LOAD t0, _tx_thread_current_ptr // Pickup current thread pointer
|
|
beqz t0, _tx_thread_idle_system_save // If NULL, idle system was interrupted
|
|
|
|
/* Save the standard scratch registers. */
|
|
|
|
STORE x7, 17*REGBYTES(sp) // Store t2
|
|
STORE x8, 12*REGBYTES(sp) // Store s0
|
|
STORE x10, 27*REGBYTES(sp) // Store a0
|
|
STORE x11, 26*REGBYTES(sp) // Store a1
|
|
STORE x12, 25*REGBYTES(sp) // Store a2
|
|
STORE x13, 24*REGBYTES(sp) // Store a3
|
|
STORE x14, 23*REGBYTES(sp) // Store a4
|
|
STORE x15, 22*REGBYTES(sp) // Store a5
|
|
STORE x16, 21*REGBYTES(sp) // Store a6
|
|
STORE x17, 20*REGBYTES(sp) // Store a7
|
|
STORE x28, 16*REGBYTES(sp) // Store t3
|
|
STORE x29, 15*REGBYTES(sp) // Store t4
|
|
STORE x30, 14*REGBYTES(sp) // Store t5
|
|
STORE x31, 13*REGBYTES(sp) // Store t6
|
|
|
|
csrr t0, mepc // Load exception program counter
|
|
STORE t0, 30*REGBYTES(sp) // Save it on the stack
|
|
|
|
/* Save floating point scratch registers. */
|
|
#if defined(__riscv_float_abi_single)
|
|
fsw f0, 31*REGBYTES(sp) // Store ft0
|
|
fsw f1, 32*REGBYTES(sp) // Store ft1
|
|
fsw f2, 33*REGBYTES(sp) // Store ft2
|
|
fsw f3, 34*REGBYTES(sp) // Store ft3
|
|
fsw f4, 35*REGBYTES(sp) // Store ft4
|
|
fsw f5, 36*REGBYTES(sp) // Store ft5
|
|
fsw f6, 37*REGBYTES(sp) // Store ft6
|
|
fsw f7, 38*REGBYTES(sp) // Store ft7
|
|
fsw f10,41*REGBYTES(sp) // Store fa0
|
|
fsw f11,42*REGBYTES(sp) // Store fa1
|
|
fsw f12,43*REGBYTES(sp) // Store fa2
|
|
fsw f13,44*REGBYTES(sp) // Store fa3
|
|
fsw f14,45*REGBYTES(sp) // Store fa4
|
|
fsw f15,46*REGBYTES(sp) // Store fa5
|
|
fsw f16,47*REGBYTES(sp) // Store fa6
|
|
fsw f17,48*REGBYTES(sp) // Store fa7
|
|
fsw f28,59*REGBYTES(sp) // Store ft8
|
|
fsw f29,60*REGBYTES(sp) // Store ft9
|
|
fsw f30,61*REGBYTES(sp) // Store ft10
|
|
fsw f31,62*REGBYTES(sp) // Store ft11
|
|
csrr t0, fcsr
|
|
STORE t0, 63*REGBYTES(sp) // Store fcsr
|
|
#elif defined(__riscv_float_abi_double)
|
|
fsd f0, 31*REGBYTES(sp) // Store ft0
|
|
fsd f1, 32*REGBYTES(sp) // Store ft1
|
|
fsd f2, 33*REGBYTES(sp) // Store ft2
|
|
fsd f3, 34*REGBYTES(sp) // Store ft3
|
|
fsd f4, 35*REGBYTES(sp) // Store ft4
|
|
fsd f5, 36*REGBYTES(sp) // Store ft5
|
|
fsd f6, 37*REGBYTES(sp) // Store ft6
|
|
fsd f7, 38*REGBYTES(sp) // Store ft7
|
|
fsd f10,41*REGBYTES(sp) // Store fa0
|
|
fsd f11,42*REGBYTES(sp) // Store fa1
|
|
fsd f12,43*REGBYTES(sp) // Store fa2
|
|
fsd f13,44*REGBYTES(sp) // Store fa3
|
|
fsd f14,45*REGBYTES(sp) // Store fa4
|
|
fsd f15,46*REGBYTES(sp) // Store fa5
|
|
fsd f16,47*REGBYTES(sp) // Store fa6
|
|
fsd f17,48*REGBYTES(sp) // Store fa7
|
|
fsd f28,59*REGBYTES(sp) // Store ft8
|
|
fsd f29,60*REGBYTES(sp) // Store ft9
|
|
fsd f30,61*REGBYTES(sp) // Store ft10
|
|
fsd f31,62*REGBYTES(sp) // Store ft11
|
|
csrr t0, fcsr
|
|
STORE t0, 63*REGBYTES(sp) // Store fcsr
|
|
#endif
|
|
|
|
/* Save the current stack pointer in the thread's control block. */
|
|
/* _tx_thread_current_ptr -> tx_thread_stack_ptr = sp; */
|
|
|
|
/* Switch to the system stack. */
|
|
/* sp = _tx_thread_system_stack_ptr; */
|
|
|
|
LOAD t1, _tx_thread_current_ptr // Pickup current thread pointer
|
|
STORE sp, 2*REGBYTES(t1) // Save stack pointer
|
|
|
|
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
|
/* _tx_execution_isr_enter is called with thread stack pointer */
|
|
call _tx_execution_isr_enter // Call the ISR execution enter function
|
|
#endif
|
|
|
|
|
|
LOAD sp, _tx_thread_system_stack_ptr // Switch to system stack
|
|
ret // Return to calling ISR
|
|
|
|
/* }
|
|
else
|
|
{ */
|
|
|
|
_tx_thread_idle_system_save:
|
|
|
|
|
|
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
|
|
call _tx_execution_isr_enter // Call the ISR execution enter function
|
|
#endif
|
|
|
|
/* Interrupt occurred in the scheduling loop. */
|
|
|
|
/* }
|
|
} */
|
|
#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double)
|
|
addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point enabled
|
|
#else
|
|
addi sp, sp, 32*REGBYTES // Recover the reserved stack space
|
|
#endif
|
|
ret // Return to calling ISR
|