diff options
| author | Tiejun Zhou <[email protected]> | 2023-03-08 08:26:22 +0000 |
|---|---|---|
| committer | Tiejun Zhou <[email protected]> | 2023-03-08 08:26:22 +0000 |
| commit | 2aa19f3de0b6cf09bb9dca78c8a53fe337b8f0f7 (patch) | |
| tree | 8ec91a64e0831e3100a6ad9a5dec41d9fd7fc74f /ports/risc-v64/gnu/src | |
| parent | 745395d6a2f931c85c4428425db21eb7d03b4324 (diff) | |
Release 6.2.1 on 08 Mar 2023. Expand to see details.v6.2.1_rel
cee19603d Include tx_user.h conditionally.
e40e08007 Update owners
d69641273 Update release date and version
394aee52f Add tx_user.h to GNU port assembly files
5cca2ddd0 RISC-V 64 bit port for Microchip
e0f2c373c Link Winmm.lib that required by the high-resolution timer.
6af472a68 Update Win32 port with high resolution timer.
aea7b556a Add DMB ISH barrier inst in ARMv8-A SMP scheduler
19091a262 Add .section .preamble to m3 m4 m7 module ports
ced60e1b7 Add missing parenthesis in ports assembly file
309dc77ca Modules Cortex-A7 IAR new port
c752a4063 Modules Cortex-A7 GNU new port
dc224b90f Fix race condition in tx_thread_wait_abort and update regression test
6e261f5b7 create threadx cmsis-pack
Diffstat (limited to 'ports/risc-v64/gnu/src')
| -rw-r--r-- | ports/risc-v64/gnu/src/tx_initialize_low_level.S | 111 | ||||
| -rw-r--r-- | ports/risc-v64/gnu/src/tx_thread_context_restore.S | 375 | ||||
| -rw-r--r-- | ports/risc-v64/gnu/src/tx_thread_context_save.S | 284 | ||||
| -rw-r--r-- | ports/risc-v64/gnu/src/tx_thread_interrupt_control.S | 82 | ||||
| -rw-r--r-- | ports/risc-v64/gnu/src/tx_thread_schedule.S | 302 | ||||
| -rw-r--r-- | ports/risc-v64/gnu/src/tx_thread_stack_build.S | 229 | ||||
| -rw-r--r-- | ports/risc-v64/gnu/src/tx_thread_system_return.S | 175 | ||||
| -rw-r--r-- | ports/risc-v64/gnu/src/tx_timer_interrupt.c | 135 |
8 files changed, 1693 insertions, 0 deletions
diff --git a/ports/risc-v64/gnu/src/tx_initialize_low_level.S b/ports/risc-v64/gnu/src/tx_initialize_low_level.S new file mode 100644 index 00000000..d99ec144 --- /dev/null +++ b/ports/risc-v64/gnu/src/tx_initialize_low_level.S @@ -0,0 +1,111 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Initialize */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + .section .data + .global __tx_free_memory_start +__tx_free_memory_start: + + + .section .text +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_initialize_low_level RISC-V64/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for any low-level processor */ +/* initialization, including setting up interrupt vectors, setting */ +/* up a periodic timer interrupt source, saving the system stack */ +/* pointer for use in ISR processing later, and finding the first */ +/* available RAM memory address for tx_application_define. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 03-08-2023 Scott Larson Initial Version 6.2.1 */ +/* */ +/**************************************************************************/ +/* VOID _tx_initialize_low_level(VOID) +{ */ + .global _tx_initialize_low_level +_tx_initialize_low_level: + sd sp, _tx_thread_system_stack_ptr, t0 // Save system stack pointer + + la t0, __tx_free_memory_start // Pickup first free address + sd t0, _tx_initialize_unused_memory, t1 // Save unused memory address + +#ifdef __riscv_flen + fscsr x0 +#endif + + ret + + + /* Define the actual timer interrupt/exception handler. */ + + .global timer1_plic_IRQHandler + //.global __minterrupt_000007 + //EXTWEAK __require_minterrupt_vector_table +timer1_plic_IRQHandler: +//__minterrupt_000007: + //REQUIRE __require_minterrupt_vector_table + + + /* Before calling _tx_thread_context_save, we have to allocate an interrupt + stack frame and save the current value of x1 (ra). */ +//#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double) +// addi sp, sp, -520 // Allocate space for all registers - with floating point enabled +//#else +// addi sp, sp, -256 // Allocate space for all registers - without floating point enabled +//#endif +// sd x1, 224(sp) // Store RA +// call _tx_thread_context_save // Call ThreadX context save + + /* Call the ThreadX timer routine. */ + call _tx_timer_interrupt // Call timer interrupt handler + call timer1_interrupt + ret + /* Timer interrupt processing is done, jump to ThreadX context restore. */ +// j _tx_thread_context_restore // Jump to ThreadX context restore function. Note: this does not return! diff --git a/ports/risc-v64/gnu/src/tx_thread_context_restore.S b/ports/risc-v64/gnu/src/tx_thread_context_restore.S new file mode 100644 index 00000000..55ba6ac0 --- /dev/null +++ b/ports/risc-v64/gnu/src/tx_thread_context_restore.S @@ -0,0 +1,375 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#include "tx_port.h" + + .section .text +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_context_restore RISC-V64/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function restores the interrupt context if it is processing a */ +/* nested interrupt. If not, it returns to the interrupt thread if no */ +/* preemption is necessary. Otherwise, if preemption is necessary or */ +/* if no thread was running, the function returns to the scheduler. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling routine */ +/* */ +/* CALLED BY */ +/* */ +/* ISRs Interrupt Service Routines */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 03-08-2023 Scott Larson Initial Version 6.2.1 */ +/* */ +/**************************************************************************/ +/* VOID _tx_thread_context_restore(VOID) +{ */ + .global _tx_thread_context_restore +_tx_thread_context_restore: + + /* Lockout interrupts. */ + + csrci mstatus, 0x08 // Disable interrupts + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + call _tx_execution_isr_exit // Call the ISR execution exit function +#endif + + /* Determine if interrupts are nested. */ + /* if (--_tx_thread_system_state) + { */ + + la t0, _tx_thread_system_state // Pickup addr of nested interrupt count + LOAD t1, 0(t0) // Pickup nested interrupt count + addi t1, t1, -1 // Decrement the nested interrupt counter + STORE t1, 0(t0) // Store new nested count + beqz t1, _tx_thread_not_nested_restore // If 0, not nested restore + + /* Interrupts are nested. */ + + /* Just recover the saved registers and return to the point of + interrupt. */ + + /* Recover floating point registers. */ +#if defined(__riscv_float_abi_single) + flw f0, 31*REGBYTES(sp) // Recover ft0 + flw f1, 32*REGBYTES(sp) // Recover ft1 + flw f2, 33*REGBYTES(sp) // Recover ft2 + flw f3, 34*REGBYTES(sp) // Recover ft3 + flw f4, 35*REGBYTES(sp) // Recover ft4 + flw f5, 36*REGBYTES(sp) // Recover ft5 + flw f6, 37*REGBYTES(sp) // Recover ft6 + flw f7, 38*REGBYTES(sp) // Recover ft7 + flw f10,41*REGBYTES(sp) // Recover fa0 + flw f11,42*REGBYTES(sp) // Recover fa1 + flw f12,43*REGBYTES(sp) // Recover fa2 + flw f13,44*REGBYTES(sp) // Recover fa3 + flw f14,45*REGBYTES(sp) // Recover fa4 + flw f15,46*REGBYTES(sp) // Recover fa5 + flw f16,47*REGBYTES(sp) // Recover fa6 + flw f17,48*REGBYTES(sp) // Recover fa7 + flw f28,59*REGBYTES(sp) // Recover ft8 + flw f29,60*REGBYTES(sp) // Recover ft9 + flw f30,61*REGBYTES(sp) // Recover ft10 + flw f31,62*REGBYTES(sp) // Recover ft11 + lw t0, 63*REGBYTES(sp) // Recover fcsr + csrw fcsr, t0 // +#elif defined(__riscv_float_abi_double) + fld f0, 31*REGBYTES(sp) // Recover ft0 + fld f1, 32*REGBYTES(sp) // Recover ft1 + fld f2, 33*REGBYTES(sp) // Recover ft2 + fld f3, 34*REGBYTES(sp) // Recover ft3 + fld f4, 35*REGBYTES(sp) // Recover ft4 + fld f5, 36*REGBYTES(sp) // Recover ft5 + fld f6, 37*REGBYTES(sp) // Recover ft6 + fld f7, 38*REGBYTES(sp) // Recover ft7 + fld f10,41*REGBYTES(sp) // Recover fa0 + fld f11,42*REGBYTES(sp) // Recover fa1 + fld f12,43*REGBYTES(sp) // Recover fa2 + fld f13,44*REGBYTES(sp) // Recover fa3 + fld f14,45*REGBYTES(sp) // Recover fa4 + fld f15,46*REGBYTES(sp) // Recover fa5 + fld f16,47*REGBYTES(sp) // Recover fa6 + fld f17,48*REGBYTES(sp) // Recover fa7 + fld f28,59*REGBYTES(sp) // Recover ft8 + fld f29,60*REGBYTES(sp) // Recover ft9 + fld f30,61*REGBYTES(sp) // Recover ft10 + fld f31,62*REGBYTES(sp) // Recover ft11 + LOAD t0, 63*REGBYTES(sp) // Recover fcsr + csrw fcsr, t0 // +#endif + + /* Recover standard registers. */ + + /* Restore registers, + Skip global pointer because that does not change. + Also skip the saved registers since they have been restored by any function we called, + except s0 since we use it ourselves. */ + + LOAD t0, 30*REGBYTES(sp) // Recover mepc + csrw mepc, t0 // Setup mepc + li t0, 0x1880 // Prepare MPIP + csrw mstatus, t0 // Enable MPIP + + LOAD x1, 28*REGBYTES(sp) // Recover RA + LOAD x5, 19*REGBYTES(sp) // Recover t0 + LOAD x6, 18*REGBYTES(sp) // Recover t1 + LOAD x7, 17*REGBYTES(sp) // Recover t2 + LOAD x8, 12*REGBYTES(sp) // Recover s0 + LOAD x10, 27*REGBYTES(sp) // Recover a0 + LOAD x11, 26*REGBYTES(sp) // Recover a1 + LOAD x12, 25*REGBYTES(sp) // Recover a2 + LOAD x13, 24*REGBYTES(sp) // Recover a3 + LOAD x14, 23*REGBYTES(sp) // Recover a4 + LOAD x15, 22*REGBYTES(sp) // Recover a5 + LOAD x16, 21*REGBYTES(sp) // Recover a6 + LOAD x17, 20*REGBYTES(sp) // Recover a7 + LOAD x28, 16*REGBYTES(sp) // Recover t3 + LOAD x29, 15*REGBYTES(sp) // Recover t4 + LOAD x30, 14*REGBYTES(sp) // Recover t5 + LOAD x31, 13*REGBYTES(sp) // Recover t6 + +#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 stack frame - without floating point enabled +#endif + mret // Return to point of interrupt + + /* } */ +_tx_thread_not_nested_restore: + /* Determine if a thread was interrupted and no preemption is required. */ + /* else if (((_tx_thread_current_ptr) && (_tx_thread_current_ptr == _tx_thread_execute_ptr) + || (_tx_thread_preempt_disable)) + { */ + + LOAD t1, _tx_thread_current_ptr // Pickup current thread pointer + beqz t1, _tx_thread_idle_system_restore // If NULL, idle system restore + + LOAD t2, _tx_thread_preempt_disable // Pickup preempt disable flag + bgtz t2, _tx_thread_no_preempt_restore // If set, restore interrupted thread + + LOAD t2, _tx_thread_execute_ptr // Pickup thread execute pointer + bne t1, t2, _tx_thread_preempt_restore // If higher-priority thread is ready, preempt + + +_tx_thread_no_preempt_restore: + /* Restore interrupted thread or ISR. */ + + /* Pickup the saved stack pointer. */ + /* SP = _tx_thread_current_ptr -> tx_thread_stack_ptr; */ + + LOAD sp, 2*REGBYTES(t1) // Switch back to thread's stack + + /* Recover floating point registers. */ +#if defined(__riscv_float_abi_single) + flw f0, 31*REGBYTES(sp) // Recover ft0 + flw f1, 32*REGBYTES(sp) // Recover ft1 + flw f2, 33*REGBYTES(sp) // Recover ft2 + flw f3, 34*REGBYTES(sp) // Recover ft3 + flw f4, 35*REGBYTES(sp) // Recover ft4 + flw f5, 36*REGBYTES(sp) // Recover ft5 + flw f6, 37*REGBYTES(sp) // Recover ft6 + flw f7, 38*REGBYTES(sp) // Recover ft7 + flw f10,41*REGBYTES(sp) // Recover fa0 + flw f11,42*REGBYTES(sp) // Recover fa1 + flw f12,43*REGBYTES(sp) // Recover fa2 + flw f13,44*REGBYTES(sp) // Recover fa3 + flw f14,45*REGBYTES(sp) // Recover fa4 + flw f15,46*REGBYTES(sp) // Recover fa5 + flw f16,47*REGBYTES(sp) // Recover fa6 + flw f17,48*REGBYTES(sp) // Recover fa7 + flw f28,59*REGBYTES(sp) // Recover ft8 + flw f29,60*REGBYTES(sp) // Recover ft9 + flw f30,61*REGBYTES(sp) // Recover ft10 + flw f31,62*REGBYTES(sp) // Recover ft11 + lw t0, 63*REGBYTES(sp) // Recover fcsr + csrw fcsr, t0 // +#elif defined(__riscv_float_abi_double) + fld f0, 31*REGBYTES(sp) // Recover ft0 + fld f1, 32*REGBYTES(sp) // Recover ft1 + fld f2, 33*REGBYTES(sp) // Recover ft2 + fld f3, 34*REGBYTES(sp) // Recover ft3 + fld f4, 35*REGBYTES(sp) // Recover ft4 + fld f5, 36*REGBYTES(sp) // Recover ft5 + fld f6, 37*REGBYTES(sp) // Recover ft6 + fld f7, 38*REGBYTES(sp) // Recover ft7 + fld f10,41*REGBYTES(sp) // Recover fa0 + fld f11,42*REGBYTES(sp) // Recover fa1 + fld f12,43*REGBYTES(sp) // Recover fa2 + fld f13,44*REGBYTES(sp) // Recover fa3 + fld f14,45*REGBYTES(sp) // Recover fa4 + fld f15,46*REGBYTES(sp) // Recover fa5 + fld f16,47*REGBYTES(sp) // Recover fa6 + fld f17,48*REGBYTES(sp) // Recover fa7 + fld f28,59*REGBYTES(sp) // Recover ft8 + fld f29,60*REGBYTES(sp) // Recover ft9 + fld f30,61*REGBYTES(sp) // Recover ft10 + fld f31,62*REGBYTES(sp) // Recover ft11 + LOAD t0, 63*REGBYTES(sp) // Recover fcsr + csrw fcsr, t0 // +#endif + + /* Recover the saved context and return to the point of interrupt. */ + + /* Recover standard registers. */ + /* Restore registers, + Skip global pointer because that does not change */ + + LOAD t0, 240(sp) // Recover mepc + csrw mepc, t0 // Setup mepc + li t0, 0x1880 // Prepare MPIP + csrw mstatus, t0 // Enable MPIP + + LOAD x1, 28*REGBYTES(sp) // Recover RA + LOAD x5, 19*REGBYTES(sp) // Recover t0 + LOAD x6, 18*REGBYTES(sp) // Recover t1 + LOAD x7, 17*REGBYTES(sp) // Recover t2 + LOAD x8, 12*REGBYTES(sp) // Recover s0 + LOAD x10, 27*REGBYTES(sp) // Recover a0 + LOAD x11, 26*REGBYTES(sp) // Recover a1 + LOAD x12, 25*REGBYTES(sp) // Recover a2 + LOAD x13, 24*REGBYTES(sp) // Recover a3 + LOAD x14, 23*REGBYTES(sp) // Recover a4 + LOAD x15, 22*REGBYTES(sp) // Recover a5 + LOAD x16, 21*REGBYTES(sp) // Recover a6 + LOAD x17, 20*REGBYTES(sp) // Recover a7 + LOAD x28, 16*REGBYTES(sp) // Recover t3 + LOAD x29, 15*REGBYTES(sp) // Recover t4 + LOAD x30, 14*REGBYTES(sp) // Recover t5 + LOAD x31, 13*REGBYTES(sp) // Recover t6 + +#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 stack frame - without floating point enabled +#endif + mret // Return to point of interrupt + + /* } + else + { */ +_tx_thread_preempt_restore: + /* Instead of directly activating the thread again, ensure we save the + entire stack frame by saving the remaining registers. */ + + LOAD t0, 2*REGBYTES(t1) // Pickup thread's stack pointer + ori t3, x0, 1 // Build interrupt stack type + STORE t3, 0(t0) // Store stack type + + /* Store floating point preserved registers. */ +#ifdef __riscv_float_abi_single + fsw f8, 39*REGBYTES(t0) // Store fs0 + fsw f9, 40*REGBYTES(t0) // Store fs1 + fsw f18, 49*REGBYTES(t0) // Store fs2 + fsw f19, 50*REGBYTES(t0) // Store fs3 + fsw f20, 51*REGBYTES(t0) // Store fs4 + fsw f21, 52*REGBYTES(t0) // Store fs5 + fsw f22, 53*REGBYTES(t0) // Store fs6 + fsw f23, 54*REGBYTES(t0) // Store fs7 + fsw f24, 55*REGBYTES(t0) // Store fs8 + fsw f25, 56*REGBYTES(t0) // Store fs9 + fsw f26, 57*REGBYTES(t0) // Store fs10 + fsw f27, 58*REGBYTES(t0) // Store fs11 +#elif defined(__riscv_float_abi_double) + fsd f8, 39*REGBYTES(t0) // Store fs0 + fsd f9, 40*REGBYTES(t0) // Store fs1 + fsd f18, 49*REGBYTES(t0) // Store fs2 + fsd f19, 50*REGBYTES(t0) // Store fs3 + fsd f20, 51*REGBYTES(t0) // Store fs4 + fsd f21, 52*REGBYTES(t0) // Store fs5 + fsd f22, 53*REGBYTES(t0) // Store fs6 + fsd f23, 54*REGBYTES(t0) // Store fs7 + fsd f24, 55*REGBYTES(t0) // Store fs8 + fsd f25, 56*REGBYTES(t0) // Store fs9 + fsd f26, 57*REGBYTES(t0) // Store fs10 + fsd f27, 58*REGBYTES(t0) // Store fs11 +#endif + + /* Store standard preserved registers. */ + + STORE x9, 11*REGBYTES(t0) // Store s1 + STORE x18, 10*REGBYTES(t0) // Store s2 + STORE x19, 9*REGBYTES(t0) // Store s3 + STORE x20, 8*REGBYTES(t0) // Store s4 + STORE x21, 7*REGBYTES(t0) // Store s5 + STORE x22, 6*REGBYTES(t0) // Store s6 + STORE x23, 5*REGBYTES(t0) // Store s7 + STORE x24, 4*REGBYTES(t0) // Store s8 + STORE x25, 3*REGBYTES(t0) // Store s9 + STORE x26, 2*REGBYTES(t0) // Store s10 + STORE x27, 1*REGBYTES(t0) // Store s11 + // Note: s0 is already stored! + + /* Save the remaining time-slice and disable it. */ + /* if (_tx_timer_time_slice) + { */ + + la t0, _tx_timer_time_slice // Pickup time slice variable address + LOAD t2, 0(t0) // Pickup time slice + beqz t2, _tx_thread_dont_save_ts // If 0, skip time slice processing + + /* _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice + _tx_timer_time_slice = 0; */ + + STORE t2, 6*REGBYTES(t1) // Save current time slice + STORE x0, 0(t0) // Clear global time slice + + + /* } */ +_tx_thread_dont_save_ts: + /* Clear the current task pointer. */ + /* _tx_thread_current_ptr = TX_NULL; */ + + /* Return to the scheduler. */ + /* _tx_thread_schedule(); */ + + STORE x0, _tx_thread_current_ptr, t0 // Clear current thread pointer*/ + /* } */ + +_tx_thread_idle_system_restore: + /* Just return back to the scheduler! */ + j _tx_thread_schedule // Return to scheduler + +/* } */ diff --git a/ports/risc-v64/gnu/src/tx_thread_context_save.S b/ports/risc-v64/gnu/src/tx_thread_context_save.S new file mode 100644 index 00000000..5e0e4be0 --- /dev/null +++ b/ports/risc-v64/gnu/src/tx_thread_context_save.S @@ -0,0 +1,284 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** 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 x5, 19*REGBYTES(sp) // First store t0 and t1 + STORE x6, 18*REGBYTES(sp) + + la x5, _tx_thread_system_state // Pickup address of system state + LOAD 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 + STORE 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. */ + + 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 x6, x6, 1 // Increment the interrupt counter + STORE x6, 0(x5) // Store the interrupt counter + + /* Not nested: Find the user thread that was running and load our SP */ + + LOAD 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. */ + + 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 diff --git a/ports/risc-v64/gnu/src/tx_thread_interrupt_control.S b/ports/risc-v64/gnu/src/tx_thread_interrupt_control.S new file mode 100644 index 00000000..d0a07636 --- /dev/null +++ b/ports/risc-v64/gnu/src/tx_thread_interrupt_control.S @@ -0,0 +1,82 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + + RETURN_MASK = 0x000000000000000F + SET_SR_MASK = 0xFFFFFFFFFFFFFFF0 + + .section .text +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_interrupt_control RISC-V64/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is responsible for changing the interrupt lockout */ +/* posture of the system. */ +/* */ +/* INPUT */ +/* */ +/* new_posture New interrupt lockout posture */ +/* */ +/* OUTPUT */ +/* */ +/* old_posture Old interrupt lockout posture */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* Application Code */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 03-08-2023 Scott Larson Initial Version 6.2.1 */ +/* */ +/**************************************************************************/ +/* UINT _tx_thread_interrupt_control(UINT new_posture) +{ */ + .global _tx_thread_interrupt_control +_tx_thread_interrupt_control: + /* Pickup current interrupt lockout posture. */ + + csrr t0, mstatus + mv t1, t0 // Save original mstatus for return + + /* Apply the new interrupt posture. */ + + li t2, SET_SR_MASK // Build set SR mask + and t0, t0, t2 // Isolate interrupt lockout bits + or t0, t0, a0 // Put new lockout bits in + csrw mstatus, t0 + andi a0, t1, RETURN_MASK // Return original mstatus. + ret +/* } */ diff --git a/ports/risc-v64/gnu/src/tx_thread_schedule.S b/ports/risc-v64/gnu/src/tx_thread_schedule.S new file mode 100644 index 00000000..2a2d4479 --- /dev/null +++ b/ports/risc-v64/gnu/src/tx_thread_schedule.S @@ -0,0 +1,302 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#include "tx_port.h" + + .section .text +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_schedule RISC-V64/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function waits for a thread control block pointer to appear in */ +/* the _tx_thread_execute_ptr variable. Once a thread pointer appears */ +/* in the variable, the corresponding thread is resumed. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_initialize_kernel_enter ThreadX entry function */ +/* _tx_thread_system_return Return to system from thread */ +/* _tx_thread_context_restore Restore thread's context */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 03-08-2023 Scott Larson Initial Version 6.2.1 */ +/* */ +/**************************************************************************/ +/* VOID _tx_thread_schedule(VOID) +{ */ + .global _tx_thread_schedule +_tx_thread_schedule: + + /* Enable interrupts. */ + csrsi mstatus, 0x08 // Enable interrupts + + /* Wait for a thread to execute. */ + /* do + { */ + + la t0, _tx_thread_execute_ptr // Pickup address of execute ptr +_tx_thread_schedule_loop: + LOAD t1, 0(t0) // Pickup next thread to execute + beqz t1, _tx_thread_schedule_loop // If NULL, wait for thread to execute + + /* } + while(_tx_thread_execute_ptr == TX_NULL); */ + + /* Yes! We have a thread to execute. Lockout interrupts and + transfer control to it. */ + csrci mstatus, 0x08 // Lockout interrupts + + /* Setup the current thread pointer. */ + /* _tx_thread_current_ptr = _tx_thread_execute_ptr; */ + + la t0, _tx_thread_current_ptr // Pickup current thread pointer address + STORE t1, 0(t0) // Set current thread pointer + + /* Increment the run count for this thread. */ + /* _tx_thread_current_ptr -> tx_thread_run_count++; */ + + LOAD t2, 1*REGBYTES(t1) // Pickup run count + LOAD t3, 6*REGBYTES(t1) // Pickup time slice value + addi t2, t2, 1 // Increment run count + STORE t2, 1*REGBYTES(t1) // Store new run count + + /* Setup time-slice, if present. */ + /* _tx_timer_time_slice = _tx_thread_current_ptr -> tx_thread_time_slice; */ + + la t2, _tx_timer_time_slice // Pickup time-slice variable address + + /* Switch to the thread's stack. */ + /* SP = _tx_thread_execute_ptr -> tx_thread_stack_ptr; */ + + LOAD sp, 2*REGBYTES(t1) // Switch to thread's stack + STORE t3, 0(t2) // Store new time-slice*/ + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + + call _tx_execution_thread_enter // Call the thread execution enter function +#endif + + /* Determine if an interrupt frame or a synchronous task suspension frame + is present. */ + + LOAD t2, 0(sp) // Pickup stack type + beqz t2, _tx_thread_synch_return // If 0, solicited thread return + + /* Determine if floating point registers need to be recovered. */ + +#if defined(__riscv_float_abi_single) + flw f0, 31*REGBYTES(sp) // Recover ft0 + flw f1, 32*REGBYTES(sp) // Recover ft1 + flw f2, 33*REGBYTES(sp) // Recover ft2 + flw f3, 34*REGBYTES(sp) // Recover ft3 + flw f4, 35*REGBYTES(sp) // Recover ft4 + flw f5, 36*REGBYTES(sp) // Recover ft5 + flw f6, 37*REGBYTES(sp) // Recover ft6 + flw f7, 38*REGBYTES(sp) // Recover ft7 + flw f8, 39*REGBYTES(sp) // Recover fs0 + flw f9, 40*REGBYTES(sp) // Recover fs1 + flw f10,41*REGBYTES(sp) // Recover fa0 + flw f11,42*REGBYTES(sp) // Recover fa1 + flw f12,43*REGBYTES(sp) // Recover fa2 + flw f13,44*REGBYTES(sp) // Recover fa3 + flw f14,45*REGBYTES(sp) // Recover fa4 + flw f15,46*REGBYTES(sp) // Recover fa5 + flw f16,47*REGBYTES(sp) // Recover fa6 + flw f17,48*REGBYTES(sp) // Recover fa7 + flw f18,49*REGBYTES(sp) // Recover fs2 + flw f19,50*REGBYTES(sp) // Recover fs3 + flw f20,51*REGBYTES(sp) // Recover fs4 + flw f21,52*REGBYTES(sp) // Recover fs5 + flw f22,53*REGBYTES(sp) // Recover fs6 + flw f23,54*REGBYTES(sp) // Recover fs7 + flw f24,55*REGBYTES(sp) // Recover fs8 + flw f25,56*REGBYTES(sp) // Recover fs9 + flw f26,57*REGBYTES(sp) // Recover fs10 + flw f27,58*REGBYTES(sp) // Recover fs11 + flw f28,59*REGBYTES(sp) // Recover ft8 + flw f29,60*REGBYTES(sp) // Recover ft9 + flw f30,61*REGBYTES(sp) // Recover ft10 + flw f31,62*REGBYTES(sp) // Recover ft11 + LOAD t0, 63*REGBYTES(sp) // Recover fcsr + csrw fcsr, t0 // +#elif defined(__riscv_float_abi_double) + fld f0, 31*REGBYTES(sp) // Recover ft0 + fld f1, 32*REGBYTES(sp) // Recover ft1 + fld f2, 33*REGBYTES(sp) // Recover ft2 + fld f3, 34*REGBYTES(sp) // Recover ft3 + fld f4, 35*REGBYTES(sp) // Recover ft4 + fld f5, 36*REGBYTES(sp) // Recover ft5 + fld f6, 37*REGBYTES(sp) // Recover ft6 + fld f7, 38*REGBYTES(sp) // Recover ft7 + fld f8, 39*REGBYTES(sp) // Recover fs0 + fld f9, 40*REGBYTES(sp) // Recover fs1 + fld f10,41*REGBYTES(sp) // Recover fa0 + fld f11,42*REGBYTES(sp) // Recover fa1 + fld f12,43*REGBYTES(sp) // Recover fa2 + fld f13,44*REGBYTES(sp) // Recover fa3 + fld f14,45*REGBYTES(sp) // Recover fa4 + fld f15,46*REGBYTES(sp) // Recover fa5 + fld f16,47*REGBYTES(sp) // Recover fa6 + fld f17,48*REGBYTES(sp) // Recover fa7 + fld f18,49*REGBYTES(sp) // Recover fs2 + fld f19,50*REGBYTES(sp) // Recover fs3 + fld f20,51*REGBYTES(sp) // Recover fs4 + fld f21,52*REGBYTES(sp) // Recover fs5 + fld f22,53*REGBYTES(sp) // Recover fs6 + fld f23,54*REGBYTES(sp) // Recover fs7 + fld f24,55*REGBYTES(sp) // Recover fs8 + fld f25,56*REGBYTES(sp) // Recover fs9 + fld f26,57*REGBYTES(sp) // Recover fs10 + fld f27,58*REGBYTES(sp) // Recover fs11 + fld f28,59*REGBYTES(sp) // Recover ft8 + fld f29,60*REGBYTES(sp) // Recover ft9 + fld f30,61*REGBYTES(sp) // Recover ft10 + fld f31,62*REGBYTES(sp) // Recover ft11 + LOAD t0, 63*REGBYTES(sp) // Recover fcsr +#endif + + /* Recover standard registers. */ + + LOAD t0, 30*REGBYTES(sp) // Recover mepc + csrw mepc, t0 // Store mepc + li t0, 0x1880 // Prepare MPIP + csrw mstatus, t0 // Enable MPIP + + LOAD x1, 28*REGBYTES(sp) // Recover RA + LOAD x5, 19*REGBYTES(sp) // Recover t0 + LOAD x6, 18*REGBYTES(sp) // Recover t1 + LOAD x7, 17*REGBYTES(sp) // Recover t2 + LOAD x8, 12*REGBYTES(sp) // Recover s0 + LOAD x9, 11*REGBYTES(sp) // Recover s1 + LOAD x10, 27*REGBYTES(sp) // Recover a0 + LOAD x11, 26*REGBYTES(sp) // Recover a1 + LOAD x12, 25*REGBYTES(sp) // Recover a2 + LOAD x13, 24*REGBYTES(sp) // Recover a3 + LOAD x14, 23*REGBYTES(sp) // Recover a4 + LOAD x15, 22*REGBYTES(sp) // Recover a5 + LOAD x16, 21*REGBYTES(sp) // Recover a6 + LOAD x17, 20*REGBYTES(sp) // Recover a7 + LOAD x18, 10*REGBYTES(sp) // Recover s2 + LOAD x19, 9*REGBYTES(sp) // Recover s3 + LOAD x20, 8*REGBYTES(sp) // Recover s4 + LOAD x21, 7*REGBYTES(sp) // Recover s5 + LOAD x22, 6*REGBYTES(sp) // Recover s6 + LOAD x23, 5*REGBYTES(sp) // Recover s7 + LOAD x24, 4*REGBYTES(sp) // Recover s8 + LOAD x25, 3*REGBYTES(sp) // Recover s9 + LOAD x26, 2*REGBYTES(sp) // Recover s10 + LOAD x27, 1*REGBYTES(sp) // Recover s11 + LOAD x28, 16*REGBYTES(sp) // Recover t3 + LOAD x29, 15*REGBYTES(sp) // Recover t4 + LOAD x30, 14*REGBYTES(sp) // Recover t5 + LOAD x31, 13*REGBYTES(sp) // Recover t6 + +#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double) + addi sp, sp, 65*REGBYTES // Recover stack frame - with floating point registers +#else + addi sp, sp, 32*REGBYTES // Recover stack frame - without floating point registers +#endif + mret // Return to point of interrupt + +_tx_thread_synch_return: + +#if defined(__riscv_float_abi_single) + flw f8, 15*REGBYTES(sp) // Recover fs0 + flw f9, 16*REGBYTES(sp) // Recover fs1 + flw f18,17*REGBYTES(sp) // Recover fs2 + flw f19,18*REGBYTES(sp) // Recover fs3 + flw f20,19*REGBYTES(sp) // Recover fs4 + flw f21,20*REGBYTES(sp) // Recover fs5 + flw f22,21*REGBYTES(sp) // Recover fs6 + flw f23,22*REGBYTES(sp) // Recover fs7 + flw f24,23*REGBYTES(sp) // Recover fs8 + flw f25,24*REGBYTES(sp) // Recover fs9 + flw f26,25*REGBYTES(sp) // Recover fs10 + flw f27,26*REGBYTES(sp) // Recover fs11 + LOAD t0, 27*REGBYTES(sp) // Recover fcsr + csrw fcsr, t0 // +#elif defined(__riscv_float_abi_double) + fld f8, 15*REGBYTES(sp) // Recover fs0 + fld f9, 16*REGBYTES(sp) // Recover fs1 + fld f18,17*REGBYTES(sp) // Recover fs2 + fld f19,18*REGBYTES(sp) // Recover fs3 + fld f20,19*REGBYTES(sp) // Recover fs4 + fld f21,20*REGBYTES(sp) // Recover fs5 + fld f22,21*REGBYTES(sp) // Recover fs6 + fld f23,22*REGBYTES(sp) // Recover fs7 + fld f24,23*REGBYTES(sp) // Recover fs8 + fld f25,24*REGBYTES(sp) // Recover fs9 + fld f26,25*REGBYTES(sp) // Recover fs10 + fld f27,26*REGBYTES(sp) // Recover fs11 + LOAD t0, 27*REGBYTES(sp) // Recover fcsr + csrw fcsr, t0 // +#endif + + /* Recover standard preserved registers. */ + /* Recover standard registers. */ + + LOAD x1, 13*REGBYTES(sp) // Recover RA + LOAD x8, 12*REGBYTES(sp) // Recover s0 + LOAD x9, 11*REGBYTES(sp) // Recover s1 + LOAD x18, 10*REGBYTES(sp) // Recover s2 + LOAD x19, 9*REGBYTES(sp) // Recover s3 + LOAD x20, 8*REGBYTES(sp) // Recover s4 + LOAD x21, 7*REGBYTES(sp) // Recover s5 + LOAD x22, 6*REGBYTES(sp) // Recover s6 + LOAD x23, 5*REGBYTES(sp) // Recover s7 + LOAD x24, 4*REGBYTES(sp) // Recover s8 + LOAD x25, 3*REGBYTES(sp) // Recover s9 + LOAD x26, 2*REGBYTES(sp) // Recover s10 + LOAD x27, 1*REGBYTES(sp) // Recover s11 + LOAD t0, 14*REGBYTES(sp) // Recover mstatus + csrw mstatus, t0 // Store mstatus, enables interrupt +#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double) + addi sp, sp, 29*REGBYTES // Recover stack frame +#else + addi sp, sp, 16*REGBYTES // Recover stack frame +#endif + ret // Return to thread + +/* } */ diff --git a/ports/risc-v64/gnu/src/tx_thread_stack_build.S b/ports/risc-v64/gnu/src/tx_thread_stack_build.S new file mode 100644 index 00000000..32c36c6c --- /dev/null +++ b/ports/risc-v64/gnu/src/tx_thread_stack_build.S @@ -0,0 +1,229 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#include "tx_port.h" + + .section .text +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_stack_build RISC-V64/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function builds a stack frame on the supplied thread's stack. */ +/* The stack frame results in a fake interrupt return to the supplied */ +/* function pointer. */ +/* */ +/* INPUT */ +/* */ +/* thread_ptr Pointer to thread control blk */ +/* function_ptr Pointer to return function */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* None */ +/* */ +/* CALLED BY */ +/* */ +/* _tx_thread_create Create thread service */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 03-08-2023 Scott Larson Initial Version 6.2.1 */ +/* */ +/**************************************************************************/ +/* VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID)) +{ */ + .global _tx_thread_stack_build +_tx_thread_stack_build: + + /* Build a fake interrupt frame. The form of the fake interrupt stack + on the RISC-V should look like the following after it is built: + Reg Index + Stack Top: 1 0 Interrupt stack frame type + x27 1 Initial s11 + x26 2 Initial s10 + x25 3 Initial s9 + x24 4 Initial s8 + x23 5 Initial s7 + x22 6 Initial s6 + x21 7 Initial s5 + x20 8 Initial s4 + x19 9 Initial s3 + x18 10 Initial s2 + x9 11 Initial s1 + x8 12 Initial s0 + x31 13 Initial t6 + x30 14 Initial t5 + x29 15 Initial t4 + x28 16 Initial t3 + x7 17 Initial t2 + x6 18 Initial t1 + x5 19 Initial t0 + x17 20 Initial a7 + x16 21 Initial a6 + x15 22 Initial a5 + x14 23 Initial a4 + x13 24 Initial a3 + x12 25 Initial a2 + x11 26 Initial a1 + x10 27 Initial a0 + x1 28 Initial ra + -- 29 reserved + mepc 30 Initial mepc +If floating point support: + f0 31 Inital ft0 + f1 32 Inital ft1 + f2 33 Inital ft2 + f3 34 Inital ft3 + f4 35 Inital ft4 + f5 36 Inital ft5 + f6 37 Inital ft6 + f7 38 Inital ft7 + f8 39 Inital fs0 + f9 40 Inital fs1 + f10 41 Inital fa0 + f11 42 Inital fa1 + f12 43 Inital fa2 + f13 44 Inital fa3 + f14 45 Inital fa4 + f15 46 Inital fa5 + f16 47 Inital fa6 + f17 48 Inital fa7 + f18 49 Inital fs2 + f19 50 Inital fs3 + f20 51 Inital fs4 + f21 52 Inital fs5 + f22 53 Inital fs6 + f23 54 Inital fs7 + f24 55 Inital fs8 + f25 56 Inital fs9 + f26 57 Inital fs10 + f27 58 Inital fs11 + f28 59 Inital ft8 + f29 60 Inital ft9 + f30 61 Inital ft10 + f31 62 Inital ft11 + fscr 63 Inital fscr + + Stack Bottom: (higher memory address) */ + + LOAD t0, 4*REGBYTES(a0) // Pickup end of stack area + li t1, ~15 // Build 16-byte alignment mask + and t0, t0, t1 // Make sure 16-byte alignment + + /* Actually build the stack frame. */ + +#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double) + addi t0, t0, -65*REGBYTES +#else + addi t0, t0, -32*REGBYTES // Allocate space for the stack frame +#endif + li t1, 1 // Build stack type + STORE t1, 0*REGBYTES(t0) // Place stack type on the top + STORE x0, 1*REGBYTES(t0) // Initial s11 + STORE x0, 2*REGBYTES(t0) // Initial s10 + STORE x0, 3*REGBYTES(t0) // Initial s9 + STORE x0, 4*REGBYTES(t0) // Initial s8 + STORE x0, 5*REGBYTES(t0) // Initial s7 + STORE x0, 6*REGBYTES(t0) // Initial s6 + STORE x0, 7*REGBYTES(t0) // Initial s5 + STORE x0, 8*REGBYTES(t0) // Initial s4 + STORE x0, 9*REGBYTES(t0) // Initial s3 + STORE x0, 10*REGBYTES(t0) // Initial s2 + STORE x0, 11*REGBYTES(t0) // Initial s1 + STORE x0, 12*REGBYTES(t0) // Initial s0 + STORE x0, 13*REGBYTES(t0) // Initial t6 + STORE x0, 14*REGBYTES(t0) // Initial t5 + STORE x0, 15*REGBYTES(t0) // Initial t4 + STORE x0, 16*REGBYTES(t0) // Initial t3 + STORE x0, 17*REGBYTES(t0) // Initial t2 + STORE x0, 18*REGBYTES(t0) // Initial t1 + STORE x0, 19*REGBYTES(t0) // Initial t0 + STORE x0, 20*REGBYTES(t0) // Initial a7 + STORE x0, 21*REGBYTES(t0) // Initial a6 + STORE x0, 22*REGBYTES(t0) // Initial a5 + STORE x0, 23*REGBYTES(t0) // Initial a4 + STORE x0, 24*REGBYTES(t0) // Initial a3 + STORE x0, 25*REGBYTES(t0) // Initial a2 + STORE x0, 26*REGBYTES(t0) // Initial a1 + STORE x0, 27*REGBYTES(t0) // Initial a0 + STORE x0, 28*REGBYTES(t0) // Initial ra + STORE a1, 30*REGBYTES(t0) // Initial mepc +#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double) + STORE x0, 31*REGBYTES(t0) // Inital ft0 + STORE x0, 32*REGBYTES(t0) // Inital ft1 + STORE x0, 33*REGBYTES(t0) // Inital ft2 + STORE x0, 34*REGBYTES(t0) // Inital ft3 + STORE x0, 35*REGBYTES(t0) // Inital ft4 + STORE x0, 36*REGBYTES(t0) // Inital ft5 + STORE x0, 37*REGBYTES(t0) // Inital ft6 + STORE x0, 38*REGBYTES(t0) // Inital ft7 + STORE x0, 39*REGBYTES(t0) // Inital fs0 + STORE x0, 40*REGBYTES(t0) // Inital fs1 + STORE x0, 41*REGBYTES(t0) // Inital fa0 + STORE x0, 42*REGBYTES(t0) // Inital fa1 + STORE x0, 43*REGBYTES(t0) // Inital fa2 + STORE x0, 44*REGBYTES(t0) // Inital fa3 + STORE x0, 45*REGBYTES(t0) // Inital fa4 + STORE x0, 46*REGBYTES(t0) // Inital fa5 + STORE x0, 47*REGBYTES(t0) // Inital fa6 + STORE x0, 48*REGBYTES(t0) // Inital fa7 + STORE x0, 49*REGBYTES(t0) // Inital fs2 + STORE x0, 50*REGBYTES(t0) // Inital fs3 + STORE x0, 51*REGBYTES(t0) // Inital fs4 + STORE x0, 52*REGBYTES(t0) // Inital fs5 + STORE x0, 53*REGBYTES(t0) // Inital fs6 + STORE x0, 54*REGBYTES(t0) // Inital fs7 + STORE x0, 55*REGBYTES(t0) // Inital fs8 + STORE x0, 56*REGBYTES(t0) // Inital fs9 + STORE x0, 57*REGBYTES(t0) // Inital fs10 + STORE x0, 58*REGBYTES(t0) // Inital fs11 + STORE x0, 59*REGBYTES(t0) // Inital ft8 + STORE x0, 60*REGBYTES(t0) // Inital ft9 + STORE x0, 61*REGBYTES(t0) // Inital ft10 + STORE x0, 62*REGBYTES(t0) // Inital ft11 + csrr a1, fcsr // Read fcsr and use it for initial value for each thread + STORE a1, 63*REGBYTES(t0) // Initial fscr + STORE x0, 64*REGBYTES(t0) // Reserved word (0) +#else + STORE x0, 31*REGBYTES(t0) // Reserved word (0) +#endif + + /* Setup stack pointer. */ + /* thread_ptr -> tx_thread_stack_ptr = t0; */ + + STORE t0, 2*REGBYTES(a0) // Save stack pointer in thread's + ret // control block and return +/* } */ diff --git a/ports/risc-v64/gnu/src/tx_thread_system_return.S b/ports/risc-v64/gnu/src/tx_thread_system_return.S new file mode 100644 index 00000000..c2b239da --- /dev/null +++ b/ports/risc-v64/gnu/src/tx_thread_system_return.S @@ -0,0 +1,175 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Thread */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#include "tx_port.h" + + .section .text +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_thread_system_return RISC-V64/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function is target processor specific. It is used to transfer */ +/* control from a thread back to the system. Only a minimal context */ +/* is saved since the compiler assumes temp registers are going to get */ +/* slicked by a function call anyway. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_thread_schedule Thread scheduling loop */ +/* */ +/* CALLED BY */ +/* */ +/* ThreadX components */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 03-08-2023 Scott Larson Initial Version 6.2.1 */ +/* */ +/**************************************************************************/ +/* VOID _tx_thread_system_return(VOID) +{ */ + .global _tx_thread_system_return +_tx_thread_system_return: + + /* Save minimal context on the stack. */ + +#if defined(__riscv_float_abi_single) || defined(__riscv_float_abi_double) + addi sp, sp, -29*REGBYTES // Allocate space on the stack - with floating point enabled +#else + addi sp, sp, -16*REGBYTES // Allocate space on the stack - without floating point enabled +#endif + + /* Store floating point preserved registers. */ +#if defined(__riscv_float_abi_single) + fsw f8, 15*REGBYTES(sp) // Store fs0 + fsw f9, 16*REGBYTES(sp) // Store fs1 + fsw f18, 17*REGBYTES(sp) // Store fs2 + fsw f19, 18*REGBYTES(sp) // Store fs3 + fsw f20, 19*REGBYTES(sp) // Store fs4 + fsw f21, 20*REGBYTES(sp) // Store fs5 + fsw f22, 21*REGBYTES(sp) // Store fs6 + fsw f23, 22*REGBYTES(sp) // Store fs7 + fsw f24, 23*REGBYTES(sp) // Store fs8 + fsw f25, 24*REGBYTES(sp) // Store fs9 + fsw f26, 25*REGBYTES(sp) // Store fs10 + fsw f27, 26*REGBYTES(sp) // Store fs11 + csrr t0, fcsr + STORE t0, 27*REGBYTES(sp) // Store fcsr +#elif defined(__riscv_float_abi_double) + fsd f8, 15*REGBYTES(sp) // Store fs0 + fsd f9, 16*REGBYTES(sp) // Store fs1 + fsd f18, 17*REGBYTES(sp) // Store fs2 + fsd f19, 18*REGBYTES(sp) // Store fs3 + fsd f20, 19*REGBYTES(sp) // Store fs4 + fsd f21, 20*REGBYTES(sp) // Store fs5 + fsd f22, 21*REGBYTES(sp) // Store fs6 + fsd f23, 22*REGBYTES(sp) // Store fs7 + fsd f24, 23*REGBYTES(sp) // Store fs8 + fsd f25, 24*REGBYTES(sp) // Store fs9 + fsd f26, 25*REGBYTES(sp) // Store fs10 + fsd f27, 26*REGBYTES(sp) // Store fs11 + csrr t0, fcsr + STORE t0, 27*REGBYTES(sp) // Store fcsr +#endif + + STORE x0, 0(sp) // Solicited stack type + STORE x1, 13*REGBYTES(sp) // Save RA + STORE x8, 12*REGBYTES(sp) // Save s0 + STORE x9, 11*REGBYTES(sp) // Save s1 + STORE x18, 10*REGBYTES(sp) // Save s2 + STORE x19, 9*REGBYTES(sp) // Save s3 + STORE x20, 8*REGBYTES(sp) // Save s4 + STORE x21, 7*REGBYTES(sp) // Save s5 + STORE x22, 6*REGBYTES(sp) // Save s6 + STORE x23, 5*REGBYTES(sp) // Save s7 + STORE x24, 4*REGBYTES(sp) // Save s8 + STORE x25, 3*REGBYTES(sp) // Save s9 + STORE x26, 2*REGBYTES(sp) // Save s10 + STORE x27, 1*REGBYTES(sp) // Save s11 + csrr t0, mstatus // Pickup mstatus + STORE t0, 14*REGBYTES(sp) // Save mstatus + + + /* Lockout interrupts. - will be enabled in _tx_thread_schedule */ + + csrci mstatus, 0xF + +#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY + + call _tx_execution_thread_exit // Call the thread execution exit function +#endif + + la t0, _tx_thread_current_ptr // Pickup address of pointer + LOAD t1, 0(t0) // Pickup current thread pointer + la t2,_tx_thread_system_stack_ptr // Pickup stack pointer address + + /* Save current stack and switch to system stack. */ + /* _tx_thread_current_ptr -> tx_thread_stack_ptr = SP; + SP = _tx_thread_system_stack_ptr; */ + + STORE sp, 2*REGBYTES(t1) // Save stack pointer + LOAD sp, 0(t2) // Switch to system stack + + /* Determine if the time-slice is active. */ + /* if (_tx_timer_time_slice) + { */ + + la t4, _tx_timer_time_slice // Pickup time slice variable addr + LOAD t3, 0(t4) // Pickup time slice value + la t2, _tx_thread_schedule // Pickup address of scheduling loop + beqz t3, _tx_thread_dont_save_ts // If no time-slice, don't save it + + /* Save time-slice for the thread and clear the current time-slice. */ + /* _tx_thread_current_ptr -> tx_thread_time_slice = _tx_timer_time_slice; + _tx_timer_time_slice = 0; */ + + STORE t3, 6*REGBYTES(t1) // Save current time-slice for thread + STORE x0, 0(t4) // Clear time-slice variable + + /* } */ +_tx_thread_dont_save_ts: + + /* Clear the current thread pointer. */ + /* _tx_thread_current_ptr = TX_NULL; */ + + STORE x0, 0(t0) // Clear current thread pointer + jr t2 // Return to thread scheduler + +/* } */ diff --git a/ports/risc-v64/gnu/src/tx_timer_interrupt.c b/ports/risc-v64/gnu/src/tx_timer_interrupt.c new file mode 100644 index 00000000..a92eb5e9 --- /dev/null +++ b/ports/risc-v64/gnu/src/tx_timer_interrupt.c @@ -0,0 +1,135 @@ +/**************************************************************************/ +/* */ +/* Copyright (c) Microsoft Corporation. All rights reserved. */ +/* */ +/* This software is licensed under the Microsoft Software License */ +/* Terms for Microsoft Azure RTOS. Full text of the license can be */ +/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */ +/* and in the root directory of this software. */ +/* */ +/**************************************************************************/ + + +/**************************************************************************/ +/**************************************************************************/ +/** */ +/** ThreadX Component */ +/** */ +/** Timer */ +/** */ +/**************************************************************************/ +/**************************************************************************/ + +#define TX_SOURCE_CODE + +/* Include necessary system files. */ + +#include "tx_api.h" +#include "tx_timer.h" +#include "tx_thread.h" + +/**************************************************************************/ +/* */ +/* FUNCTION RELEASE */ +/* */ +/* _tx_timer_interrupt RISC-V64/GNU */ +/* 6.2.1 */ +/* AUTHOR */ +/* */ +/* Scott Larson, Microsoft Corporation */ +/* */ +/* DESCRIPTION */ +/* */ +/* This function processes the hardware timer interrupt. This */ +/* processing includes incrementing the system clock and checking for */ +/* time slice and/or timer expiration. If either is found, the */ +/* interrupt context save/restore functions are called along with the */ +/* expiration functions. */ +/* */ +/* INPUT */ +/* */ +/* None */ +/* */ +/* OUTPUT */ +/* */ +/* None */ +/* */ +/* CALLS */ +/* */ +/* _tx_timer_expiration_process Timer expiration processing */ +/* _tx_thread_time_slice Time slice interrupted thread */ +/* */ +/* CALLED BY */ +/* */ +/* interrupt vector */ +/* */ +/* RELEASE HISTORY */ +/* */ +/* DATE NAME DESCRIPTION */ +/* */ +/* 03-08-2023 Scott Larson Initial Version 6.2.1 */ +/* */ +/**************************************************************************/ +VOID _tx_timer_interrupt(VOID) +{ + /* Increment system clock. */ + _tx_timer_system_clock++; + + /* Test for time-slice expiration. */ + if (_tx_timer_time_slice) + { + /* Decrement the time_slice. */ + _tx_timer_time_slice--; + + /* Check for expiration. */ + if (_tx_timer_time_slice == 0) + { + + /* Set the time-slice expired flag. */ + _tx_timer_expired_time_slice = TX_TRUE; + } + } + + /* Test for timer expiration. */ + if (*_tx_timer_current_ptr) + { + + /* Set expiration flag. */ + _tx_timer_expired = TX_TRUE; + } + else + { + + /* No timer expired, increment the timer pointer. */ + _tx_timer_current_ptr++; + + /* Check for wrap-around. */ + if (_tx_timer_current_ptr == _tx_timer_list_end) + { + + /* Wrap to beginning of list. */ + _tx_timer_current_ptr = _tx_timer_list_start; + } + } + + /* See if anything has expired. */ + if ((_tx_timer_expired_time_slice) || (_tx_timer_expired)) + { + + /* Did a timer expire? */ + if (_tx_timer_expired) + { + + /* Process timer expiration. */ + _tx_timer_expiration_process(); + } + + /* Did time slice expire? */ + if (_tx_timer_expired_time_slice) + { + + /* Time slice interrupted thread. */ + _tx_thread_time_slice(); + } + } +} |
