/*************************************************************************** * 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 */ /** */ /**************************************************************************/ /**************************************************************************/ /* #define TX_SOURCE_CODE */ /* Include necessary system files. */ /* #include "tx_api.h" #include "tx_thread.h" #include "tx_timer.h" */ EXTERN _tx_thread_current_ptr EXTERN _tx_thread_system_state EXTERN _tx_thread_system_stack_ptr #ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY EXTERN _tx_execution_isr_enter #endif SECTION `.text`:CODE:REORDER:NOROOT(2) CODE /**************************************************************************/ /* */ /* FUNCTION RELEASE */ /* */ /* _tx_thread_context_save RISC-V32/IAR */ /* 6.1 */ /* AUTHOR */ /* */ /* William E. Lamie, Microsoft Corporation */ /* Tom van Leeuwen, Technolution B.V. */ /* */ /* 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 */ /* */ /* 09-30-2020 William E. Lamie Initial Version 6.1 */ /* */ /**************************************************************************/ /* VOID _tx_thread_context_save(VOID) { */ PUBLIC _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. */ sw x5, 0x4C(sp) ; First store t0 and t1 sw x6, 0x48(sp) la x5, _tx_thread_system_state ; Pickup address of system state lw x6, 0(x5) ; Pickup system state /* Check for a nested interrupt condition. */ /* if (_tx_thread_system_state++) { */ beqz x6, _tx_thread_not_nested_save ; If 0, first interrupt condition addi x6, x6, 1 ; Increment the interrupt counter sw x6, 0(x5) ; Store the interrupt counter /* Nested interrupt condition. Save the reset of the scratch registers on the stack and return to the calling ISR. */ sw x7, 0x44(sp) ; Store t2 sw x8, 0x30(sp) ; Store s0 sw x10, 0x6C(sp) ; Store a0 sw x11, 0x68(sp) ; Store a1 sw x12, 0x64(sp) ; Store a2 sw x13, 0x60(sp) ; Store a3 sw x14, 0x5C(sp) ; Store a4 sw x15, 0x58(sp) ; Store a5 sw x16, 0x54(sp) ; Store a6 sw x17, 0x50(sp) ; Store a7 sw x28, 0x40(sp) ; Store t3 sw x29, 0x3C(sp) ; Store t4 sw x30, 0x38(sp) ; Store t5 sw x31, 0x34(sp) ; Store t6 csrr t0, mepc ; Load exception program counter sw t0, 0x78(sp) ; Save it on the stack #if __iar_riscv_base_isa == rv32e /* Save floating point scratch registers. */ fsw f0, 0x7C(sp) ; Store ft0 fsw f1, 0x80(sp) ; Store ft1 fsw f2, 0x84(sp) ; Store ft2 fsw f3, 0x88(sp) ; Store ft3 fsw f4, 0x8C(sp) ; Store ft4 fsw f5, 0x90(sp) ; Store ft5 fsw f6, 0x94(sp) ; Store ft6 fsw f7, 0x98(sp) ; Store ft7 fsw f10,0xA4(sp) ; Store fa0 fsw f11,0xA8(sp) ; Store fa1 fsw f12,0xAC(sp) ; Store fa2 fsw f13,0xB0(sp) ; Store fa3 fsw f14,0xB4(sp) ; Store fa4 fsw f15,0xB8(sp) ; Store fa5 fsw f16,0xBC(sp) ; Store fa6 fsw f17,0xC0(sp) ; Store fa7 fsw f28,0xEC(sp) ; Store ft8 fsw f29,0xF0(sp) ; Store ft9 fsw f30,0xF4(sp) ; Store ft10 fsw f31,0xF8(sp) ; Store ft11 csrr t0, fcsr sw t0, 0xFC(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 x6, x6, 1 ; Increment the interrupt counter sw x6, 0(x5) ; Store the interrupt counter /* Not nested: Find the user thread that was running and load our SP */ lw x5, _tx_thread_current_ptr ; Pickup current thread pointer beqz x5, _tx_thread_idle_system_save ; If NULL, idle system was interrupted /* Save the standard scratch registers. */ sw x7, 0x44(sp) ; Store t2 sw x8, 0x30(sp) ; Store s0 sw x10, 0x6C(sp) ; Store a0 sw x11, 0x68(sp) ; Store a1 sw x12, 0x64(sp) ; Store a2 sw x13, 0x60(sp) ; Store a3 sw x14, 0x5C(sp) ; Store a4 sw x15, 0x58(sp) ; Store a5 sw x16, 0x54(sp) ; Store a6 sw x17, 0x50(sp) ; Store a7 sw x28, 0x40(sp) ; Store t3 sw x29, 0x3C(sp) ; Store t4 sw x30, 0x38(sp) ; Store t5 sw x31, 0x34(sp) ; Store t6 csrr t0, mepc ; Load exception program counter sw t0, 0x78(sp) ; Save it on the stack #if __iar_riscv_base_isa == rv32e /* Save floating point scratch registers. */ fsw f0, 0x7C(sp) ; Store ft0 fsw f1, 0x80(sp) ; Store ft1 fsw f2, 0x84(sp) ; Store ft2 fsw f3, 0x88(sp) ; Store ft3 fsw f4, 0x8C(sp) ; Store ft4 fsw f5, 0x90(sp) ; Store ft5 fsw f6, 0x94(sp) ; Store ft6 fsw f7, 0x98(sp) ; Store ft7 fsw f10,0xA4(sp) ; Store fa0 fsw f11,0xA8(sp) ; Store fa1 fsw f12,0xAC(sp) ; Store fa2 fsw f13,0xB0(sp) ; Store fa3 fsw f14,0xB4(sp) ; Store fa4 fsw f15,0xB8(sp) ; Store fa5 fsw f16,0xBC(sp) ; Store fa6 fsw f17,0xC0(sp) ; Store fa7 fsw f28,0xEC(sp) ; Store ft8 fsw f29,0xF0(sp) ; Store ft9 fsw f30,0xF4(sp) ; Store ft10 fsw f31,0xF8(sp) ; Store ft11 csrr t0, fcsr sw t0, 0xFC(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; */ lw t1, _tx_thread_current_ptr ; Pickup current thread pointer sw sp, 8(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 lw 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 __iar_riscv_base_isa == rv32e addi sp, sp, 260 ; Recover stack frame - with floating point enabled #else addi sp, sp, 128 ; Recover the reserved stack space #endif ret ; Return to calling ISR END