Release 6.1.7

This commit is contained in:
Bo Chen
2021-06-02 06:45:05 +00:00
parent d759e6bb9e
commit f5056f4923
1269 changed files with 57325 additions and 55178 deletions

View File

@@ -26,11 +26,11 @@
/* PORT SPECIFIC C INFORMATION RELEASE */
/* */
/* tx_port.h Cortex-M4/AC6 */
/* 6.1.6 */
/* 6.1.7 */
/* */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
@@ -43,14 +43,14 @@
/* own special types that can be mapped to actual data types by this */
/* file to guarantee consistency in the interface and functionality. */
/* */
/* This file replaces the previous Cortex-M3/M4/M7 files. It unifies */
/* the ARMv7-M architecture and compilers into one common file. */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 09-30-2020 William E. Lamie Initial Version 6.1 */
/* 04-02-2021 Bhupendra Naphade Modified comment(s),updated */
/* macro definition, */
/* resulting in version 6.1.6 */
/* 06-02-2021 Scott Larson Initial Version 6.1.7 */
/* */
/**************************************************************************/
@@ -62,7 +62,7 @@
#ifdef TX_INCLUDE_USER_DEFINE_FILE
/* Yes, include the user defines in tx_user.h. The defines in this file may
/* Yes, include the user defines in tx_user.h. The defines in this file may
alternately be defined on the command line. */
#include "tx_user.h"
@@ -74,6 +74,28 @@
#include <stdlib.h>
#include <string.h>
#ifdef __ICCARM__
#include <intrinsics.h> /* IAR Intrinsics */
#define __asm__ __asm /* Define to make all inline asm look similar */
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#include <yvals.h>
#endif
#endif /* __ICCARM__ */
#ifdef __ghs__
#include <arm_ghs.h>
#include "tx_ghs.h"
#endif /* __ghs__ */
#if !defined(__GNUC__) && !defined(__CC_ARM)
#define __get_control_value __get_CONTROL
#define __set_control_value __set_CONTROL
#endif
#ifndef __GNUC__
#define __get_ipsr_value __get_IPSR
#endif
/* Define ThreadX basic types for this port. */
@@ -84,9 +106,10 @@ typedef int INT;
typedef unsigned int UINT;
typedef long LONG;
typedef unsigned long ULONG;
typedef unsigned long long ULONG64;
typedef short SHORT;
typedef unsigned short USHORT;
#define ULONG64_DEFINED
/* Define the priority levels for ThreadX. Legal values range
from 32 to 1024 and MUST be evenly divisible by 32. */
@@ -111,19 +134,19 @@ typedef unsigned short USHORT;
#define TX_TIMER_THREAD_STACK_SIZE 1024 /* Default timer thread stack size */
#endif
#ifndef TX_TIMER_THREAD_PRIORITY
#ifndef TX_TIMER_THREAD_PRIORITY
#define TX_TIMER_THREAD_PRIORITY 0 /* Default timer thread priority */
#endif
/* Define various constants for the ThreadX Cortex-M7 port. */
/* Define various constants for the ThreadX Cortex-M port. */
#define TX_INT_DISABLE 1 /* Disable interrupts */
#define TX_INT_ENABLE 0 /* Enable interrupts */
/* Define the clock source for trace event entry time stamp. The following two item are port specific.
For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock
/* Define the clock source for trace event entry time stamp. The following two item are port specific.
For example, if the time source is at the address 0x0a800024 and is 16-bits in size, the clock
source constants would be:
#define TX_TRACE_TIME_SOURCE *((ULONG *) 0x0a800024)
@@ -131,46 +154,83 @@ typedef unsigned short USHORT;
*/
#ifndef TX_MISRA_ENABLE
#ifndef TX_TRACE_TIME_SOURCE
#define TX_TRACE_TIME_SOURCE *((ULONG *) 0xE0001004)
#define TX_TRACE_TIME_SOURCE *((ULONG *) 0xE0001004)
#endif
#else
ULONG _tx_misra_time_stamp_get(VOID);
#define TX_TRACE_TIME_SOURCE _tx_misra_time_stamp_get()
#endif
#ifndef TX_TRACE_TIME_MASK
#define TX_TRACE_TIME_MASK 0xFFFFFFFFUL
#endif
#ifdef __ghs__
/* Define constants for Green Hills EventAnalyzer. */
/* Define the number of ticks per second. This informs the EventAnalyzer what the timestamps
represent. By default, this is set to 1,000,000 i.e., one tick every microsecond. */
#define TX_EL_TICKS_PER_SECOND 1000000
/* Define the method of how to get the upper and lower 32-bits of the time stamp. By default, simply
simulate the time-stamp source with a counter. */
#define read_tbu() _tx_el_time_base_upper
#define read_tbl() ++_tx_el_time_base_lower
#endif /* __ghs__ */
/* Define the port specific options for the _tx_build_options variable. This variable indicates
how the ThreadX library was built. */
#define TX_PORT_SPECIFIC_BUILD_OPTIONS 0
#define TX_PORT_SPECIFIC_BUILD_OPTIONS (0)
/* Define the in-line initialization constant so that modules with in-line
initialization capabilities can prevent their initialization from being
a function call. */
#ifdef TX_MISRA_ENABLE
#define TX_DISABLE_INLINE
#else
#define TX_INLINE_INITIALIZATION
#endif
/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is
/* Determine whether or not stack checking is enabled. By default, ThreadX stack checking is
disabled. When the following is defined, ThreadX thread stack checking is enabled. If stack
checking is enabled (TX_ENABLE_STACK_CHECKING is defined), the TX_DISABLE_STACK_FILLING
define is negated, thereby forcing the stack fill which is necessary for the stack checking
logic. */
#ifndef TX_MISRA_ENABLE
#ifdef TX_ENABLE_STACK_CHECKING
#undef TX_DISABLE_STACK_FILLING
#endif
#endif
/* Define the TX_THREAD control block extensions for this port. The main reason
for the multiple macros is so that backward compatibility can be maintained with
for the multiple macros is so that backward compatibility can be maintained with
existing ThreadX kernel awareness modules. */
#define TX_THREAD_EXTENSION_0
#define TX_THREAD_EXTENSION_1
#define TX_THREAD_EXTENSION_2
#define TX_THREAD_EXTENSION_3
#define TX_THREAD_EXTENSION_0
#define TX_THREAD_EXTENSION_1
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#define TX_THREAD_EXTENSION_2 VOID *tx_thread_iar_tls_pointer;
#elif defined(__ghs__)
#define TX_THREAD_EXTENSION_2 VOID * tx_thread_eh_globals; \
int Errno; /* errno. */ \
char * strtok_saved_pos; /* strtok() position. */
#else
#define TX_THREAD_EXTENSION_2
#endif
#define TX_THREAD_EXTENSION_3
/* Define the port extensions of the remaining ThreadX objects. */
@@ -184,11 +244,11 @@ typedef unsigned short USHORT;
#define TX_TIMER_EXTENSION
/* Define the user extension field of the thread control block. Nothing
/* Define the user extension field of the thread control block. Nothing
additional is needed for this port so it is defined as white space. */
#ifndef TX_THREAD_USER_EXTENSION
#define TX_THREAD_USER_EXTENSION
#define TX_THREAD_USER_EXTENSION
#endif
@@ -196,12 +256,28 @@ typedef unsigned short USHORT;
tx_thread_shell_entry, and tx_thread_terminate. */
#define TX_THREAD_CREATE_EXTENSION(thread_ptr)
#define TX_THREAD_DELETE_EXTENSION(thread_ptr)
#ifdef TX_ENABLE_IAR_LIBRARY_SUPPORT
#if (__VER__ < 8000000)
#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = __iar_dlib_perthread_allocate();
#define TX_THREAD_DELETE_EXTENSION(thread_ptr) __iar_dlib_perthread_deallocate(thread_ptr -> tx_thread_iar_tls_pointer); \
thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL;
#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION __iar_dlib_perthread_access(0);
#else
void *_tx_iar_create_per_thread_tls_area(void);
void _tx_iar_destroy_per_thread_tls_area(void *tls_ptr);
void __iar_Initlocks(void);
#define TX_THREAD_CREATE_EXTENSION(thread_ptr) thread_ptr -> tx_thread_iar_tls_pointer = _tx_iar_create_per_thread_tls_area();
#define TX_THREAD_DELETE_EXTENSION(thread_ptr) do {_tx_iar_destroy_per_thread_tls_area(thread_ptr -> tx_thread_iar_tls_pointer); \
thread_ptr -> tx_thread_iar_tls_pointer = TX_NULL; } while(0);
#define TX_PORT_SPECIFIC_PRE_SCHEDULER_INITIALIZATION do {__iar_Initlocks();} while(0);
#endif
#else
#define TX_THREAD_CREATE_EXTENSION(thread_ptr)
#define TX_THREAD_DELETE_EXTENSION(thread_ptr)
#endif
#ifdef TX_ENABLE_FPU_SUPPORT
#if defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__TARGET_FPU_VFP) || defined(__VFP__)
#ifdef TX_MISRA_ENABLE
@@ -210,26 +286,49 @@ void _tx_misra_control_set(ULONG value);
ULONG _tx_misra_fpccr_get(void);
void _tx_misra_vfp_touch(void);
#else
#else /* TX_MISRA_ENABLE not defined */
__attribute__( ( always_inline ) ) static inline ULONG __get_control(void)
/* Define some helper functions (these are intrinsics in some compilers). */
#ifdef __GNUC__ /* GCC and ARM Compiler 6 */
__attribute__( ( always_inline ) ) static inline ULONG __get_control_value(void)
{
ULONG control_value;
__asm__ volatile (" MRS %0,CONTROL ": "=r" (control_value) );
return(control_value);
}
__attribute__( ( always_inline ) ) static inline void __set_control(ULONG control_value)
__attribute__( ( always_inline ) ) static inline void __set_control_value(ULONG control_value)
{
__asm__ volatile (" MSR CONTROL,%0": : "r" (control_value): "memory" );
}
#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0");
#endif
#elif defined(__CC_ARM) /* ARM Compiler 5 */
__attribute__( ( always_inline ) ) ULONG __get_control_value(void)
{
ULONG control_value;
__asm volatile ("MRS control_value,CONTROL");
return(control_value);
}
__attribute__( ( always_inline ) ) void __set_control_value(ULONG control_value)
{
__asm__ volatile ("MSR CONTROL,control_value");
}
/* Can't access VFP registers with inline asm, so define this in tx_thread_schedule. */
void _tx_vfp_access(void);
#define TX_VFP_TOUCH() _tx_vfp_access();
#elif defined(__ICCARM__) /* IAR */
#define TX_VFP_TOUCH() __asm__ volatile ("VMOV.F32 s0, s0");
#endif /* Helper functions for different compilers */
#endif /* TX_MISRA_ENABLE */
/* A completed thread falls into _thread_shell_entry and we can simply deactivate the FPU via CONTROL.FPCA
@@ -237,23 +336,22 @@ __attribute__( ( always_inline ) ) static inline void __set_control(ULONG contro
#ifndef TX_MISRA_ENABLE
#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \
ULONG _tx_vfp_state; \
_tx_vfp_state = __get_control(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
__set_control(_tx_vfp_state); \
}
#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \
ULONG _tx_vfp_state; \
_tx_vfp_state = __get_control_value(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
__set_control_value(_tx_vfp_state); \
}
#else
#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \
ULONG _tx_vfp_state; \
_tx_vfp_state = _tx_misra_control_get(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
_tx_misra_control_set(_tx_vfp_state); \
}
#endif
#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr) { \
ULONG _tx_vfp_state; \
_tx_vfp_state = _tx_misra_control_get(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
_tx_misra_control_set(_tx_vfp_state); \
}
#endif
/* A thread can be terminated by another thread, so we first check if it's self-terminating and not in an ISR.
If so, deactivate the FPU via CONTROL.FPCA. Otherwise we are in an interrupt or another thread is terminating
@@ -262,79 +360,76 @@ __attribute__( ( always_inline ) ) static inline void __set_control(ULONG contro
#ifndef TX_MISRA_ENABLE
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \
ULONG _tx_system_state; \
_tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \
if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \
{ \
ULONG _tx_vfp_state; \
_tx_vfp_state = __get_control(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
__set_control(_tx_vfp_state); \
} \
else \
{ \
ULONG _tx_fpccr; \
_tx_fpccr = *((ULONG *) 0xE000EF34); \
_tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \
if (_tx_fpccr == ((ULONG) 0x01)) \
{ \
ULONG _tx_vfp_state; \
_tx_vfp_state = __get_control(); \
_tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \
__asm__ volatile ("vmov.f32 s0, s0"); \
if (_tx_vfp_state == ((ULONG) 0)) \
{ \
_tx_vfp_state = __get_control(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
__set_control(_tx_vfp_state); \
} \
} \
} \
}
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \
ULONG _tx_system_state; \
_tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \
if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \
{ \
ULONG _tx_vfp_state; \
_tx_vfp_state = __get_control_value(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
__set_control_value(_tx_vfp_state); \
} \
else \
{ \
ULONG _tx_fpccr; \
_tx_fpccr = *((ULONG *) 0xE000EF34); \
_tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \
if (_tx_fpccr == ((ULONG) 0x01)) \
{ \
ULONG _tx_vfp_state; \
_tx_vfp_state = __get_control_value(); \
_tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \
TX_VFP_TOUCH(); \
if (_tx_vfp_state == ((ULONG) 0)) \
{ \
_tx_vfp_state = __get_control_value(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
__set_control_value(_tx_vfp_state); \
} \
} \
} \
}
#else
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \
ULONG _tx_system_state; \
_tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \
if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \
{ \
ULONG _tx_vfp_state; \
_tx_vfp_state = _tx_misra_control_get(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
_tx_misra_control_set(_tx_vfp_state); \
} \
else \
{ \
ULONG _tx_fpccr; \
_tx_fpccr = _tx_misra_fpccr_get(); \
_tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \
if (_tx_fpccr == ((ULONG) 0x01)) \
{ \
ULONG _tx_vfp_state; \
_tx_vfp_state = _tx_misra_control_get(); \
_tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \
_tx_misra_vfp_touch(); \
if (_tx_vfp_state == ((ULONG) 0)) \
{ \
_tx_vfp_state = _tx_misra_control_get(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
_tx_misra_control_set(_tx_vfp_state); \
} \
} \
} \
}
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr) { \
ULONG _tx_system_state; \
_tx_system_state = TX_THREAD_GET_SYSTEM_STATE(); \
if ((_tx_system_state == ((ULONG) 0)) && ((thread_ptr) == _tx_thread_current_ptr)) \
{ \
ULONG _tx_vfp_state; \
_tx_vfp_state = _tx_misra_control_get(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
_tx_misra_control_set(_tx_vfp_state); \
} \
else \
{ \
ULONG _tx_fpccr; \
_tx_fpccr = _tx_misra_fpccr_get(); \
_tx_fpccr = _tx_fpccr & ((ULONG) 0x01); \
if (_tx_fpccr == ((ULONG) 0x01)) \
{ \
ULONG _tx_vfp_state; \
_tx_vfp_state = _tx_misra_control_get(); \
_tx_vfp_state = _tx_vfp_state & ((ULONG) 0x4); \
_tx_misra_vfp_touch(); \
if (_tx_vfp_state == ((ULONG) 0)) \
{ \
_tx_vfp_state = _tx_misra_control_get(); \
_tx_vfp_state = _tx_vfp_state & ~((ULONG) 0x4); \
_tx_misra_control_set(_tx_vfp_state); \
} \
} \
} \
}
#endif
#else
#else /* No VFP in use */
#define TX_THREAD_COMPLETED_EXTENSION(thread_ptr)
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr)
#endif
#define TX_THREAD_TERMINATED_EXTENSION(thread_ptr)
#endif /* defined(__ARMVFP__) || defined(__ARM_PCS_VFP) || defined(__TARGET_FPU_VFP) || defined(__VFP__) */
/* Define the ThreadX object creation extensions for the remaining objects. */
@@ -359,126 +454,242 @@ __attribute__( ( always_inline ) ) static inline void __set_control(ULONG contro
#define TX_TIMER_DELETE_EXTENSION(timer_ptr)
/* Define the get system state macro. */
/* Define the get system state macro. */
#ifndef TX_THREAD_GET_SYSTEM_STATE
#ifndef TX_MISRA_ENABLE
#ifdef __CC_ARM /* ARM Compiler 5 */
register unsigned int _ipsr __asm("ipsr");
#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _ipsr)
#elif defined(__GNUC__) /* GCC and ARM Compiler 6 */
__attribute__( ( always_inline ) ) static inline unsigned int __get_ipsr_value(void)
{
unsigned int ipsr_value;
__asm__ volatile (" MRS %0,IPSR ": "=r" (ipsr_value) );
return(ipsr_value);
}
#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_ipsr_value())
#else
#elif defined(__ICCARM__) /* IAR */
#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | __get_IPSR())
#endif /* TX_THREAD_GET_SYSTEM_STATE for different compilers */
#else /* TX_MISRA_ENABLE is defined, use MISRA function. */
ULONG _tx_misra_ipsr_get(VOID);
#define TX_THREAD_GET_SYSTEM_STATE() (_tx_thread_system_state | _tx_misra_ipsr_get())
#endif
#endif
#endif /* TX_MISRA_ENABLE */
#endif /* TX_THREAD_GET_SYSTEM_STATE */
/* Define the check for whether or not to call the _tx_thread_system_return function. A non-zero value
indicates that _tx_thread_system_return should not be called. */
indicates that _tx_thread_system_return should not be called. This overrides the definition in tx_thread.h
for Cortex-M since so we don't waste time checking the _tx_thread_system_state variable that is always
zero after initialization for Cortex-M ports. */
#ifndef TX_THREAD_SYSTEM_RETURN_CHECK
#define TX_THREAD_SYSTEM_RETURN_CHECK(c) (c) = ((ULONG) _tx_thread_preempt_disable);
#endif
/* Define the macro to ensure _tx_thread_preempt_disable is set early in initialization in order to
/* Define the macro to ensure _tx_thread_preempt_disable is set early in initialization in order to
prevent early scheduling on Cortex-M parts. */
#define TX_PORT_SPECIFIC_POST_INITIALIZATION _tx_thread_preempt_disable++;
/* This ARM architecture has the CLZ instruction. This is available on
architectures v5 and above. If available, redefine the macro for calculating the
lowest bit set. */
#ifndef TX_DISABLE_INLINE
/* Define the TX_LOWEST_SET_BIT_CALCULATE macro for each compiler. */
#ifdef __ICCARM__ /* IAR Compiler */
#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __CLZ(__RBIT((m)));
#elif defined(__CC_ARM) /* AC5 Compiler */
#define TX_LOWEST_SET_BIT_CALCULATE(m, b) (b) = (UINT) __clz(__rbit((m)));
#elif defined(__GNUC__) /* GCC and AC6 Compiler */
#define TX_LOWEST_SET_BIT_CALCULATE(m, b) __asm__ volatile (" RBIT %0,%1 ": "=r" (m) : "r" (m) ); \
__asm__ volatile (" CLZ %0,%1 ": "=r" (b) : "r" (m) );
#endif
#ifndef TX_DISABLE_INLINE
/* Define AC6 specific macros, with in-line assembly for performance. */
/* Define the interrupt disable/restore macros for each compiler. */
#if defined(__GNUC__) || defined(__ICCARM__)
/*** GCC/AC6 and IAR ***/
__attribute__( ( always_inline ) ) static inline unsigned int __get_interrupt_posture(void)
{
unsigned int posture;
#ifdef TX_PORT_USE_BASEPRI
__asm__ volatile ("MRS %0, BASEPRI ": "=r" (posture));
#else
__asm__ volatile ("MRS %0, PRIMASK ": "=r" (posture));
#endif
return(posture);
}
#ifdef TX_PORT_USE_BASEPRI
__attribute__( ( always_inline ) ) static inline void __set_basepri_value(unsigned int basepri_value)
{
__asm__ volatile ("MSR BASEPRI,%0 ": : "r" (basepri_value));
}
#else
__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void)
{
__asm__ volatile ("CPSIE i": : : "memory");
}
#endif
__attribute__( ( always_inline ) ) static inline void __restore_interrupt(unsigned int int_posture)
{
#ifdef TX_PORT_USE_BASEPRI
__set_basepri_value(int_posture);
//__asm__ volatile ("MSR BASEPRI,%0": : "r" (int_posture): "memory");
#else
__asm__ volatile ("MSR PRIMASK,%0": : "r" (int_posture): "memory");
#endif
}
__attribute__( ( always_inline ) ) static inline unsigned int __disable_interrupts(void)
{
unsigned int int_posture;
unsigned int primask_value;
int_posture = __get_interrupt_posture();
__asm__ volatile (" MRS %0,PRIMASK ": "=r" (primask_value) );
__asm__ volatile (" CPSID i" : : : "memory" );
return(primask_value);
#ifdef TX_PORT_USE_BASEPRI
__set_basepri_value(TX_PORT_BASEPRI);
#else
__asm__ volatile ("CPSID i" : : : "memory");
#endif
return(int_posture);
}
__attribute__( ( always_inline ) ) static inline void __restore_interrupts(unsigned int primask_value)
{
__asm__ volatile (" MSR PRIMASK,%0": : "r" (primask_value): "memory" );
}
__attribute__( ( always_inline ) ) static inline unsigned int __get_primask_value(void)
{
unsigned int primask_value;
__asm__ volatile (" MRS %0,PRIMASK ": "=r" (primask_value) );
return(primask_value);
}
__attribute__( ( always_inline ) ) static inline void __enable_interrupts(void)
{
__asm__ volatile (" CPSIE i": : : "memory" );
}
__attribute__( ( always_inline ) ) static inline void _tx_thread_system_return_inline(void)
{
unsigned int interrupt_save;
/* Set PendSV to invoke ThreadX scheduler. */
*((ULONG *) 0xE000ED04) = ((ULONG) 0x10000000);
if (__get_ipsr_value() == 0)
{
interrupt_save = __get_primask_value();
interrupt_save = __get_interrupt_posture();
#ifdef TX_PORT_USE_BASEPRI
__set_basepri_value(0);
#else
__enable_interrupts();
__restore_interrupts(interrupt_save);
}
#endif
__restore_interrupt(interrupt_save);
}
}
#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save;
#define TX_DISABLE interrupt_save = __disable_interrupts();
#define TX_RESTORE __restore_interrupt(interrupt_save);
/*** End GCC/AC6 and IAR ***/
#elif defined(__CC_ARM)
/*** AC5 ***/
static __inline unsigned int __get_interrupt_posture(void)
{
unsigned int posture;
#ifdef TX_PORT_USE_BASEPRI
__asm__ volatile ("MRS #posture, BASEPRI");
#else
__asm__ volatile ("MRS #posture, PRIMASK");
#endif
return(posture);
}
#ifdef TX_PORT_USE_BASEPRI
static __inline void __set_basepri_value(unsigned int basepri_value)
{
__asm__ volatile ("MSR BASEPRI, #basepri_value");
}
#endif
static __inline unsigned int __disable_interrupts(void)
{
unsigned int int_posture;
int_posture = __get_interrupt_posture();
#ifdef TX_PORT_USE_BASEPRI
__set_basepri_value(TX_PORT_BASEPRI);
#else
__asm__ volatile ("CPSID i");
#endif
return(int_posture);
}
static __inline void __restore_interrupt(unsigned int int_posture)
{
#ifdef TX_PORT_USE_BASEPRI
__set_basepri_value(int_posture);
#else
__asm__ volatile ("MSR PRIMASK, #int_posture");
#endif
}
static void _tx_thread_system_return_inline(void)
{
unsigned int interrupt_save;
/* Set PendSV to invoke ThreadX scheduler. */
*((ULONG *) 0xE000ED04) = ((ULONG) 0x10000000);
if (_ipsr == 0)
{
#ifdef TX_PORT_USE_BASEPRI
interrupt_save = __get_interrupt_posture();
__set_basepri_value(0);
__set_basepri_value(interrupt_save);
#else
interrupt_save = __disable_irq();
__enable_irq();
if (interrupt_save != 0)
__disable_irq();
#endif
}
}
#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save;
#define TX_INTERRUPT_SAVE_AREA unsigned int interrupt_save;
#define TX_DISABLE interrupt_save = __disable_interrupts();
#define TX_RESTORE __restore_interrupt(interrupt_save);
#define TX_DISABLE interrupt_save = __disable_interrupts();
#define TX_RESTORE __restore_interrupts(interrupt_save);
/*** End AC5 ***/
#endif /* Interrupt disable/restore macros for each compiler. */
/* Redefine _tx_thread_system_return for improved performance. */
#define _tx_thread_system_return _tx_thread_system_return_inline
#else
#else /* TX_DISABLE_INLINE is defined */
#define TX_INTERRUPT_SAVE_AREA UINT interrupt_save;
UINT _tx_thread_interrupt_disable(VOID);
VOID _tx_thread_interrupt_restore(UINT previous_posture);
#define TX_DISABLE interrupt_save = _tx_thread_interrupt_control(TX_INT_DISABLE);
#define TX_RESTORE _tx_thread_interrupt_control(interrupt_save);
#endif
#define TX_INTERRUPT_SAVE_AREA register UINT interrupt_save;
#define TX_DISABLE interrupt_save = _tx_thread_interrupt_disable();
#define TX_RESTORE _tx_thread_interrupt_restore(interrupt_save);
#endif /* TX_DISABLE_INLINE */
/* Define FPU extension for the Cortex-M4. Each is assumed to be called in the context of the executing
thread. This is for legacy only, and not needed anylonger. */
/* Define FPU extension for the Cortex-M. Each is assumed to be called in the context of the executing
thread. These are no longer needed, but are preserved for backward compatibility only. */
void tx_thread_fpu_enable(void);
void tx_thread_fpu_disable(void);
@@ -487,16 +698,15 @@ void tx_thread_fpu_disable(void);
/* Define the version ID of ThreadX. This may be utilized by the application. */
#ifdef TX_THREAD_INIT
CHAR _tx_version_id[] =
"Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX Cortex-M4/AC6 Version 6.1.6 *";
CHAR _tx_version_id[] =
"Copyright (c) Microsoft Corporation. All rights reserved. * ThreadX Cortex-M4/AC6 Version 6.1.7 *";
#else
#ifdef TX_MISRA_ENABLE
extern CHAR _tx_version_id[100];
#else
extern CHAR _tx_version_id[];
#endif
#endif
#endif

View File

@@ -1,41 +1,39 @@
Microsoft's Azure RTOS ThreadX for Cortex-M4
Microsoft's Azure RTOS ThreadX for ARMv7-M
(Cortex-M3, Cortex-M4, Cortex-M7)
Using ARM Compiler 6 (AC6)
Using the AC6 Tools
1. Import the ThreadX Projects
1. Building the ThreadX run-time Library
In order to build the ThreadX library and the ThreadX demonstration, first import
the 'tx' and 'sample_threadx' projects (located in the "example_build" directory)
into your DS workspace.
2. Building the ThreadX run-time Library
Building the ThreadX library is easy; simply right-click the Eclipse project
"tx" and then select the "Build Project" button. You should now observe the compilation
and assembly of the ThreadX library. This project build produces the ThreadX
library file tx.a.
3. Demonstration System
2. Demonstration System
The ThreadX demonstration is designed to execute under the DS debugger on the
MPS2_Cortex_M4 Bare Metal simulator.
MPS2_Cortex_Mx Bare Metal simulator.
Building the demonstration is easy; simply right-click the Eclipse project
"sample_threadx" and then select the "Build Project" button. You should now observe
the compilation and assembly of the ThreadX demonstration. This project build produces
the ThreadX library file sample_threadx.axf. Next, expand the demo ThreadX project folder
in the Project Explorer window, right-click on the 'cortex-m4_tx.launch' file, click
'Debug As', and then click 'cortex-m4_tx' from the submenu. This will cause the
in the Project Explorer window, right-click on the 'cortex-mx_tx.launch' file, click
'Debug As', and then click 'cortex-mx_tx' from the submenu. This will cause the
debugger to load the sample_threadx.axf ELF file and run to main. You are now ready
to execute the ThreadX demonstration.
4. System Initialization
3. System Initialization
The entry point in ThreadX for the Cortex-M4 using AC6 tools uses the standard AC6
Cortex-M4 reset sequence. From the reset vector the C runtime will be initialized.
The entry point in ThreadX for the Cortex-M using AC6 tools uses the standard GNU
Cortex-M reset sequence. From the reset vector the C runtime will be initialized.
The ThreadX tx_initialize_low_level.S file is responsible for setting up
various system data structures, the vector area, and a periodic timer interrupt
@@ -46,11 +44,11 @@ address for use by the application, which is supplied as the sole input
parameter to your application definition function, tx_application_define.
5. Register Usage and Stack Frames
4. Register Usage and Stack Frames
The following defines the saved context stack frames for context switches
that occur as a result of interrupt handling or from thread-level API calls.
All suspended threads have the same stack frame in the Cortex-M4 version of
All suspended threads have the same stack frame in the Cortex-M version of
ThreadX. The top of the suspended thread's stack is pointed to by
tx_thread_stack_ptr in the associated thread control block TX_THREAD.
@@ -58,7 +56,7 @@ Non-FPU Stack Frame:
Stack Offset Stack Contents
0x00 LR Interrupted LR (LR at time of PENDSV)
0x00 lr Interrupted lr (lr at time of PENDSV)
0x04 r4 Software stacked GP registers
0x08 r5
0x0C r6
@@ -80,7 +78,7 @@ FPU Stack Frame (only interrupted thread with FPU enabled):
Stack Offset Stack Contents
0x00 LR Interrupted LR (LR at time of PENDSV)
0x00 lr Interrupted lr (lr at time of PENDSV)
0x04 s16 Software stacked FPU registers
0x08 s17
0x0C s18
@@ -132,57 +130,47 @@ FPU Stack Frame (only interrupted thread with FPU enabled):
0xC4 fpscr
6. Improving Performance
5. Improving Performance
The distribution version of ThreadX is built without any compiler optimizations.
This makes it easy to debug because you can trace or set breakpoints inside of
ThreadX itself. Of course, this costs some performance. To make it run faster,
you can change the build_threadx.bat file to remove the -g option and enable
all compiler optimizations.
The distribution version of ThreadX is built without any compiler
optimizations. This makes it easy to debug because you can trace or set
breakpoints inside of ThreadX itself. Of course, this costs some
performance. To make it run faster, you can change the ThreadX library
project to enable various compiler optimizations.
In addition, you can eliminate the ThreadX basic API error checking by
compiling your application code with the symbol TX_DISABLE_ERROR_CHECKING
defined.
7. Interrupt Handling
6. Interrupt Handling
ThreadX provides complete and high-performance interrupt handling for Cortex-M4
ThreadX provides complete and high-performance interrupt handling for Cortex-M
targets. There are a certain set of requirements that are defined in the
following sub-sections:
7.1 Vector Area
6.1 Vector Area
The Cortex-M4 vectors start at the label __tx_vectors or similar. The application may modify
The Cortex-M vectors start at the label __tx_vectors or similar. The application may modify
the vector area according to its needs. There is code in tx_initialize_low_level() that will
configure the vector base register.
7.2 Managed Interrupts
6.2 Managed Interrupts
ISRs can be written completely in C (or assembly language) without any calls to
_tx_thread_context_save or _tx_thread_context_restore. These ISRs are allowed access to the
ThreadX API that is available to ISRs.
ISRs written in C will take the form (where "your_C_isr" is an entry in the vector table):
void your_C_isr(void)
{
/* ISR processing goes here, including any needed function calls. */
}
ISRs written in assembly language will take the form:
A ThreadX managed interrupt is defined below. By following these conventions, the
application ISR is then allowed access to various ThreadX services from the ISR.
Here is the standard template for managed ISRs in ThreadX:
.global your_assembly_isr
.global __tx_IntHandler
.thumb_func
your_assembly_isr:
; VOID your_assembly_isr(VOID)
__tx_IntHandler:
; VOID InterruptHandler (VOID)
; {
PUSH {r0, lr}
;
; /* Do interrupt handler work here */
; /* BL <your interrupt routine in C> */
@@ -190,37 +178,31 @@ your_assembly_isr:
BX lr
; }
Note: the Cortex-M4 requires exception handlers to be thumb labels, this implies bit 0 set.
Note: the Cortex-M requires exception handlers to be thumb labels, this implies bit 0 set.
To accomplish this, the declaration of the label has to be preceded by the assembler directive
.thumb_func to instruct the linker to create thumb labels. The label __tx_IntHandler needs to
be inserted in the correct location in the interrupt vector table. This table is typically
located in either your runtime startup file or in the tx_initialize_low_level.S file.
8. FPU Support
7. FPU Support
ThreadX for Cortex-M4 supports automatic ("lazy") VFP support, which means that applications threads
ThreadX for Cortex-M supports automatic ("lazy") VFP support, which means that applications threads
can simply use the VFP and ThreadX automatically maintains the VFP registers as part of the thread
context. If saving the context of the FPU registers is needed, the ThreadX library should be re-built
with TX_ENABLE_FPU_SUPPORT defined.
context - no additional setup by the application.
9. Revision History
8. Revision History
For generic code revision information, please refer to the readme_threadx_generic.txt
file, which is included in your distribution. The following details the revision
information associated with this specific port of ThreadX:
04-02-2021 Release 6.1.6 changes:
tx_port.h Updated macro definition
03-02-2021 The following files were changed/added for version 6.1.5:
tx_thread_schedule.s Added low power feature
09-30-2020 Initial ThreadX 6.1 version for Cortex-M4 using AC6 tools.
06-02-2021 Initial ThreadX version 6.1.7 for Cortex-M using AC6 tools.
Copyright(c) 1996-2020 Microsoft Corporation
Copyright(c) 1996-2021 Microsoft Corporation
https://azure.com/rtos

View File

@@ -1,86 +1,81 @@
@/**************************************************************************/
@/* */
@/* 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 */
@/** */
@/**************************************************************************/
@/**************************************************************************/
@
@
.global _tx_thread_system_state
.global _tx_thread_current_ptr
.global _tx_thread_system_stack_ptr
.global _tx_thread_execute_ptr
.global _tx_timer_time_slice
.global _tx_thread_schedule
.global _tx_thread_preempt_disable
@
@
/**************************************************************************/
/* */
/* 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 */
/** */
/**************************************************************************/
/**************************************************************************/
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
.global _tx_execution_isr_exit
#endif
.text
.align 4
.syntax unified
@/**************************************************************************/
@/* */
@/* FUNCTION RELEASE */
@/* */
@/* _tx_thread_context_restore Cortex-M4/AC6 */
@/* 6.1 */
@/* AUTHOR */
@/* */
@/* William E. Lamie, Microsoft Corporation */
@/* */
@/* DESCRIPTION */
@/* */
@/* This function is only needed for legacy applications and it should */
@/* not be called in any new development on a Cortex-M. */
@/* 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 */
@/* */
@/* 09-30-2020 William E. Lamie Initial Version 6.1 */
@/* */
@/**************************************************************************/
@VOID _tx_thread_context_restore(VOID)
@{
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_context_restore Cortex-M4/AC6 */
/* 6.1.7 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is only needed for legacy applications and it should */
/* not be called in any new development on a Cortex-M. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* [_tx_execution_isr_exit] Execution profiling ISR exit */
/* */
/* CALLED BY */
/* */
/* ISRs Interrupt Service Routines */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 06-02-2021 Scott Larson Initial Version 6.1.7 */
/* */
/**************************************************************************/
// VOID _tx_thread_context_restore(VOID)
// {
.global _tx_thread_context_restore
.thumb_func
_tx_thread_context_restore:
@
@ /* Not needed for this port - just return! */
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the ISR exit function to indicate an ISR is complete. */
PUSH {r0, lr} // Save return address
BL _tx_execution_isr_exit // Call the ISR exit function
POP {r0, lr} // Recover return address
#endif
BX lr
@}
// }

View File

@@ -1,80 +1,83 @@
@/**************************************************************************/
@/* */
@/* 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 */
@/** */
@/**************************************************************************/
@/**************************************************************************/
@
@
.global _tx_thread_system_state
.global _tx_thread_current_ptr
@
@
/**************************************************************************/
/* */
/* 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 */
/** */
/**************************************************************************/
/**************************************************************************/
.text
.align 4
.syntax unified
@/**************************************************************************/
@/* */
@/* FUNCTION RELEASE */
@/* */
@/* _tx_thread_context_save Cortex-M4/AC6 */
@/* 6.1 */
@/* AUTHOR */
@/* */
@/* William E. Lamie, Microsoft Corporation */
@/* */
@/* DESCRIPTION */
@/* */
@/* This function is only needed for legacy applications and it should */
@/* not be called in any new development on a Cortex-M. */
@/* 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)
@{
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
.global _tx_execution_isr_enter
#endif
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_context_save Cortex-M4/AC6 */
/* 6.1.7 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is only needed for legacy applications and it should */
/* not be called in any new development on a Cortex-M. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* ISRs */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 06-02-2021 Scott Larson Initial Version 6.1.7 */
/* */
/**************************************************************************/
// VOID _tx_thread_context_save(VOID)
// {
.global _tx_thread_context_save
.thumb_func
_tx_thread_context_save:
@
@ /* Not needed for this port - just return! */
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the ISR enter function to indicate an ISR is starting. */
PUSH {r0, lr} // Save return address
BL _tx_execution_isr_enter // Call the ISR enter function
POP {r0, lr} // Recover return address
#endif
/* Context is already saved - just return. */
BX lr
@}
// }

View File

@@ -1,81 +1,79 @@
@/**************************************************************************/
@/* */
@/* 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. */
@/* */
@/**************************************************************************/
/**************************************************************************/
/* */
/* 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 */
@/** */
@/**************************************************************************/
@/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** ThreadX Component */
/** */
/** Thread */
/** */
/**************************************************************************/
/**************************************************************************/
.text 32
.align 4
.syntax unified
@/**************************************************************************/
@/* */
@/* FUNCTION RELEASE */
@/* */
@/* _tx_thread_interrupt_control Cortex-M4/AC6 */
@/* 6.1 */
@/* AUTHOR */
@/* */
@/* William E. Lamie, 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 */
@/* */
@/* 09-30-2020 William E. Lamie Initial Version 6.1 */
@/* */
@/**************************************************************************/
@/* UINT _tx_thread_interrupt_control(UINT new_posture)
{ */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_interrupt_control Cortex-M4/AC6 */
/* 6.1.7 */
/* 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 */
/* */
/* 06-02-2021 Scott Larson Initial Version 6.1.7 */
/* */
/**************************************************************************/
// UINT _tx_thread_interrupt_control(UINT new_posture)
// {
.global _tx_thread_interrupt_control
.thumb_func
_tx_thread_interrupt_control:
@/* Pickup current interrupt lockout posture. */
MRS r1, PRIMASK @ Pickup current interrupt lockout
@/* Apply the new interrupt posture. */
MSR PRIMASK, r0 @ Apply the new interrupt lockout
MOV r0, r1 @ Transfer old to return register
BX lr @ Return to caller
@/* } */
#ifdef TX_PORT_USE_BASEPRI
MRS r1, BASEPRI // Pickup current interrupt posture
MSR BASEPRI, r0 // Apply the new interrupt posture
MOV r0, r1 // Transfer old to return register
#else
MRS r1, PRIMASK // Pickup current interrupt lockout
MSR PRIMASK, r0 // Apply the new interrupt lockout
MOV r0, r1 // Transfer old to return register
#endif
BX lr // Return to caller
// }

View File

@@ -0,0 +1,79 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/**************************************************************************/
/**************************************************************************/
.text 32
.align 4
.syntax unified
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_interrupt_disable Cortex-M4/AC6 */
/* 6.1.7 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is responsible for disabling interrupts and returning */
/* the previous interrupt lockout posture. */
/* */
/* INPUT */
/* */
/* None */
/* */
/* OUTPUT */
/* */
/* old_posture Old interrupt lockout posture */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 06-02-2021 Scott Larson Initial Version 6.1.7 */
/* */
/**************************************************************************/
// UINT _tx_thread_interrupt_disable(VOID)
// {
.global _tx_thread_interrupt_disable
.thumb_func
_tx_thread_interrupt_disable:
/* Return current interrupt lockout posture. */
#ifdef TX_PORT_USE_BASEPRI
MRS r0, BASEPRI
LDR r1, =TX_PORT_BASEPRI
MSR BASEPRI, r1
#else
MRS r0, PRIMASK
CPSID i
#endif
BX lr
// }

View File

@@ -0,0 +1,76 @@
/**************************************************************************/
/* */
/* 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 */
/** */
/**************************************************************************/
/**************************************************************************/
.text 32
.align 4
.syntax unified
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_interrupt_restore Cortex-M4/AC6 */
/* 6.1.7 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is responsible for restoring the previous */
/* interrupt lockout posture. */
/* */
/* INPUT */
/* */
/* previous_posture Previous interrupt posture */
/* */
/* OUTPUT */
/* */
/* None */
/* */
/* CALLS */
/* */
/* None */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 06-02-2021 Scott Larson Initial Version 6.1.7 */
/* */
/**************************************************************************/
// VOID _tx_thread_interrupt_restore(UINT previous_posture)
// {
.global _tx_thread_interrupt_restore
.thumb_func
_tx_thread_interrupt_restore:
/* Restore previous interrupt lockout posture. */
#ifdef TX_PORT_USE_BASEPRI
MSR BASEPRI, r0
#else
MSR PRIMASK, r0
#endif
BX lr
// }

View File

@@ -1,304 +1,286 @@
@/**************************************************************************/
@/* */
@/* 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 */
@/** */
@/**************************************************************************/
@/**************************************************************************/
@
@
.global _tx_thread_current_ptr
.global _tx_thread_execute_ptr
.global _tx_timer_time_slice
.global _tx_thread_system_stack_ptr
/**************************************************************************/
/* */
/* 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 */
/** */
/**************************************************************************/
/**************************************************************************/
.global _tx_thread_current_ptr
.global _tx_thread_execute_ptr
.global _tx_timer_time_slice
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
.global _tx_execution_thread_enter
.global _tx_execution_thread_exit
#endif
#ifdef TX_LOW_POWER
.global tx_low_power_enter
.global tx_low_power_exit
#endif
@
@
.text
.align 4
.syntax unified
@/**************************************************************************/
@/* */
@/* FUNCTION RELEASE */
@/* */
@/* _tx_thread_schedule Cortex-M4/AC6 */
@/* 6.1.5 */
@/* AUTHOR */
@/* */
@/* William E. Lamie, 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 */
@/* */
@/* 09-30-2020 William E. Lamie Initial Version 6.1 */
@/* 03-02-2021 Scott Larson Modified comment(s), add */
@/* low power code, */
@/* resulting in version 6.1.5 */
@/* */
@/**************************************************************************/
@VOID _tx_thread_schedule(VOID)
@{
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_schedule Cortex-M4/AC6 */
/* 6.1.7 */
/* 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 */
/* */
/* 06-02-2021 Scott Larson Initial Version 6.1.7 */
/* */
/**************************************************************************/
// VOID _tx_thread_schedule(VOID)
// {
.global _tx_thread_schedule
.thumb_func
_tx_thread_schedule:
@
@ /* This function should only ever be called on Cortex-M4
@ from the first schedule request. Subsequent scheduling occurs
@ from the PendSV handling routines below. */
@
@ /* Clear the preempt-disable flag to enable rescheduling after initialization on Cortex-M targets. */
@
MOV r0, #0 @ Build value for TX_FALSE
LDR r2, =_tx_thread_preempt_disable @ Build address of preempt disable flag
STR r0, [r2, #0] @ Clear preempt disable flag
@
@ /* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */
@
#ifdef TX_ENABLE_FPU_SUPPORT
MRS r0, CONTROL @ Pickup current CONTROL register
BIC r0, r0, #4 @ Clear the FPCA bit
MSR CONTROL, r0 @ Setup new CONTROL register
/* This function should only ever be called on Cortex-M
from the first schedule request. Subsequent scheduling occurs
from the PendSV handling routine below. */
/* Clear the preempt-disable flag to enable rescheduling after initialization on Cortex-M targets. */
MOV r0, #0 // Build value for TX_FALSE
LDR r2, =_tx_thread_preempt_disable // Build address of preempt disable flag
STR r0, [r2, #0] // Clear preempt disable flag
/* Clear CONTROL.FPCA bit so VFP registers aren't unnecessarily stacked. */
#ifdef __ARM_PCS_VFP
MRS r0, CONTROL // Pickup current CONTROL register
BIC r0, r0, #4 // Clear the FPCA bit
MSR CONTROL, r0 // Setup new CONTROL register
#endif
@
@ /* Enable interrupts */
@
/* Enable interrupts */
CPSIE i
@
@ /* Enter the scheduler for the first time. */
@
MOV r0, #0x10000000 @ Load PENDSVSET bit
MOV r1, #0xE000E000 @ Load NVIC base
STR r0, [r1, #0xD04] @ Set PENDSVBIT in ICSR
DSB @ Complete all memory accesses
ISB @ Flush pipeline
@
@ /* Wait here for the PendSV to take place. */
@
/* Enter the scheduler for the first time. */
MOV r0, #0x10000000 // Load PENDSVSET bit
MOV r1, #0xE000E000 // Load NVIC base
STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR
DSB // Complete all memory accesses
ISB // Flush pipeline
/* Wait here for the PendSV to take place. */
__tx_wait_here:
B __tx_wait_here @ Wait for the PendSV to happen
@}
@
@ /* Generic context switch-out switch-in handler... Note that this handler is
@ common for both PendSV and SVCall. */
@
B __tx_wait_here // Wait for the PendSV to happen
// }
/* Generic context switching PendSV handler. */
.global PendSV_Handler
.global __tx_PendSVHandler
.syntax unified
.thumb_func
PendSV_Handler:
.thumb_func
__tx_PendSVHandler:
@
@ /* Get current thread value and new thread pointer. */
@
/* Get current thread value and new thread pointer. */
__tx_ts_handler:
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
@
@ /* Call the thread exit function to indicate the thread is no longer executing. */
@
CPSID i @ Disable interrupts
PUSH {r0, lr} @ Save LR (and r0 just for alignment)
BL _tx_execution_thread_exit @ Call the thread exit function
POP {r0, lr} @ Recover LR
CPSIE i @ Enable interrupts
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread exit function to indicate the thread is no longer executing. */
CPSID i // Disable interrupts
PUSH {r0, lr} // Save LR (and r0 just for alignment)
BL _tx_execution_thread_exit // Call the thread exit function
POP {r0, lr} // Recover LR
CPSIE i // Enable interrupts
#endif
LDR r0, =_tx_thread_current_ptr @ Build current thread pointer address
LDR r2, =_tx_thread_execute_ptr @ Build execute thread pointer address
MOV r3, #0 @ Build NULL value
LDR r1, [r0] @ Pickup current thread pointer
@
@ /* Determine if there is a current thread to finish preserving. */
@
CBZ r1, __tx_ts_new @ If NULL, skip preservation
@
@ /* Recover PSP and preserve current thread context. */
@
STR r3, [r0] @ Set _tx_thread_current_ptr to NULL
MRS r12, PSP @ Pickup PSP pointer (thread's stack pointer)
STMDB r12!, {r4-r11} @ Save its remaining registers
#ifdef TX_ENABLE_FPU_SUPPORT
TST LR, #0x10 @ Determine if the VFP extended frame is present
LDR r0, =_tx_thread_current_ptr // Build current thread pointer address
LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address
MOV r3, #0 // Build NULL value
LDR r1, [r0] // Pickup current thread pointer
/* Determine if there is a current thread to finish preserving. */
CBZ r1, __tx_ts_new // If NULL, skip preservation
/* Recover PSP and preserve current thread context. */
STR r3, [r0] // Set _tx_thread_current_ptr to NULL
MRS r12, PSP // Pickup PSP pointer (thread's stack pointer)
STMDB r12!, {r4-r11} // Save its remaining registers
#ifdef __ARM_PCS_VFP
TST LR, #0x10 // Determine if the VFP extended frame is present
BNE _skip_vfp_save
VSTMDB r12!,{s16-s31} @ Yes, save additional VFP registers
VSTMDB r12!,{s16-s31} // Yes, save additional VFP registers
_skip_vfp_save:
#endif
LDR r4, =_tx_timer_time_slice @ Build address of time-slice variable
STMDB r12!, {LR} @ Save LR on the stack
@
@ /* Determine if time-slice is active. If it isn't, skip time handling processing. */
@
LDR r5, [r4] @ Pickup current time-slice
STR r12, [r1, #8] @ Save the thread stack pointer
CBZ r5, __tx_ts_new @ If not active, skip processing
@
@ /* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable. */
@
STR r5, [r1, #24] @ Save current time-slice
@
@ /* Clear the global time-slice. */
@
STR r3, [r4] @ Clear time-slice
@
@
@ /* Executing thread is now completely preserved!!! */
@
__tx_ts_new:
@
@ /* Now we are looking for a new thread to execute! */
@
CPSID i @ Disable interrupts
LDR r1, [r2] @ Is there another thread ready to execute?
CBZ r1, __tx_ts_wait @ No, skip to the wait processing
@
@ /* Yes, another thread is ready for else, make the current thread the new thread. */
@
STR r1, [r0] @ Setup the current thread pointer to the new thread
CPSIE i @ Enable interrupts
@
@ /* Increment the thread run count. */
@
__tx_ts_restore:
LDR r7, [r1, #4] @ Pickup the current thread run count
LDR r4, =_tx_timer_time_slice @ Build address of time-slice variable
LDR r5, [r1, #24] @ Pickup thread's current time-slice
ADD r7, r7, #1 @ Increment the thread run count
STR r7, [r1, #4] @ Store the new run count
@
@ /* Setup global time-slice with thread's current time-slice. */
@
STR r5, [r4] @ Setup global time-slice
LDR r4, =_tx_timer_time_slice // Build address of time-slice variable
STMDB r12!, {LR} // Save LR on the stack
#ifdef TX_ENABLE_EXECUTION_CHANGE_NOTIFY
@
@ /* Call the thread entry function to indicate the thread is executing. */
@
PUSH {r0, r1} @ Save r0/r1
BL _tx_execution_thread_enter @ Call the thread execution enter function
POP {r0, r1} @ Recover r3
/* Determine if time-slice is active. If it isn't, skip time handling processing. */
LDR r5, [r4] // Pickup current time-slice
STR r12, [r1, #8] // Save the thread stack pointer
CBZ r5, __tx_ts_new // If not active, skip processing
/* Time-slice is active, save the current thread's time-slice and clear the global time-slice variable. */
STR r5, [r1, #24] // Save current time-slice
/* Clear the global time-slice. */
STR r3, [r4] // Clear time-slice
/* Executing thread is now completely preserved!!! */
__tx_ts_new:
/* Now we are looking for a new thread to execute! */
CPSID i // Disable interrupts
LDR r1, [r2] // Is there another thread ready to execute?
CBZ r1, __tx_ts_wait // No, skip to the wait processing
/* Yes, another thread is ready for else, make the current thread the new thread. */
STR r1, [r0] // Setup the current thread pointer to the new thread
CPSIE i // Enable interrupts
/* Increment the thread run count. */
__tx_ts_restore:
LDR r7, [r1, #4] // Pickup the current thread run count
LDR r4, =_tx_timer_time_slice // Build address of time-slice variable
LDR r5, [r1, #24] // Pickup thread's current time-slice
ADD r7, r7, #1 // Increment the thread run count
STR r7, [r1, #4] // Store the new run count
/* Setup global time-slice with thread's current time-slice. */
STR r5, [r4] // Setup global time-slice
#if (defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) || defined(TX_EXECUTION_PROFILE_ENABLE))
/* Call the thread entry function to indicate the thread is executing. */
PUSH {r0, r1} // Save r0 and r1
BL _tx_execution_thread_enter // Call the thread execution enter function
POP {r0, r1} // Recover r0 and r1
#endif
@
@ /* Restore the thread context and PSP. */
@
LDR r12, [r1, #8] @ Pickup thread's stack pointer
LDMIA r12!, {LR} @ Pickup LR
#ifdef TX_ENABLE_FPU_SUPPORT
TST LR, #0x10 @ Determine if the VFP extended frame is present
BNE _skip_vfp_restore @ If not, skip VFP restore
VLDMIA r12!, {s16-s31} @ Yes, restore additional VFP registers
/* Restore the thread context and PSP. */
LDR r12, [r1, #8] // Pickup thread's stack pointer
LDMIA r12!, {LR} // Pickup LR
#ifdef __ARM_PCS_VFP
TST LR, #0x10 // Determine if the VFP extended frame is present
BNE _skip_vfp_restore // If not, skip VFP restore
VLDMIA r12!, {s16-s31} // Yes, restore additional VFP registers
_skip_vfp_restore:
#endif
LDMIA r12!, {r4-r11} @ Recover thread's registers
MSR PSP, r12 @ Setup the thread's stack pointer
@
@ /* Return to thread. */
@
BX lr @ Return to thread!
@
@ /* The following is the idle wait processing... in this case, no threads are ready for execution and the
@ system will simply be idle until an interrupt occurs that makes a thread ready. Note that interrupts
@ are disabled to allow use of WFI for waiting for a thread to arrive. */
@
LDMIA r12!, {r4-r11} // Recover thread's registers
MSR PSP, r12 // Setup the thread's stack pointer
/* Return to thread. */
BX lr // Return to thread!
/* The following is the idle wait processing... in this case, no threads are ready for execution and the
system will simply be idle until an interrupt occurs that makes a thread ready. Note that interrupts
are disabled to allow use of WFI for waiting for a thread to arrive. */
__tx_ts_wait:
CPSID i @ Disable interrupts
LDR r1, [r2] @ Pickup the next thread to execute pointer
STR r1, [r0] @ Store it in the current pointer
CBNZ r1, __tx_ts_ready @ If non-NULL, a new thread is ready!
CPSID i // Disable interrupts
LDR r1, [r2] // Pickup the next thread to execute pointer
STR r1, [r0] // Store it in the current pointer
CBNZ r1, __tx_ts_ready // If non-NULL, a new thread is ready!
#ifdef TX_LOW_POWER
PUSH {r0-r3}
BL tx_low_power_enter @ Possibly enter low power mode
POP {r0-r3}
BL tx_low_power_enter // Possibly enter low power mode
#endif
#ifdef TX_ENABLE_WFI
DSB @ Ensure no outstanding memory transactions
WFI @ Wait for interrupt
ISB @ Ensure pipeline is flushed
DSB // Ensure no outstanding memory transactions
WFI // Wait for interrupt
ISB // Ensure pipeline is flushed
#endif
#ifdef TX_LOW_POWER
PUSH {r0-r3}
BL tx_low_power_exit @ Exit low power mode
POP {r0-r3}
BL tx_low_power_exit // Exit low power mode
#endif
CPSIE i @ Enable interrupts
B __tx_ts_wait @ Loop to continue waiting
@
@ /* At this point, we have a new thread ready to go. Clear any newly pended PendSV - since we are
@ already in the handler! */
@
CPSIE i // Enable interrupts
B __tx_ts_wait // Loop to continue waiting
/* At this point, we have a new thread ready to go. Clear any newly pended PendSV - since we are
already in the handler! */
__tx_ts_ready:
MOV r7, #0x08000000 @ Build clear PendSV value
MOV r8, #0xE000E000 @ Build base NVIC address
STR r7, [r8, #0xD04] @ Clear any PendSV
@
@ /* Re-enable interrupts and restore new thread. */
@
CPSIE i @ Enable interrupts
B __tx_ts_restore @ Restore the thread
MOV r7, #0x08000000 // Build clear PendSV value
MOV r8, #0xE000E000 // Build base NVIC address
STR r7, [r8, #0xD04] // Clear any PendSV
#ifdef TX_ENABLE_FPU_SUPPORT
/* Re-enable interrupts and restore new thread. */
.global tx_thread_fpu_enable
.thumb_func
CPSIE i // Enable interrupts
B __tx_ts_restore // Restore the thread
// }
#ifdef __ARM_PCS_VFP
.global tx_thread_fpu_enable
.thumb_func
tx_thread_fpu_enable:
@
@ /* Automatic VPF logic is supported, this function is present only for
@ backward compatibility purposes and therefore simply returns. */
@
BX LR @ Return to caller
.global tx_thread_fpu_disable
.thumb_func
.global tx_thread_fpu_disable
.thumb_func
tx_thread_fpu_disable:
@
@ /* Automatic VPF logic is supported, this function is present only for
@ backward compatibility purposes and therefore simply returns. */
@
BX LR @ Return to caller
/* Automatic VPF logic is supported, this function is present only for
backward compatibility purposes and therefore simply returns. */
BX LR // Return to caller
#endif

View File

@@ -1,135 +1,133 @@
@/**************************************************************************/
@/* */
@/* 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 */
@/** */
@/**************************************************************************/
@/**************************************************************************/
@
@
/**************************************************************************/
/* */
/* 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 */
/** */
/**************************************************************************/
/**************************************************************************/
.text
.align 4
.syntax unified
@/**************************************************************************/
@/* */
@/* FUNCTION RELEASE */
@/* */
@/* _tx_thread_stack_build Cortex-M4/AC6 */
@/* 6.1 */
@/* AUTHOR */
@/* */
@/* William E. Lamie, 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 */
@/* */
@/* 09-30-2020 William E. Lamie Initial Version 6.1 */
@/* */
@/**************************************************************************/
@VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
@{
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_stack_build Cortex-M4/AC6 */
/* 6.1.7 */
/* 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 */
/* */
/* 06-02-2021 Scott Larson Initial Version 6.1.7 */
/* */
/**************************************************************************/
// VOID _tx_thread_stack_build(TX_THREAD *thread_ptr, VOID (*function_ptr)(VOID))
// {
.global _tx_thread_stack_build
.thumb_func
_tx_thread_stack_build:
@
@
@ /* Build a fake interrupt frame. The form of the fake interrupt stack
@ on the Cortex-M4 should look like the following after it is built:
@
@ Stack Top:
@ LR Interrupted LR (LR at time of PENDSV)
@ r4 Initial value for r4
@ r5 Initial value for r5
@ r6 Initial value for r6
@ r7 Initial value for r7
@ r8 Initial value for r8
@ r9 Initial value for r9
@ r10 Initial value for r10
@ r11 Initial value for r11
@ r0 Initial value for r0 (Hardware stack starts here!!)
@ r1 Initial value for r1
@ r2 Initial value for r2
@ r3 Initial value for r3
@ r12 Initial value for r12
@ lr Initial value for lr
@ pc Initial value for pc
@ xPSR Initial value for xPSR
@
@ Stack Bottom: (higher memory address) */
@
LDR r2, [r0, #16] @ Pickup end of stack area
BIC r2, r2, #0x7 @ Align frame
SUB r2, r2, #68 @ Subtract frame size
LDR r3, =0xFFFFFFFD @ Build initial LR value
STR r3, [r2, #0] @ Save on the stack
@
@ /* Actually build the stack frame. */
@
MOV r3, #0 @ Build initial register value
STR r3, [r2, #4] @ Store initial r4
STR r3, [r2, #8] @ Store initial r5
STR r3, [r2, #12] @ Store initial r6
STR r3, [r2, #16] @ Store initial r7
STR r3, [r2, #20] @ Store initial r8
STR r3, [r2, #24] @ Store initial r9
STR r3, [r2, #28] @ Store initial r10
STR r3, [r2, #32] @ Store initial r11
@
@ /* Hardware stack follows. */
@
STR r3, [r2, #36] @ Store initial r0
STR r3, [r2, #40] @ Store initial r1
STR r3, [r2, #44] @ Store initial r2
STR r3, [r2, #48] @ Store initial r3
STR r3, [r2, #52] @ Store initial r12
MOV r3, #0xFFFFFFFF @ Poison EXC_RETURN value
STR r3, [r2, #56] @ Store initial lr
STR r1, [r2, #60] @ Store initial pc
MOV r3, #0x01000000 @ Only T-bit need be set
STR r3, [r2, #64] @ Store initial xPSR
@
@ /* Setup stack pointer. */
@ thread_ptr -> tx_thread_stack_ptr = r2;
@
STR r2, [r0, #8] @ Save stack pointer in thread's
@ control block
BX lr @ Return to caller
@}
/* Build a fake interrupt frame. The form of the fake interrupt stack
on the Cortex-M should look like the following after it is built:
Stack Top:
LR Interrupted LR (LR at time of PENDSV)
r4 Initial value for r4
r5 Initial value for r5
r6 Initial value for r6
r7 Initial value for r7
r8 Initial value for r8
r9 Initial value for r9
r10 Initial value for r10
r11 Initial value for r11
r0 Initial value for r0 (Hardware stack starts here!!)
r1 Initial value for r1
r2 Initial value for r2
r3 Initial value for r3
r12 Initial value for r12
lr Initial value for lr
pc Initial value for pc
xPSR Initial value for xPSR
Stack Bottom: (higher memory address) */
LDR r2, [r0, #16] // Pickup end of stack area
BIC r2, r2, #0x7 // Align frame for 8-byte alignment
SUB r2, r2, #68 // Subtract frame size
LDR r3, =0xFFFFFFFD // Build initial LR value
STR r3, [r2, #0] // Save on the stack
/* Actually build the stack frame. */
MOV r3, #0 // Build initial register value
STR r3, [r2, #4] // Store initial r4
STR r3, [r2, #8] // Store initial r5
STR r3, [r2, #12] // Store initial r6
STR r3, [r2, #16] // Store initial r7
STR r3, [r2, #20] // Store initial r8
STR r3, [r2, #24] // Store initial r9
STR r3, [r2, #28] // Store initial r10
STR r3, [r2, #32] // Store initial r11
/* Hardware stack follows. */
STR r3, [r2, #36] // Store initial r0
STR r3, [r2, #40] // Store initial r1
STR r3, [r2, #44] // Store initial r2
STR r3, [r2, #48] // Store initial r3
STR r3, [r2, #52] // Store initial r12
MOV r3, #0xFFFFFFFF // Poison EXC_RETURN value
STR r3, [r2, #56] // Store initial lr
STR r1, [r2, #60] // Store initial pc
MOV r3, #0x01000000 // Only T-bit need be set
STR r3, [r2, #64] // Store initial xPSR
/* Setup stack pointer. */
// thread_ptr -> tx_thread_stack_ptr = r2;
STR r2, [r0, #8] // Save stack pointer in thread's
// control block
BX lr // Return to caller
// }

View File

@@ -1,88 +1,93 @@
@/**************************************************************************/
@/* */
@/* 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 */
@/** */
@/**************************************************************************/
@/**************************************************************************/
/**************************************************************************/
/* */
/* 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 */
/** */
/**************************************************************************/
/**************************************************************************/
.text 32
.align 4
.syntax unified
@/**************************************************************************/
@/* */
@/* FUNCTION RELEASE */
@/* */
@/* _tx_thread_system_return Cortex-M4/AC6 */
@/* 6.1 */
@/* AUTHOR */
@/* */
@/* William E. Lamie, Microsoft Corporation */
@/* */
@/* DESCRIPTION */
@/* */
@/* This function is target processor specific. It is used to transfer */
@/* control from a thread back to the ThreadX 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 */
@/* */
@/* 09-30-2020 William E. Lamie Initial Version 6.1 */
@/* */
@/**************************************************************************/
@/* VOID _tx_thread_system_return(VOID)
@{ */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_thread_system_return Cortex-M4/AC6 */
/* 6.1.7 */
/* AUTHOR */
/* */
/* Scott Larson, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function is target processor specific. It is used to transfer */
/* control from a thread back to the ThreadX 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 */
/* */
/* 06-02-2021 Scott Larson Initial Version 6.1.7 */
/* */
/**************************************************************************/
// VOID _tx_thread_system_return(VOID)
// {
.thumb_func
.global _tx_thread_system_return
_tx_thread_system_return:
@
@ /* Return to real scheduler via PendSV. Note that this routine is often
@ replaced with in-line assembly in tx_port.h to improved performance. */
@
MOV r0, #0x10000000 @ Load PENDSVSET bit
MOV r1, #0xE000E000 @ Load NVIC base
STR r0, [r1, #0xD04] @ Set PENDSVBIT in ICSR
MRS r0, IPSR @ Pickup IPSR
CMP r0, #0 @ Is it a thread returning?
BNE _isr_context @ If ISR, skip interrupt enable
MRS r1, PRIMASK @ Thread context returning, pickup PRIMASK
CPSIE i @ Enable interrupts
MSR PRIMASK, r1 @ Restore original interrupt posture
_isr_context:
BX lr @ Return to caller
@/* } */
/* Return to real scheduler via PendSV. Note that this routine is often
replaced with in-line assembly in tx_port.h to improved performance. */
MOV r0, #0x10000000 // Load PENDSVSET bit
MOV r1, #0xE000E000 // Load NVIC base
STR r0, [r1, #0xD04] // Set PENDSVBIT in ICSR
MRS r0, IPSR // Pickup IPSR
CMP r0, #0 // Is it a thread returning?
BNE _isr_context // If ISR, skip interrupt enable
#ifdef TX_PORT_USE_BASEPRI
MRS r1, BASEPRI // Thread context returning, pickup BASEPRI
MOV r0, #0
MSR BASEPRI, r0 // Enable interrupts
MSR BASEPRI, r1 // Restore original interrupt posture
#else
MRS r1, PRIMASK // Thread context returning, pickup PRIMASK
CPSIE i // Enable interrupts
MSR PRIMASK, r1 // Restore original interrupt posture
#endif
_isr_context:
BX lr // Return to caller
// }

View File

@@ -1,257 +1,250 @@
@/**************************************************************************/
@/* */
@/* 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 */
@/** */
@/**************************************************************************/
@/**************************************************************************/
@
@
.global _tx_timer_time_slice
.global _tx_timer_system_clock
.global _tx_timer_current_ptr
.global _tx_timer_list_start
.global _tx_timer_list_end
.global _tx_timer_expired_time_slice
.global _tx_timer_expired
.global _tx_thread_time_slice
.global _tx_timer_expiration_process
@
@
/**************************************************************************/
/* */
/* 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 */
/** */
/**************************************************************************/
/**************************************************************************/
.global _tx_timer_time_slice
.global _tx_timer_system_clock
.global _tx_timer_current_ptr
.global _tx_timer_list_start
.global _tx_timer_list_end
.global _tx_timer_expired_time_slice
.global _tx_timer_expired
.global _tx_thread_time_slice
.global _tx_timer_expiration_process
.text
.align 4
.syntax unified
@/**************************************************************************/
@/* */
@/* FUNCTION RELEASE */
@/* */
@/* _tx_timer_interrupt Cortex-M4/AC6 */
@/* 6.1 */
@/* AUTHOR */
@/* */
@/* William E. Lamie, 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 */
@/* */
@/* 09-30-2020 William E. Lamie Initial Version 6.1 */
@/* */
@/**************************************************************************/
@VOID _tx_timer_interrupt(VOID)
@{
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _tx_timer_interrupt Cortex-M4/AC6 */
/* 6.1.7 */
/* 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 */
/* expiration functions are called. */
/* */
/* 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 */
/* */
/* 06-02-2021 Scott Larson Initial Version 6.1.7 */
/* */
/**************************************************************************/
// VOID _tx_timer_interrupt(VOID)
// {
.global _tx_timer_interrupt
.thumb_func
_tx_timer_interrupt:
@
@ /* Upon entry to this routine, it is assumed that context save has already
@ been called, and therefore the compiler scratch registers are available
@ for use. */
@
@ /* Increment the system clock. */
@ _tx_timer_system_clock++;
@
LDR r1, =_tx_timer_system_clock @ Pickup address of system clock
LDR r0, [r1, #0] @ Pickup system clock
ADD r0, r0, #1 @ Increment system clock
STR r0, [r1, #0] @ Store new system clock
@
@ /* Test for time-slice expiration. */
@ if (_tx_timer_time_slice)
@ {
@
LDR r3, =_tx_timer_time_slice @ Pickup address of time-slice
LDR r2, [r3, #0] @ Pickup time-slice
CMP r2, #0 @ Is it non-active?
BEQ __tx_timer_no_time_slice @ Yes, skip time-slice processing
@
@ /* Decrement the time_slice. */
@ _tx_timer_time_slice--;
@
SUB r2, r2, #1 @ Decrement the time-slice
STR r2, [r3, #0] @ Store new time-slice value
@
@ /* Check for expiration. */
@ if (__tx_timer_time_slice == 0)
@
CMP r2, #0 @ Has it expired?
BNE __tx_timer_no_time_slice @ No, skip expiration processing
@
@ /* Set the time-slice expired flag. */
@ _tx_timer_expired_time_slice = TX_TRUE;
@
LDR r3, =_tx_timer_expired_time_slice @ Pickup address of expired flag
MOV r0, #1 @ Build expired value
STR r0, [r3, #0] @ Set time-slice expiration flag
@
@ }
@
/* Upon entry to this routine, it is assumed that the compiler scratch registers are available
for use. */
/* Increment the system clock. */
// _tx_timer_system_clock++;
LDR r1, =_tx_timer_system_clock // Pickup address of system clock
LDR r0, [r1, #0] // Pickup system clock
ADD r0, r0, #1 // Increment system clock
STR r0, [r1, #0] // Store new system clock
/* Test for time-slice expiration. */
// if (_tx_timer_time_slice)
// {
LDR r3, =_tx_timer_time_slice // Pickup address of time-slice
LDR r2, [r3, #0] // Pickup time-slice
CBZ r2, __tx_timer_no_time_slice // Is it non-active?
// Yes, skip time-slice processing
/* Decrement the time_slice. */
// _tx_timer_time_slice--;
SUB r2, r2, #1 // Decrement the time-slice
STR r2, [r3, #0] // Store new time-slice value
/* Check for expiration. */
// if (__tx_timer_time_slice == 0)
CBNZ r2, __tx_timer_no_time_slice // Has it expired?
// No, skip expiration processing
/* Set the time-slice expired flag. */
// _tx_timer_expired_time_slice = TX_TRUE;
LDR r3, =_tx_timer_expired_time_slice // Pickup address of expired flag
MOV r0, #1 // Build expired value
STR r0, [r3, #0] // Set time-slice expiration flag
// }
__tx_timer_no_time_slice:
@
@ /* Test for timer expiration. */
@ if (*_tx_timer_current_ptr)
@ {
@
LDR r1, =_tx_timer_current_ptr @ Pickup current timer pointer address
LDR r0, [r1, #0] @ Pickup current timer
LDR r2, [r0, #0] @ Pickup timer list entry
CMP r2, #0 @ Is there anything in the list?
BEQ __tx_timer_no_timer @ No, just increment the timer
@
@ /* Set expiration flag. */
@ _tx_timer_expired = TX_TRUE;
@
LDR r3, =_tx_timer_expired @ Pickup expiration flag address
MOV r2, #1 @ Build expired value
STR r2, [r3, #0] @ Set expired flag
B __tx_timer_done @ Finished timer processing
@
@ }
@ else
@ {
/* Test for timer expiration. */
// if (*_tx_timer_current_ptr)
// {
LDR r1, =_tx_timer_current_ptr // Pickup current timer pointer address
LDR r0, [r1, #0] // Pickup current timer
LDR r2, [r0, #0] // Pickup timer list entry
CBZ r2, __tx_timer_no_timer // Is there anything in the list?
// No, just increment the timer
/* Set expiration flag. */
// _tx_timer_expired = TX_TRUE;
LDR r3, =_tx_timer_expired // Pickup expiration flag address
MOV r2, #1 // Build expired value
STR r2, [r3, #0] // Set expired flag
B __tx_timer_done // Finished timer processing
// }
// else
// {
__tx_timer_no_timer:
@
@ /* No timer expired, increment the timer pointer. */
@ _tx_timer_current_ptr++;
@
ADD r0, r0, #4 @ Move to next timer
@
@ /* Check for wrap-around. */
@ if (_tx_timer_current_ptr == _tx_timer_list_end)
@
LDR r3, =_tx_timer_list_end @ Pickup addr of timer list end
LDR r2, [r3, #0] @ Pickup list end
CMP r0, r2 @ Are we at list end?
BNE __tx_timer_skip_wrap @ No, skip wrap-around logic
@
@ /* Wrap to beginning of list. */
@ _tx_timer_current_ptr = _tx_timer_list_start;
@
LDR r3, =_tx_timer_list_start @ Pickup addr of timer list start
LDR r0, [r3, #0] @ Set current pointer to list start
@
/* No timer expired, increment the timer pointer. */
// _tx_timer_current_ptr++;
ADD r0, r0, #4 // Move to next timer
/* Check for wrap-around. */
// if (_tx_timer_current_ptr == _tx_timer_list_end)
LDR r3, =_tx_timer_list_end // Pickup addr of timer list end
LDR r2, [r3, #0] // Pickup list end
CMP r0, r2 // Are we at list end?
BNE __tx_timer_skip_wrap // No, skip wrap-around logic
/* Wrap to beginning of list. */
// _tx_timer_current_ptr = _tx_timer_list_start;
LDR r3, =_tx_timer_list_start // Pickup addr of timer list start
LDR r0, [r3, #0] // Set current pointer to list start
__tx_timer_skip_wrap:
@
STR r0, [r1, #0] @ Store new current timer pointer
@ }
@
STR r0, [r1, #0] // Store new current timer pointer
// }
__tx_timer_done:
@
@
@ /* See if anything has expired. */
@ if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))
@ {
@
LDR r3, =_tx_timer_expired_time_slice @ Pickup addr of expired flag
LDR r2, [r3, #0] @ Pickup time-slice expired flag
CMP r2, #0 @ Did a time-slice expire?
BNE __tx_something_expired @ If non-zero, time-slice expired
LDR r1, =_tx_timer_expired @ Pickup addr of other expired flag
LDR r0, [r1, #0] @ Pickup timer expired flag
CMP r0, #0 @ Did a timer expire?
BEQ __tx_timer_nothing_expired @ No, nothing expired
@
/* See if anything has expired. */
// if ((_tx_timer_expired_time_slice) || (_tx_timer_expired))
// {
LDR r3, =_tx_timer_expired_time_slice // Pickup addr of expired flag
LDR r2, [r3, #0] // Pickup time-slice expired flag
CBNZ r2, __tx_something_expired // Did a time-slice expire?
// If non-zero, time-slice expired
LDR r1, =_tx_timer_expired // Pickup addr of other expired flag
LDR r0, [r1, #0] // Pickup timer expired flag
CBZ r0, __tx_timer_nothing_expired // Did a timer expire?
// No, nothing expired
__tx_something_expired:
@
@
STMDB sp!, {r0, lr} @ Save the lr register on the stack
@ and save r0 just to keep 8-byte alignment
@
@ /* Did a timer expire? */
@ if (_tx_timer_expired)
@ {
@
LDR r1, =_tx_timer_expired @ Pickup addr of expired flag
LDR r0, [r1, #0] @ Pickup timer expired flag
CMP r0, #0 @ Check for timer expiration
BEQ __tx_timer_dont_activate @ If not set, skip timer activation
@
@ /* Process timer expiration. */
@ _tx_timer_expiration_process();
@
BL _tx_timer_expiration_process @ Call the timer expiration handling routine
@
@ }
STMDB sp!, {r0, lr} // Save the lr register on the stack
// and save r0 just to keep 8-byte alignment
/* Did a timer expire? */
// if (_tx_timer_expired)
// {
LDR r1, =_tx_timer_expired // Pickup addr of expired flag
LDR r0, [r1, #0] // Pickup timer expired flag
CBZ r0, __tx_timer_dont_activate // Check for timer expiration
// If not set, skip timer activation
/* Process timer expiration. */
// _tx_timer_expiration_process();
BL _tx_timer_expiration_process // Call the timer expiration handling routine
// }
__tx_timer_dont_activate:
@
@ /* Did time slice expire? */
@ if (_tx_timer_expired_time_slice)
@ {
@
LDR r3, =_tx_timer_expired_time_slice @ Pickup addr of time-slice expired
LDR r2, [r3, #0] @ Pickup the actual flag
CMP r2, #0 @ See if the flag is set
BEQ __tx_timer_not_ts_expiration @ No, skip time-slice processing
@
@ /* Time slice interrupted thread. */
@ _tx_thread_time_slice();
@
BL _tx_thread_time_slice @ Call time-slice processing
LDR r0, =_tx_thread_preempt_disable @ Build address of preempt disable flag
LDR r1, [r0] @ Is the preempt disable flag set?
CBNZ r1, __tx_timer_skip_time_slice @ Yes, skip the PendSV logic
LDR r0, =_tx_thread_current_ptr @ Build current thread pointer address
LDR r1, [r0] @ Pickup the current thread pointer
LDR r2, =_tx_thread_execute_ptr @ Build execute thread pointer address
LDR r3, [r2] @ Pickup the execute thread pointer
LDR r0, =0xE000ED04 @ Build address of control register
LDR r2, =0x10000000 @ Build value for PendSV bit
CMP r1, r3 @ Are they the same?
BEQ __tx_timer_skip_time_slice @ If the same, there was no time-slice performed
STR r2, [r0] @ Not the same, issue the PendSV for preemption
/* Did time slice expire? */
// if (_tx_timer_expired_time_slice)
// {
LDR r3, =_tx_timer_expired_time_slice // Pickup addr of time-slice expired
LDR r2, [r3, #0] // Pickup the actual flag
CBZ r2, __tx_timer_not_ts_expiration // See if the flag is set
// No, skip time-slice processing
/* Time slice interrupted thread. */
// _tx_thread_time_slice();
BL _tx_thread_time_slice // Call time-slice processing
LDR r0, =_tx_thread_preempt_disable // Build address of preempt disable flag
LDR r1, [r0] // Is the preempt disable flag set?
CBNZ r1, __tx_timer_skip_time_slice // Yes, skip the PendSV logic
LDR r0, =_tx_thread_current_ptr // Build current thread pointer address
LDR r1, [r0] // Pickup the current thread pointer
LDR r2, =_tx_thread_execute_ptr // Build execute thread pointer address
LDR r3, [r2] // Pickup the execute thread pointer
LDR r0, =0xE000ED04 // Build address of control register
LDR r2, =0x10000000 // Build value for PendSV bit
CMP r1, r3 // Are they the same?
BEQ __tx_timer_skip_time_slice // If the same, there was no time-slice performed
STR r2, [r0] // Not the same, issue the PendSV for preemption
__tx_timer_skip_time_slice:
@
@ }
@
// }
__tx_timer_not_ts_expiration:
@
LDMIA sp!, {r0, lr} @ Recover lr register (r0 is just there for
@ the 8-byte stack alignment
@
@ }
@
LDMIA sp!, {r0, lr} // Recover lr register (r0 is just there for
// the 8-byte stack alignment
// }
__tx_timer_nothing_expired:
DSB @ Complete all memory access
BX lr @ Return to caller
@
@}
DSB // Complete all memory access
BX lr // Return to caller
// }