Tree reorganization.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8900 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
641f2c3726
commit
cf204e72ea
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* @file nil.h
|
||||
* @file ch.h
|
||||
* @brief Nil RTOS main header file.
|
||||
* @details This header includes all the required kernel headers so it is the
|
||||
* only header you usually need to include in your application.
|
||||
|
@ -27,18 +27,11 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _NIL_H_
|
||||
#define _NIL_H_
|
||||
#ifndef _CH_H_
|
||||
#define _CH_H_
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing a thread.
|
||||
* @note It is required as an early definition.
|
||||
*/
|
||||
typedef struct nil_thread thread_t;
|
||||
|
||||
#include "nilconf.h"
|
||||
#include "niltypes.h"
|
||||
#include "nilcore.h"
|
||||
#include "chconf.h"
|
||||
#include "chtypes.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
|
@ -61,22 +54,22 @@ typedef struct nil_thread thread_t;
|
|||
/**
|
||||
* @brief Kernel version string.
|
||||
*/
|
||||
#define CH_KERNEL_VERSION "1.1.1"
|
||||
#define CH_KERNEL_VERSION "2.0.0"
|
||||
|
||||
/**
|
||||
* @brief Kernel version major number.
|
||||
*/
|
||||
#define CH_KERNEL_MAJOR 1
|
||||
#define CH_KERNEL_MAJOR 2
|
||||
|
||||
/**
|
||||
* @brief Kernel version minor number.
|
||||
*/
|
||||
#define CH_KERNEL_MINOR 1
|
||||
#define CH_KERNEL_MINOR 0
|
||||
|
||||
/**
|
||||
* @brief Kernel version patch number.
|
||||
*/
|
||||
#define CH_KERNEL_PATCH 1
|
||||
#define CH_KERNEL_PATCH 0
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -150,26 +143,26 @@ typedef struct nil_thread thread_t;
|
|||
* @note This number is not inclusive of the idle thread which is
|
||||
* implicitly handled.
|
||||
*/
|
||||
#if !defined(NIL_CFG_NUM_THREADS) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_NUM_THREADS 2
|
||||
#if !defined(CH_CFG_NUM_THREADS) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_NUM_THREADS 2
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief System time counter resolution.
|
||||
* @note Allowed values are 16 or 32 bits.
|
||||
*/
|
||||
#if !defined(NIL_CFG_ST_RESOLUTION) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_ST_RESOLUTION 32
|
||||
#if !defined(CH_CFG_ST_RESOLUTION) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_ST_RESOLUTION 32
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief System tick frequency.
|
||||
* @note This value together with the @p NIL_CFG_ST_RESOLUTION
|
||||
* @note This value together with the @p CH_CFG_ST_RESOLUTION
|
||||
* option defines the maximum amount of time allowed for
|
||||
* timeouts.
|
||||
*/
|
||||
#if !defined(NIL_CFG_ST_FREQUENCY) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_ST_FREQUENCY 100
|
||||
#if !defined(CH_CFG_ST_FREQUENCY) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_ST_FREQUENCY 100
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -180,8 +173,29 @@ typedef struct nil_thread thread_t;
|
|||
* The value one is not valid, timeouts are rounded up to
|
||||
* this value.
|
||||
*/
|
||||
#if !defined(NIL_CFG_ST_TIMEDELTA) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_ST_TIMEDELTA 0
|
||||
#if !defined(CH_CFG_ST_TIMEDELTA) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_ST_TIMEDELTA 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Semaphores APIs.
|
||||
* @details If enabled then the Semaphores APIs are included in the kernel.
|
||||
*
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_USE_SEMAPHORES TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Mutexes APIs.
|
||||
* @details If enabled then the mutexes APIs are included in the kernel.
|
||||
*
|
||||
* @note Feature not currently implemented.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(CH_CFG_USE_MUTEXES) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_USE_MUTEXES FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -190,44 +204,122 @@ typedef struct nil_thread thread_t;
|
|||
*
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(NIL_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_USE_EVENTS TRUE
|
||||
#if !defined(CH_CFG_USE_EVENTS) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_USE_EVENTS TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Mailboxes APIs.
|
||||
* @details If enabled then the asynchronous messages (mailboxes) APIs are
|
||||
* included in the kernel.
|
||||
*
|
||||
* @note The default is @p TRUE.
|
||||
* @note Requires @p CH_CFG_USE_SEMAPHORES.
|
||||
*/
|
||||
#if !defined(CH_CFG_USE_MAILBOXES) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_USE_MAILBOXES TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Core Memory Manager APIs.
|
||||
* @details If enabled then the core memory manager APIs are included
|
||||
* in the kernel.
|
||||
*
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(CH_CFG_USE_MEMCORE) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_USE_MEMCORE TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Heap Allocator APIs.
|
||||
* @details If enabled then the memory heap allocator APIs are included
|
||||
* in the kernel.
|
||||
*
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(CH_CFG_USE_HEAP) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_USE_HEAP TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Memory Pools Allocator APIs.
|
||||
* @details If enabled then the memory pools allocator APIs are included
|
||||
* in the kernel.
|
||||
*
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#if !defined(CH_CFG_USE_MEMPOOLS) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_USE_MEMPOOLS TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Debug option, kernel statistics.
|
||||
*
|
||||
* @note Feature not currently implemented.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(CH_DBG_STATISTICS) || defined(__DOXYGEN__)
|
||||
#define CH_DBG_STATISTICS FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Debug option, system state check.
|
||||
* @note This is a planned feature, not yet implemented.
|
||||
*
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__)
|
||||
#define CH_DBG_SYSTEM_STATE_CHECK FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Debug option, parameters checks.
|
||||
*
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)
|
||||
#define CH_DBG_ENABLE_CHECKS FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief System assertions.
|
||||
*
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(NIL_CFG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_ENABLE_ASSERTS FALSE
|
||||
#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
|
||||
#define CH_DBG_ENABLE_ASSERTS FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Stack check.
|
||||
*
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(NIL_CFG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_ENABLE_STACK_CHECK FALSE
|
||||
#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__)
|
||||
#define CH_DBG_ENABLE_STACK_CHECK FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief System initialization hook.
|
||||
*/
|
||||
#if !defined(NIL_CFG_SYSTEM_INIT_HOOK) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_SYSTEM_INIT_HOOK() {}
|
||||
#if !defined(CH_CFG_SYSTEM_INIT_HOOK) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_SYSTEM_INIT_HOOK() {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Threads descriptor structure extension.
|
||||
* @details User fields added to the end of the @p thread_t structure.
|
||||
*/
|
||||
#if !defined(NIL_CFG_THREAD_EXT_FIELDS) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_THREAD_EXT_FIELDS
|
||||
#if !defined(CH_CFG_THREAD_EXT_FIELDS) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_THREAD_EXT_FIELDS
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Threads initialization hook.
|
||||
*/
|
||||
#if !defined(NIL_CFG_THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_THREAD_EXT_INIT_HOOK(tr) {}
|
||||
#if !defined(CH_CFG_THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_THREAD_EXT_INIT_HOOK(tr) {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -236,8 +328,8 @@ typedef struct nil_thread thread_t;
|
|||
* should be invoked from here.
|
||||
* @note This macro can be used to activate a power saving mode.
|
||||
*/
|
||||
#if !defined(NIL_CFG_IDLE_ENTER_HOOK) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_IDLE_ENTER_HOOK() {}
|
||||
#if !defined(CH_CFG_IDLE_ENTER_HOOK) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_IDLE_ENTER_HOOK() {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -246,44 +338,59 @@ typedef struct nil_thread thread_t;
|
|||
* should be invoked from here.
|
||||
* @note This macro can be used to deactivate a power saving mode.
|
||||
*/
|
||||
#if !defined(NIL_CFG_IDLE_LEAVE_HOOK) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_IDLE_LEAVE_HOOK() {}
|
||||
#if !defined(CH_CFG_IDLE_LEAVE_HOOK) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_IDLE_LEAVE_HOOK() {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief System halt hook.
|
||||
*/
|
||||
#if !defined(NIL_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
|
||||
#define NIL_CFG_SYSTEM_HALT_HOOK(reason) {}
|
||||
#if !defined(CH_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
|
||||
#define CH_CFG_SYSTEM_HALT_HOOK(reason) {}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if NIL_CFG_NUM_THREADS < 1
|
||||
#if !defined(_CHIBIOS_NIL_CONF_)
|
||||
#error "missing or wrong configuration file"
|
||||
#endif
|
||||
|
||||
#if CH_CFG_NUM_THREADS < 1
|
||||
#error "at least one thread must be defined"
|
||||
#endif
|
||||
|
||||
#if NIL_CFG_NUM_THREADS > 12
|
||||
#error "Nil is not recommended for thread-intensive applications, consider" \
|
||||
"ChibiOS/RT instead"
|
||||
#if CH_CFG_NUM_THREADS > 16
|
||||
#error "ChibiOS/NIL is not recommended for thread-intensive applications," \
|
||||
"consider ChibiOS/RT instead"
|
||||
#endif
|
||||
|
||||
#if (NIL_CFG_ST_RESOLUTION != 16) && (NIL_CFG_ST_RESOLUTION != 32)
|
||||
#error "invalid NIL_CFG_ST_RESOLUTION specified, must be 16 or 32"
|
||||
#if (CH_CFG_ST_RESOLUTION != 16) && (CH_CFG_ST_RESOLUTION != 32)
|
||||
#error "invalid CH_CFG_ST_RESOLUTION specified, must be 16 or 32"
|
||||
#endif
|
||||
|
||||
#if NIL_CFG_ST_FREQUENCY <= 0
|
||||
#error "invalid NIL_CFG_ST_FREQUENCY specified, must be greated than zero"
|
||||
#if CH_CFG_ST_FREQUENCY <= 0
|
||||
#error "invalid CH_CFG_ST_FREQUENCY specified, must be greated than zero"
|
||||
#endif
|
||||
|
||||
#if (NIL_CFG_ST_TIMEDELTA < 0) || (NIL_CFG_ST_TIMEDELTA == 1)
|
||||
#error "invalid NIL_CFG_ST_TIMEDELTA specified, must " \
|
||||
#if (CH_CFG_ST_TIMEDELTA < 0) || (CH_CFG_ST_TIMEDELTA == 1)
|
||||
#error "invalid CH_CFG_ST_TIMEDELTA specified, must " \
|
||||
"be zero or greater than one"
|
||||
#endif
|
||||
|
||||
#if (NIL_CFG_ENABLE_ASSERTS == TRUE) || (NIL_CFG_ENABLE_STACK_CHECK == TRUE)
|
||||
#if CH_CFG_USE_MUTEXES == TRUE
|
||||
#error "mutexes not yet supported"
|
||||
#endif
|
||||
|
||||
#if CH_DBG_STATISTICS == TRUE
|
||||
#error "statistics not yet supported"
|
||||
#endif
|
||||
|
||||
#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || \
|
||||
(CH_DBG_ENABLE_CHECKS == TRUE) || \
|
||||
(CH_DBG_ENABLE_ASSERTS == TRUE) || \
|
||||
(CH_DBG_ENABLE_STACK_CHECK == TRUE)
|
||||
#define NIL_DBG_ENABLED TRUE
|
||||
#else
|
||||
#define NIL_DBG_ENABLED FALSE
|
||||
|
@ -291,9 +398,7 @@ typedef struct nil_thread thread_t;
|
|||
|
||||
/** Boundaries of the idle thread boundaries, only required if stack checking
|
||||
is enabled.*/
|
||||
#if (NIL_CFG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
|
||||
extern stkalign_t __main_thread_stack_base__, __main_thread_stack_end__;
|
||||
|
||||
#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
|
||||
#define THD_IDLE_BASE (&__main_thread_stack_base__)
|
||||
#define THD_IDLE_END (&__main_thread_stack_end__)
|
||||
#else
|
||||
|
@ -306,10 +411,23 @@ extern stkalign_t __main_thread_stack_base__, __main_thread_stack_end__;
|
|||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of internal context structure.
|
||||
* @brief Type of system time.
|
||||
*/
|
||||
typedef struct port_intctx intctx_t;
|
||||
#if (CH_CFG_ST_RESOLUTION == 32) || defined(__DOXYGEN__)
|
||||
typedef uint32_t systime_t;
|
||||
#else
|
||||
typedef uint16_t systime_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing a thread.
|
||||
* @note It is required as an early definition.
|
||||
*/
|
||||
typedef struct nil_thread thread_t;
|
||||
|
||||
#include "chcore.h"
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Type of a structure representing a semaphore.
|
||||
*/
|
||||
|
@ -321,6 +439,7 @@ typedef struct nil_semaphore semaphore_t;
|
|||
struct nil_semaphore {
|
||||
volatile cnt_t cnt; /**< @brief Semaphore counter. */
|
||||
};
|
||||
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
|
||||
|
||||
/**
|
||||
* @brief Thread function.
|
||||
|
@ -352,29 +471,31 @@ typedef thread_t * thread_reference_t;
|
|||
* @brief Structure representing a thread.
|
||||
*/
|
||||
struct nil_thread {
|
||||
intctx_t *ctxp; /**< @brief Pointer to internal context. */
|
||||
struct port_context ctx; /**< @brief Processor context. */
|
||||
tstate_t state; /**< @brief Thread state. */
|
||||
/* Note, the following union contains a pointer while the thread is in a
|
||||
sleeping state (!NIL_THD_IS_READY()) else contains the wake-up message.*/
|
||||
union {
|
||||
msg_t msg; /**< @brief Wake-up message. */
|
||||
void *p; /**< @brief Generic pointer. */
|
||||
thread_reference_t *trp; /**< @brief Pointer to thread reference. */
|
||||
thread_reference_t *trp; /**< @brief Pointer to thread reference.*/
|
||||
#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
|
||||
semaphore_t *semp; /**< @brief Pointer to semaphore. */
|
||||
#if (NIL_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
||||
#endif
|
||||
#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
||||
eventmask_t ewmask; /**< @brief Enabled events mask. */
|
||||
#endif
|
||||
} u1;
|
||||
volatile systime_t timeout;/**< @brief Timeout counter, zero
|
||||
volatile systime_t timeout; /**< @brief Timeout counter, zero
|
||||
if disabled. */
|
||||
#if (NIL_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
||||
eventmask_t epmask; /**< @brief Pending events mask. */
|
||||
#endif
|
||||
#if (NIL_CFG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
|
||||
stkalign_t *stklim;/**< @brief Thread stack boundary. */
|
||||
#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
|
||||
stkalign_t *stklimit; /**< @brief Thread stack boundary. */
|
||||
#endif
|
||||
/* Optional extra fields.*/
|
||||
NIL_CFG_THREAD_EXT_FIELDS
|
||||
CH_CFG_THREAD_EXT_FIELDS
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -398,13 +519,13 @@ struct nil_system {
|
|||
* or to an higher priority thread if a switch is required.
|
||||
*/
|
||||
thread_t *next;
|
||||
#if (NIL_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief System time.
|
||||
*/
|
||||
volatile systime_t systime;
|
||||
#endif
|
||||
#if (NIL_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief System time of the last tick event.
|
||||
*/
|
||||
|
@ -414,10 +535,16 @@ struct nil_system {
|
|||
*/
|
||||
systime_t nexttime;
|
||||
#endif
|
||||
#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Thread structures for all the defined threads.
|
||||
* @brief ISR nesting level.
|
||||
*/
|
||||
thread_t threads[NIL_CFG_NUM_THREADS + 1];
|
||||
cnt_t isr_cnt;
|
||||
/**
|
||||
* @brief Lock nesting level.
|
||||
*/
|
||||
cnt_t lock_cnt;
|
||||
#endif
|
||||
#if (NIL_DBG_ENABLED == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Panic message.
|
||||
|
@ -428,12 +555,21 @@ struct nil_system {
|
|||
*/
|
||||
const char * volatile dbg_panic_msg;
|
||||
#endif
|
||||
/**
|
||||
* @brief Thread structures for all the defined threads.
|
||||
*/
|
||||
thread_t threads[CH_CFG_NUM_THREADS + 1];
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK == TRUE
|
||||
#define _dbg_enter_lock() (nil.lock_cnt = (cnt_t)1)
|
||||
#define _dbg_leave_lock() (nil.lock_cnt = (cnt_t)0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Threads tables definition macros
|
||||
* @{
|
||||
|
@ -442,7 +578,7 @@ struct nil_system {
|
|||
* @brief Start of user threads table.
|
||||
*/
|
||||
#define THD_TABLE_BEGIN \
|
||||
const thread_config_t nil_thd_configs[NIL_CFG_NUM_THREADS + 1] = {
|
||||
const thread_config_t nil_thd_configs[CH_CFG_NUM_THREADS + 1] = {
|
||||
|
||||
/**
|
||||
* @brief Entry of user threads table
|
||||
|
@ -460,20 +596,53 @@ struct nil_system {
|
|||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Working Areas and Alignment
|
||||
* @name Memory alignment support macros
|
||||
*/
|
||||
/**
|
||||
* @brief Enforces a correct alignment for a stack area size value.
|
||||
* @brief Alignment mask constant.
|
||||
*
|
||||
* @param[in] n the stack size to be aligned to the next stack
|
||||
* alignment boundary
|
||||
* @return The aligned stack size.
|
||||
*
|
||||
* @api
|
||||
* @param[in] a alignment, must be a power of two
|
||||
*/
|
||||
#define THD_ALIGN_STACK_SIZE(n) \
|
||||
((((n) - 1U) | (sizeof(stkalign_t) - 1U)) + 1U)
|
||||
#define MEM_ALIGN_MASK(a) ((size_t)(a) - 1U)
|
||||
|
||||
/**
|
||||
* @brief Aligns to the previous aligned memory address.
|
||||
*
|
||||
* @param[in] p variable to be aligned
|
||||
* @param[in] a alignment, must be a power of two
|
||||
*/
|
||||
#define MEM_ALIGN_PREV(p, a) ((size_t)(p) & ~MEM_ALIGN_MASK(a))
|
||||
|
||||
/**
|
||||
* @brief Aligns to the new aligned memory address.
|
||||
*
|
||||
* @param[in] p variable to be aligned
|
||||
* @param[in] a alignment, must be a power of two
|
||||
*/
|
||||
#define MEM_ALIGN_NEXT(p, a) MEM_ALIGN_PREV((size_t)(p) + \
|
||||
MEM_ALIGN_MASK(a), (a))
|
||||
|
||||
/**
|
||||
* @brief Returns whatever a pointer or memory size is aligned.
|
||||
*
|
||||
* @param[in] p variable to be aligned
|
||||
* @param[in] a alignment, must be a power of two
|
||||
*/
|
||||
#define MEM_IS_ALIGNED(p, a) (((size_t)(p) & MEM_ALIGN_MASK(a)) == 0U)
|
||||
|
||||
/**
|
||||
* @brief Returns whatever a constant is a valid alignment.
|
||||
* @details Valid alignments are powers of two.
|
||||
*
|
||||
* @param[in] a alignment to be checked, must be a constant
|
||||
*/
|
||||
#define MEM_IS_VALID_ALIGNMENT(a) \
|
||||
(((size_t)(a) != 0U) && (((size_t)(a) & ((size_t)(a) - 1U)) == 0U))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Working Areas
|
||||
*/
|
||||
/**
|
||||
* @brief Calculates the total Working Area size.
|
||||
*
|
||||
|
@ -482,8 +651,8 @@ struct nil_system {
|
|||
*
|
||||
* @api
|
||||
*/
|
||||
#define THD_WORKING_AREA_SIZE(n) \
|
||||
THD_ALIGN_STACK_SIZE(PORT_WA_SIZE(n))
|
||||
#define THD_WORKING_AREA_SIZE(n) MEM_ALIGN_NEXT(PORT_WA_SIZE(n), \
|
||||
PORT_STACK_ALIGN)
|
||||
|
||||
/**
|
||||
* @brief Static working area allocation.
|
||||
|
@ -495,8 +664,7 @@ struct nil_system {
|
|||
*
|
||||
* @api
|
||||
*/
|
||||
#define THD_WORKING_AREA(s, n) \
|
||||
stkalign_t s[THD_WORKING_AREA_SIZE(n) / sizeof(stkalign_t)]
|
||||
#define THD_WORKING_AREA(s, n) PORT_WORKING_AREA(s, n)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -556,7 +724,9 @@ struct nil_system {
|
|||
*
|
||||
* @special
|
||||
*/
|
||||
#define CH_IRQ_PROLOGUE() PORT_IRQ_PROLOGUE()
|
||||
#define CH_IRQ_PROLOGUE() \
|
||||
PORT_IRQ_PROLOGUE(); \
|
||||
_dbg_check_enter_isr()
|
||||
|
||||
/**
|
||||
* @brief IRQ handler exit code.
|
||||
|
@ -564,7 +734,9 @@ struct nil_system {
|
|||
*
|
||||
* @special
|
||||
*/
|
||||
#define CH_IRQ_EPILOGUE() PORT_IRQ_EPILOGUE()
|
||||
#define CH_IRQ_EPILOGUE() \
|
||||
_dbg_check_leave_isr(); \
|
||||
PORT_IRQ_EPILOGUE()
|
||||
|
||||
/**
|
||||
* @brief Standard normal IRQ handler declaration.
|
||||
|
@ -605,7 +777,7 @@ struct nil_system {
|
|||
* @api
|
||||
*/
|
||||
#define S2ST(sec) \
|
||||
((systime_t)((uint32_t)(sec) * (uint32_t)NIL_CFG_ST_FREQUENCY))
|
||||
((systime_t)((uint32_t)(sec) * (uint32_t)CH_CFG_ST_FREQUENCY))
|
||||
|
||||
/**
|
||||
* @brief Milliseconds to system ticks.
|
||||
|
@ -619,7 +791,7 @@ struct nil_system {
|
|||
*/
|
||||
#define MS2ST(msec) \
|
||||
((systime_t)(((((uint32_t)(msec)) * \
|
||||
((uint32_t)NIL_CFG_ST_FREQUENCY)) + 999UL) / 1000UL))
|
||||
((uint32_t)CH_CFG_ST_FREQUENCY)) + 999UL) / 1000UL))
|
||||
|
||||
/**
|
||||
* @brief Microseconds to system ticks.
|
||||
|
@ -633,7 +805,7 @@ struct nil_system {
|
|||
*/
|
||||
#define US2ST(usec) \
|
||||
((systime_t)(((((uint32_t)(usec)) * \
|
||||
((uint32_t)NIL_CFG_ST_FREQUENCY)) + 999999UL) / 1000000UL))
|
||||
((uint32_t)CH_CFG_ST_FREQUENCY)) + 999999UL) / 1000000UL))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -701,32 +873,67 @@ struct nil_system {
|
|||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enters the kernel lock mode.
|
||||
* @brief Raises the system interrupt priority mask to the maximum level.
|
||||
* @details All the maskable interrupt sources are disabled regardless their
|
||||
* hardware priority.
|
||||
* @note Do not invoke this API from within a kernel lock.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
#define chSysDisable() port_disable()
|
||||
#define chSysDisable() { \
|
||||
port_disable(); \
|
||||
_dbg_check_disable(); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enters the kernel lock mode.
|
||||
* @brief Raises the system interrupt priority mask to system level.
|
||||
* @details The interrupt sources that should not be able to preempt the kernel
|
||||
* are disabled, interrupt sources with higher priority are still
|
||||
* enabled.
|
||||
* @note Do not invoke this API from within a kernel lock.
|
||||
* @note This API is no replacement for @p chSysLock(), the @p chSysLock()
|
||||
* could do more than just disable the interrupts.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
#define chSysEnable() port_enable()
|
||||
#define chSysSuspend() { \
|
||||
port_suspend(); \
|
||||
_dbg_check_suspend(); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lowers the system interrupt priority mask to user level.
|
||||
* @details All the interrupt sources are enabled.
|
||||
* @note Do not invoke this API from within a kernel lock.
|
||||
* @note This API is no replacement for @p chSysUnlock(), the
|
||||
* @p chSysUnlock() could do more than just enable the interrupts.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
#define chSysEnable() { \
|
||||
_dbg_check_enable(); \
|
||||
port_enable(); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enters the kernel lock state.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
#define chSysLock() port_lock()
|
||||
#define chSysLock() { \
|
||||
port_lock(); \
|
||||
_dbg_check_lock(); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Leaves the kernel lock state.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
#define chSysUnlock() port_unlock()
|
||||
#define chSysUnlock() { \
|
||||
_dbg_check_unlock(); \
|
||||
port_unlock(); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enters the kernel lock state from within an interrupt handler.
|
||||
|
@ -740,7 +947,10 @@ struct nil_system {
|
|||
*
|
||||
* @special
|
||||
*/
|
||||
#define chSysLockFromISR() port_lock_from_isr()
|
||||
#define chSysLockFromISR() { \
|
||||
port_lock_from_isr(); \
|
||||
_dbg_check_lock_from_isr(); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Leaves the kernel lock state from within an interrupt handler.
|
||||
|
@ -755,7 +965,10 @@ struct nil_system {
|
|||
*
|
||||
* @special
|
||||
*/
|
||||
#define chSysUnlockFromISR() port_unlock_from_isr()
|
||||
#define chSysUnlockFromISR() { \
|
||||
_dbg_check_unlock_from_isr(); \
|
||||
port_unlock_from_isr(); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Evaluates if a reschedule is required.
|
||||
|
@ -834,6 +1047,7 @@ struct nil_system {
|
|||
(void) chSchGoSleepTimeoutS(NIL_STATE_SLEEPING, (abstime) - \
|
||||
chVTGetSystemTimeX())
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Initializes a semaphore with the specified counter value.
|
||||
*
|
||||
|
@ -873,12 +1087,34 @@ struct nil_system {
|
|||
*/
|
||||
#define chSemWaitS(sp) chSemWaitTimeoutS(sp, TIME_INFINITE)
|
||||
|
||||
/**
|
||||
* @brief Decreases the semaphore counter.
|
||||
* @details This macro can be used when the counter is known to be positive.
|
||||
*
|
||||
* @param[in] sp pointer to a @p semaphore_t structure
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define chSemFastWaitI(sp) ((sp)->cnt--)
|
||||
|
||||
/**
|
||||
* @brief Increases the semaphore counter.
|
||||
* @details This macro can be used when the counter is known to be not
|
||||
* negative.
|
||||
*
|
||||
* @param[in] sp pointer to a @p semaphore_t structure
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define chSemFastSignalI(sp) ((sp)->cnt++)
|
||||
|
||||
/**
|
||||
* @brief Returns the semaphore counter current value.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define chSemGetCounterI(sp) ((sp)->cnt)
|
||||
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
|
||||
|
||||
/**
|
||||
* @brief Current system time.
|
||||
|
@ -893,7 +1129,7 @@ struct nil_system {
|
|||
*
|
||||
* @xclass
|
||||
*/
|
||||
#if (NIL_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__)
|
||||
#define chVTGetSystemTimeX() (nil.systime)
|
||||
#else
|
||||
#define chVTGetSystemTimeX() port_timer_get_time()
|
||||
|
@ -927,12 +1163,34 @@ struct nil_system {
|
|||
#define chVTIsTimeWithinX(time, start, end) \
|
||||
((bool)((systime_t)((time) - (start)) < (systime_t)((end) - (start))))
|
||||
|
||||
/**
|
||||
* @brief Function parameters check.
|
||||
* @details If the condition check fails then the kernel panics and halts.
|
||||
* @note The condition is tested only if the @p CH_DBG_ENABLE_CHECKS switch
|
||||
* is specified in @p chconf.h else the macro does nothing.
|
||||
*
|
||||
* @param[in] c the condition to be verified to be true
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#if !defined(chDbgCheck)
|
||||
#define chDbgCheck(c) do { \
|
||||
/*lint -save -e506 -e774 [2.1, 14.3] Can be a constant by design.*/ \
|
||||
if (CH_DBG_ENABLE_CHECKS != FALSE) { \
|
||||
if (!(c)) { \
|
||||
/*lint -restore*/ \
|
||||
chSysHalt(__func__); \
|
||||
} \
|
||||
} \
|
||||
} while (false)
|
||||
#endif /* !defined(chDbgCheck) */
|
||||
|
||||
/**
|
||||
* @brief Condition assertion.
|
||||
* @details If the condition check fails then the kernel panics with a
|
||||
* message and halts.
|
||||
* @note The condition is tested only if the @p NIL_CFG_ENABLE_ASSERTS
|
||||
* switch is specified in @p nilconf.h else the macro does nothing.
|
||||
* @note The condition is tested only if the @p CH_DBG_ENABLE_ASSERTS
|
||||
* switch is specified in @p chconf.h else the macro does nothing.
|
||||
* @note The remark string is not currently used except for putting a
|
||||
* comment in the code about the assertion.
|
||||
*
|
||||
|
@ -944,7 +1202,7 @@ struct nil_system {
|
|||
#if !defined(chDbgAssert)
|
||||
#define chDbgAssert(c, r) do { \
|
||||
/*lint -save -e506 -e774 [2.1, 14.3] Can be a constant by design.*/ \
|
||||
if (NIL_CFG_ENABLE_ASSERTS != FALSE) { \
|
||||
if (CH_DBG_ENABLE_ASSERTS != FALSE) { \
|
||||
if (!(c)) { \
|
||||
/*lint -restore*/ \
|
||||
chSysHalt(__func__); \
|
||||
|
@ -954,13 +1212,33 @@ struct nil_system {
|
|||
#endif /* !defined(chDbgAssert) */
|
||||
/** @} */
|
||||
|
||||
/* Empty macros if the state checker is not enabled.*/
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK == FALSE
|
||||
#define _dbg_enter_lock()
|
||||
#define _dbg_leave_lock()
|
||||
#define _dbg_check_disable()
|
||||
#define _dbg_check_suspend()
|
||||
#define _dbg_check_enable()
|
||||
#define _dbg_check_lock()
|
||||
#define _dbg_check_unlock()
|
||||
#define _dbg_check_lock_from_isr()
|
||||
#define _dbg_check_unlock_from_isr()
|
||||
#define _dbg_check_enter_isr()
|
||||
#define _dbg_check_leave_isr()
|
||||
#define chDbgCheckClassI()
|
||||
#define chDbgCheckClassS()
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
|
||||
extern stkalign_t __main_thread_stack_base__, __main_thread_stack_end__;
|
||||
#endif
|
||||
extern nil_system_t nil;
|
||||
extern const thread_config_t nil_thd_configs[NIL_CFG_NUM_THREADS + 1];
|
||||
extern const thread_config_t nil_thd_configs[CH_CFG_NUM_THREADS + 1];
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -976,28 +1254,50 @@ extern "C" {
|
|||
void chSysPolledDelayX(rtcnt_t cycles);
|
||||
void chSysRestoreStatusX(syssts_t sts);
|
||||
thread_t *chSchReadyI(thread_t *tp, msg_t msg);
|
||||
bool chSchIsPreemptionRequired(void);
|
||||
void chSchDoReschedule(void);
|
||||
void chSchRescheduleS(void);
|
||||
msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout);
|
||||
msg_t chThdSuspendTimeoutS(thread_reference_t *trp, systime_t timeout);
|
||||
void chThdResumeI(thread_reference_t *trp, msg_t msg);
|
||||
void chThdSleep(systime_t timeout);
|
||||
void chThdSleepUntil(systime_t abstime);
|
||||
#if CH_CFG_USE_SEMAPHORES == TRUE
|
||||
msg_t chSemWaitTimeout(semaphore_t *sp, systime_t timeout);
|
||||
msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t timeout);
|
||||
void chSemSignal(semaphore_t *sp);
|
||||
void chSemSignalI(semaphore_t *sp);
|
||||
void chSemReset(semaphore_t *sp, cnt_t n);
|
||||
void chSemResetI(semaphore_t *sp, cnt_t n);
|
||||
#if NIL_CFG_USE_EVENTS == TRUE
|
||||
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
|
||||
#if CH_CFG_USE_EVENTS == TRUE
|
||||
void chEvtSignal(thread_t *tp, eventmask_t mask);
|
||||
void chEvtSignalI(thread_t *tp, eventmask_t mask);
|
||||
eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, systime_t timeout);
|
||||
eventmask_t chEvtWaitAnyTimeoutS(eventmask_t mask, systime_t timeout);
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK == TRUE
|
||||
void _dbg_check_disable(void);
|
||||
void _dbg_check_suspend(void);
|
||||
void _dbg_check_enable(void);
|
||||
void _dbg_check_lock(void);
|
||||
void _dbg_check_unlock(void);
|
||||
void _dbg_check_lock_from_isr(void);
|
||||
void _dbg_check_unlock_from_isr(void);
|
||||
void _dbg_check_enter_isr(void);
|
||||
void _dbg_check_leave_isr(void);
|
||||
void chDbgCheckClassI(void);
|
||||
void chDbgCheckClassS(void);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _NIL_H_ */
|
||||
/* Optional subsystems.*/
|
||||
#include "chmboxes.h"
|
||||
#include "chmemcore.h"
|
||||
#include "chmempools.h"
|
||||
#include "chheap.h"
|
||||
|
||||
#endif /* _CH_H_ */
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -1,5 +1,28 @@
|
|||
# List of all the ChibiOS/NIL kernel files.
|
||||
KERNSRC = ${CHIBIOS}/os/nil/src/nil.c
|
||||
# List of all the ChibiOS/NIL kernel files, there is no need to remove the files
|
||||
# from this list, you can disable parts of the kernel by editing chconf.h.
|
||||
ifeq ($(USE_SMART_BUILD),yes)
|
||||
CHCONF := $(strip $(shell cat chconf.h | egrep -e "define"))
|
||||
KERNSRC := ${CHIBIOS}/os/nil/src/ch.c
|
||||
ifneq ($(findstring CH_CFG_USE_MAILBOXES TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/common/oslib/src/chmboxes.c
|
||||
endif
|
||||
ifneq ($(findstring CH_CFG_USE_MEMCORE TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/common/oslib/src/chmemcore.c
|
||||
endif
|
||||
ifneq ($(findstring CH_CFG_USE_HEAP TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/common/oslib/src/chheap.c
|
||||
endif
|
||||
ifneq ($(findstring CH_CFG_USE_MEMPOOLS TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/common/oslib/src/chmempools.c
|
||||
endif
|
||||
else
|
||||
KERNSRC := ${CHIBIOS}/os/nil/src/ch.c \
|
||||
${CHIBIOS}/os/common/oslib/src/chmboxes.c \
|
||||
${CHIBIOS}/os/common/oslib/src/chmemcore.c \
|
||||
${CHIBIOS}/os/common/oslib/src/chmempools.c \
|
||||
${CHIBIOS}/os/common/oslib/src/chheap.c
|
||||
endif
|
||||
|
||||
# Required include directories
|
||||
KERNINC = ${CHIBIOS}/os/nil/include
|
||||
KERNINC := ${CHIBIOS}/os/nil/include \
|
||||
${CHIBIOS}/os/common/oslib/include
|
||||
|
|
334
os/nil/src/ch.c
334
os/nil/src/ch.c
|
@ -18,14 +18,14 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* @file nil.c
|
||||
* @file ch.c
|
||||
* @brief Nil RTOS main source file.
|
||||
*
|
||||
* @addtogroup NIL_KERNEL
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "nil.h"
|
||||
#include "ch.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
|
@ -56,6 +56,156 @@ nil_system_t nil;
|
|||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if (CH_DBG_SYSTEM_STATE_CHECK == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Guard code for @p chSysDisable().
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_check_disable(void) {
|
||||
|
||||
if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
|
||||
chSysHalt("SV#1");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Guard code for @p chSysSuspend().
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_check_suspend(void) {
|
||||
|
||||
if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
|
||||
chSysHalt("SV#2");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Guard code for @p chSysEnable().
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_check_enable(void) {
|
||||
|
||||
if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
|
||||
chSysHalt("SV#3");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Guard code for @p chSysLock().
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_check_lock(void) {
|
||||
|
||||
if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
|
||||
chSysHalt("SV#4");
|
||||
}
|
||||
_dbg_enter_lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Guard code for @p chSysUnlock().
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_check_unlock(void) {
|
||||
|
||||
if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
|
||||
chSysHalt("SV#5");
|
||||
}
|
||||
_dbg_leave_lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Guard code for @p chSysLockFromIsr().
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_check_lock_from_isr(void) {
|
||||
|
||||
if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
|
||||
chSysHalt("SV#6");
|
||||
}
|
||||
_dbg_enter_lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Guard code for @p chSysUnlockFromIsr().
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_check_unlock_from_isr(void) {
|
||||
|
||||
if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
|
||||
chSysHalt("SV#7");
|
||||
}
|
||||
_dbg_leave_lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Guard code for @p CH_IRQ_PROLOGUE().
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_check_enter_isr(void) {
|
||||
|
||||
port_lock_from_isr();
|
||||
if ((nil.isr_cnt < (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
|
||||
chSysHalt("SV#8");
|
||||
}
|
||||
nil.isr_cnt++;
|
||||
port_unlock_from_isr();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Guard code for @p CH_IRQ_EPILOGUE().
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_check_leave_isr(void) {
|
||||
|
||||
port_lock_from_isr();
|
||||
if ((nil.isr_cnt <= (cnt_t)0) || (nil.lock_cnt != (cnt_t)0)) {
|
||||
chSysHalt("SV#9");
|
||||
}
|
||||
nil.isr_cnt--;
|
||||
port_unlock_from_isr();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief I-class functions context check.
|
||||
* @details Verifies that the system is in an appropriate state for invoking
|
||||
* an I-class API function. A panic is generated if the state is
|
||||
* not compatible.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void chDbgCheckClassI(void) {
|
||||
|
||||
if ((nil.isr_cnt < (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
|
||||
chSysHalt("SV#10");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief S-class functions context check.
|
||||
* @details Verifies that the system is in an appropriate state for invoking
|
||||
* an S-class API function. A panic is generated if the state is
|
||||
* not compatible.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void chDbgCheckClassS(void) {
|
||||
|
||||
if ((nil.isr_cnt != (cnt_t)0) || (nil.lock_cnt <= (cnt_t)0)) {
|
||||
chSysHalt("SV#11");
|
||||
}
|
||||
}
|
||||
#endif /* CH_DBG_SYSTEM_STATE_CHECK == TRUE */
|
||||
|
||||
/**
|
||||
* @brief Initializes the kernel.
|
||||
* @details Initializes the kernel structures, the current instructions flow
|
||||
|
@ -71,43 +221,59 @@ void chSysInit(void) {
|
|||
thread_t *tp;
|
||||
const thread_config_t *tcp;
|
||||
|
||||
/* Port layer initialization.*/
|
||||
port_init();
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK == TRUE
|
||||
nil.isr_cnt = (cnt_t)0;
|
||||
nil.lock_cnt = (cnt_t)0;
|
||||
#endif
|
||||
|
||||
/* System initialization hook.*/
|
||||
NIL_CFG_SYSTEM_INIT_HOOK();
|
||||
CH_CFG_SYSTEM_INIT_HOOK();
|
||||
|
||||
/* Iterates through the list of defined threads.*/
|
||||
tp = &nil.threads[0];
|
||||
tcp = nil_thd_configs;
|
||||
while (tp < &nil.threads[NIL_CFG_NUM_THREADS]) {
|
||||
#if NIL_CFG_ENABLE_STACK_CHECK
|
||||
tp->stklim = (stkalign_t *)tcp->wbase;
|
||||
while (tp < &nil.threads[CH_CFG_NUM_THREADS]) {
|
||||
#if CH_DBG_ENABLE_STACK_CHECK
|
||||
tp->stklimit = (stkalign_t *)tcp->wbase;
|
||||
#endif
|
||||
|
||||
/* Port dependent thread initialization.*/
|
||||
PORT_SETUP_CONTEXT(tp, tcp->wend, tcp->funcp, tcp->arg);
|
||||
PORT_SETUP_CONTEXT(tp, tcp->wbase, tcp->wend, tcp->funcp, tcp->arg);
|
||||
|
||||
/* Initialization hook.*/
|
||||
NIL_CFG_THREAD_EXT_INIT_HOOK(tp);
|
||||
CH_CFG_THREAD_EXT_INIT_HOOK(tp);
|
||||
|
||||
tp++;
|
||||
tcp++;
|
||||
}
|
||||
|
||||
#if NIL_CFG_ENABLE_STACK_CHECK
|
||||
#if CH_DBG_ENABLE_STACK_CHECK
|
||||
/* The idle thread is a special case because its stack is set up by the
|
||||
runtime environment.*/
|
||||
tp->stklim = THD_IDLE_BASE;
|
||||
tp->stklimit = THD_IDLE_BASE;
|
||||
#endif
|
||||
|
||||
/* Interrupts partially enabled. It is equivalent to entering the
|
||||
kernel critical zone.*/
|
||||
chSysSuspend();
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK == TRUE
|
||||
nil.lock_cnt = (cnt_t)1;
|
||||
#endif
|
||||
|
||||
/* Heap initialization, if enabled.*/
|
||||
#if CH_CFG_USE_HEAP == TRUE
|
||||
_heap_init();
|
||||
#endif
|
||||
|
||||
/* Port layer initialization last because it depend on some of the
|
||||
initializations performed before.*/
|
||||
port_init();
|
||||
|
||||
/* Runs the highest priority thread, the current one becomes the idle
|
||||
thread.*/
|
||||
nil.current = nil.next = nil.threads;
|
||||
port_switch(nil.current, tp);
|
||||
|
||||
/* Interrupts enabled for the idle thread.*/
|
||||
chSysEnable();
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,7 +298,7 @@ void chSysHalt(const char *reason) {
|
|||
(void)reason;
|
||||
#endif
|
||||
|
||||
NIL_CFG_SYSTEM_HALT_HOOK(reason);
|
||||
CH_CFG_SYSTEM_HALT_HOOK(reason);
|
||||
|
||||
/* Harmless infinite loop.*/
|
||||
while (true) {
|
||||
|
@ -148,7 +314,9 @@ void chSysHalt(const char *reason) {
|
|||
*/
|
||||
void chSysTimerHandlerI(void) {
|
||||
|
||||
#if NIL_CFG_ST_TIMEDELTA == 0
|
||||
chDbgCheckClassI();
|
||||
|
||||
#if CH_CFG_ST_TIMEDELTA == 0
|
||||
thread_t *tp = &nil.threads[0];
|
||||
nil.systime++;
|
||||
do {
|
||||
|
@ -177,7 +345,7 @@ void chSysTimerHandlerI(void) {
|
|||
chSysUnlockFromISR();
|
||||
tp++;
|
||||
chSysLockFromISR();
|
||||
} while (tp < &nil.threads[NIL_CFG_NUM_THREADS]);
|
||||
} while (tp < &nil.threads[CH_CFG_NUM_THREADS]);
|
||||
#else
|
||||
thread_t *tp = &nil.threads[0];
|
||||
systime_t next = (systime_t)0;
|
||||
|
@ -193,16 +361,20 @@ void chSysTimerHandlerI(void) {
|
|||
|
||||
tp->timeout -= nil.nexttime - nil.lasttime;
|
||||
if (tp->timeout == (systime_t)0) {
|
||||
#if CH_CFG_USE_SEMAPHORES == TRUE
|
||||
/* Timeout on semaphores requires a special handling because the
|
||||
semaphore counter must be incremented.*/
|
||||
/*lint -save -e9013 [15.7] There is no else because it is not needed.*/
|
||||
if (NIL_THD_IS_WTSEM(tp)) {
|
||||
tp->u1.semp->cnt++;
|
||||
}
|
||||
else if (NIL_THD_IS_SUSP(tp)) {
|
||||
else {
|
||||
#endif
|
||||
if (NIL_THD_IS_SUSP(tp)) {
|
||||
*tp->u1.trp = NULL;
|
||||
}
|
||||
/*lint -restore*/
|
||||
#if CH_CFG_USE_SEMAPHORES == TRUE
|
||||
}
|
||||
#endif
|
||||
(void) chSchReadyI(tp, MSG_TIMEOUT);
|
||||
}
|
||||
else {
|
||||
|
@ -216,7 +388,7 @@ void chSysTimerHandlerI(void) {
|
|||
chSysUnlockFromISR();
|
||||
tp++;
|
||||
chSysLockFromISR();
|
||||
} while (tp < &nil.threads[NIL_CFG_NUM_THREADS]);
|
||||
} while (tp < &nil.threads[CH_CFG_NUM_THREADS]);
|
||||
nil.lasttime = nil.nexttime;
|
||||
if (next > (systime_t)0) {
|
||||
nil.nexttime += next;
|
||||
|
@ -360,9 +532,8 @@ void chSysPolledDelayX(rtcnt_t cycles) {
|
|||
*/
|
||||
thread_t *chSchReadyI(thread_t *tp, msg_t msg) {
|
||||
|
||||
chDbgAssert((tp >= nil.threads) &&
|
||||
(tp < &nil.threads[NIL_CFG_NUM_THREADS]),
|
||||
"pointer out of range");
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck((tp >= nil.threads) && (tp < &nil.threads[CH_CFG_NUM_THREADS]));
|
||||
chDbgAssert(!NIL_THD_IS_READY(tp), "already ready");
|
||||
chDbgAssert(nil.next <= nil.current, "priority ordering");
|
||||
|
||||
|
@ -375,6 +546,41 @@ thread_t *chSchReadyI(thread_t *tp, msg_t msg) {
|
|||
return tp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Evaluates if preemption is required.
|
||||
* @details The decision is taken by comparing the relative priorities and
|
||||
* depending on the state of the round robin timeout counter.
|
||||
* @note Not a user function, it is meant to be invoked by the scheduler
|
||||
* itself or from within the port layer.
|
||||
*
|
||||
* @retval true if there is a thread that must go in running state
|
||||
* immediately.
|
||||
* @retval false if preemption is not required.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
bool chSchIsPreemptionRequired(void) {
|
||||
|
||||
return chSchIsRescRequiredI();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Switches to the first thread on the runnable queue.
|
||||
* @note Not a user function, it is meant to be invoked by the scheduler
|
||||
* itself or from within the port layer.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
void chSchDoReschedule(void) {
|
||||
thread_t *otp = nil.current;
|
||||
|
||||
nil.current = nil.next;
|
||||
if (otp == &nil.threads[CH_CFG_NUM_THREADS]) {
|
||||
CH_CFG_IDLE_LEAVE_HOOK();
|
||||
}
|
||||
port_switch(nil.next, otp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reschedules if needed.
|
||||
*
|
||||
|
@ -382,14 +588,10 @@ thread_t *chSchReadyI(thread_t *tp, msg_t msg) {
|
|||
*/
|
||||
void chSchRescheduleS(void) {
|
||||
|
||||
if (chSchIsRescRequiredI()) {
|
||||
thread_t *otp = nil.current;
|
||||
chDbgCheckClassS();
|
||||
|
||||
nil.current = nil.next;
|
||||
if (otp == &nil.threads[NIL_CFG_NUM_THREADS]) {
|
||||
NIL_CFG_IDLE_LEAVE_HOOK();
|
||||
}
|
||||
port_switch(nil.next, otp);
|
||||
if (chSchIsRescRequiredI()) {
|
||||
chSchDoReschedule();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -413,20 +615,22 @@ void chSchRescheduleS(void) {
|
|||
msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout) {
|
||||
thread_t *ntp, *otp = nil.current;
|
||||
|
||||
chDbgAssert(otp != &nil.threads[NIL_CFG_NUM_THREADS],
|
||||
chDbgCheckClassS();
|
||||
|
||||
chDbgAssert(otp != &nil.threads[CH_CFG_NUM_THREADS],
|
||||
"idle cannot sleep");
|
||||
|
||||
/* Storing the wait object for the current thread.*/
|
||||
otp->state = newstate;
|
||||
|
||||
#if NIL_CFG_ST_TIMEDELTA > 0
|
||||
#if CH_CFG_ST_TIMEDELTA > 0
|
||||
if (timeout != TIME_INFINITE) {
|
||||
systime_t abstime;
|
||||
|
||||
/* TIMEDELTA makes sure to have enough time to reprogram the timer
|
||||
before the free-running timer counter reaches the selected timeout.*/
|
||||
if (timeout < (systime_t)NIL_CFG_ST_TIMEDELTA) {
|
||||
timeout = (systime_t)NIL_CFG_ST_TIMEDELTA;
|
||||
if (timeout < (systime_t)CH_CFG_ST_TIMEDELTA) {
|
||||
timeout = (systime_t)CH_CFG_ST_TIMEDELTA;
|
||||
}
|
||||
|
||||
/* Absolute time of the timeout event.*/
|
||||
|
@ -461,8 +665,8 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout) {
|
|||
/* Is this thread ready to execute?*/
|
||||
if (NIL_THD_IS_READY(ntp)) {
|
||||
nil.current = nil.next = ntp;
|
||||
if (ntp == &nil.threads[NIL_CFG_NUM_THREADS]) {
|
||||
NIL_CFG_IDLE_ENTER_HOOK();
|
||||
if (ntp == &nil.threads[CH_CFG_NUM_THREADS]) {
|
||||
CH_CFG_IDLE_ENTER_HOOK();
|
||||
}
|
||||
port_switch(ntp, otp);
|
||||
return nil.current->u1.msg;
|
||||
|
@ -470,7 +674,7 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout) {
|
|||
|
||||
/* Points to the next thread in lowering priority order.*/
|
||||
ntp++;
|
||||
chDbgAssert(ntp <= &nil.threads[NIL_CFG_NUM_THREADS],
|
||||
chDbgAssert(ntp <= &nil.threads[CH_CFG_NUM_THREADS],
|
||||
"pointer out of range");
|
||||
}
|
||||
}
|
||||
|
@ -549,6 +753,7 @@ void chThdSleepUntil(systime_t abstime) {
|
|||
chSysUnlock();
|
||||
}
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Performs a wait operation on a semaphore with timeout specification.
|
||||
*
|
||||
|
@ -599,6 +804,9 @@ msg_t chSemWaitTimeout(semaphore_t *sp, systime_t timeout) {
|
|||
*/
|
||||
msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t timeout) {
|
||||
|
||||
chDbgCheckClassS();
|
||||
chDbgCheck(sp != NULL);
|
||||
|
||||
/* Note, the semaphore counter is a volatile variable so accesses are
|
||||
manually optimized.*/
|
||||
cnt_t cnt = sp->cnt;
|
||||
|
@ -646,6 +854,9 @@ void chSemSignal(semaphore_t *sp) {
|
|||
*/
|
||||
void chSemSignalI(semaphore_t *sp) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck(sp != NULL);
|
||||
|
||||
if (++sp->cnt <= (cnt_t)0) {
|
||||
thread_reference_t tr = nil.threads;
|
||||
while (true) {
|
||||
|
@ -659,7 +870,7 @@ void chSemSignalI(semaphore_t *sp) {
|
|||
}
|
||||
tr++;
|
||||
|
||||
chDbgAssert(tr < &nil.threads[NIL_CFG_NUM_THREADS],
|
||||
chDbgAssert(tr < &nil.threads[CH_CFG_NUM_THREADS],
|
||||
"pointer out of range");
|
||||
}
|
||||
}
|
||||
|
@ -709,12 +920,15 @@ void chSemResetI(semaphore_t *sp, cnt_t n) {
|
|||
thread_t *tp;
|
||||
cnt_t cnt;
|
||||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck((sp != NULL) && (n >= (cnt_t)0));
|
||||
|
||||
cnt = sp->cnt;
|
||||
sp->cnt = n;
|
||||
tp = nil.threads;
|
||||
while (cnt < (cnt_t)0) {
|
||||
|
||||
chDbgAssert(tp < &nil.threads[NIL_CFG_NUM_THREADS],
|
||||
chDbgAssert(tp < &nil.threads[CH_CFG_NUM_THREADS],
|
||||
"pointer out of range");
|
||||
|
||||
/* Is this thread waiting on this semaphore?*/
|
||||
|
@ -729,7 +943,6 @@ void chSemResetI(semaphore_t *sp, cnt_t n) {
|
|||
}
|
||||
}
|
||||
|
||||
#if (NIL_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Adds a set of event flags directly to the specified @p thread_t.
|
||||
*
|
||||
|
@ -745,7 +958,9 @@ void chEvtSignal(thread_t *tp, eventmask_t mask) {
|
|||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
}
|
||||
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
|
||||
|
||||
#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Adds a set of event flags directly to the specified @p thread_t.
|
||||
* @post This function does not reschedule so a call to a rescheduling
|
||||
|
@ -760,6 +975,9 @@ void chEvtSignal(thread_t *tp, eventmask_t mask) {
|
|||
*/
|
||||
void chEvtSignalI(thread_t *tp, eventmask_t mask) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck(tp != NULL);
|
||||
|
||||
tp->epmask |= mask;
|
||||
if (NIL_THD_IS_WTOREVT(tp) &&
|
||||
((tp->epmask & tp->u1.ewmask) != (eventmask_t)0)) {
|
||||
|
@ -786,37 +1004,10 @@ void chEvtSignalI(thread_t *tp, eventmask_t mask) {
|
|||
* @api
|
||||
*/
|
||||
eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, systime_t timeout) {
|
||||
eventmask_t m;
|
||||
|
||||
chSysLock();
|
||||
m = chEvtWaitAnyTimeoutS(mask, timeout);
|
||||
chSysUnlock();
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits for any of the specified events.
|
||||
* @details The function waits for any event among those specified in
|
||||
* @p mask to become pending then the events are cleared and
|
||||
* returned.
|
||||
*
|
||||
* @param[in] mask mask of the event flags that the function should wait
|
||||
* for, @p ALL_EVENTS enables all the events
|
||||
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||
* the following special values are allowed:
|
||||
* - @a TIME_IMMEDIATE immediate timeout.
|
||||
* - @a TIME_INFINITE no timeout.
|
||||
* .
|
||||
* @return The mask of the served and cleared events.
|
||||
* @retval 0 if the operation has timed out.
|
||||
*
|
||||
* @sclass
|
||||
*/
|
||||
eventmask_t chEvtWaitAnyTimeoutS(eventmask_t mask, systime_t timeout) {
|
||||
thread_t *ctp = nil.current;
|
||||
eventmask_t m;
|
||||
|
||||
chSysLock();
|
||||
if ((m = (ctp->epmask & mask)) == (eventmask_t)0) {
|
||||
if (TIME_IMMEDIATE == timeout) {
|
||||
chSysUnlock();
|
||||
|
@ -832,9 +1023,10 @@ eventmask_t chEvtWaitAnyTimeoutS(eventmask_t mask, systime_t timeout) {
|
|||
m = ctp->epmask & mask;
|
||||
}
|
||||
ctp->epmask &= ~m;
|
||||
chSysUnlock();
|
||||
|
||||
return m;
|
||||
}
|
||||
#endif /* NIL_CFG_USE_EVENTS == TRUE */
|
||||
#endif /* CH_CFG_USE_EVENTS == TRUE */
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -48,17 +48,17 @@
|
|||
/**
|
||||
* @brief Kernel version string.
|
||||
*/
|
||||
#define CH_KERNEL_VERSION "3.2.0"
|
||||
#define CH_KERNEL_VERSION "4.0.0"
|
||||
|
||||
/**
|
||||
* @brief Kernel version major number.
|
||||
*/
|
||||
#define CH_KERNEL_MAJOR 3
|
||||
#define CH_KERNEL_MAJOR 4
|
||||
|
||||
/**
|
||||
* @brief Kernel version minor number.
|
||||
*/
|
||||
#define CH_KERNEL_MINOR 2
|
||||
#define CH_KERNEL_MINOR 0
|
||||
|
||||
/**
|
||||
* @brief Kernel version patch number.
|
||||
|
@ -69,8 +69,14 @@
|
|||
/* Core headers.*/
|
||||
#include "chtypes.h"
|
||||
#include "chconf.h"
|
||||
|
||||
#if !defined(_CHIBIOS_RT_CONF_)
|
||||
#error "invalid configuration file"
|
||||
#endif
|
||||
|
||||
#include "chlicense.h"
|
||||
#include "chsystypes.h"
|
||||
#include "chalign.h"
|
||||
#include "chcore.h"
|
||||
#include "chdebug.h"
|
||||
#include "chtm.h"
|
||||
|
@ -92,10 +98,13 @@
|
|||
#include "chmemcore.h"
|
||||
#include "chheap.h"
|
||||
#include "chmempools.h"
|
||||
#include "chdynamic.h"
|
||||
#include "chqueues.h"
|
||||
#include "chstreams.h"
|
||||
|
||||
#if !defined(_CHIBIOS_RT_CONF_)
|
||||
#error "missing or wrong configuration file"
|
||||
#endif
|
||||
|
||||
#endif /* _CH_H_ */
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -18,17 +18,15 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* @file chmemcore.h
|
||||
* @brief Core memory manager macros and structures.
|
||||
* @file chmem.h
|
||||
* @brief Memory alignment macros and structures.
|
||||
*
|
||||
* @addtogroup memcore
|
||||
* @addtogroup mem
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHMEMCORE_H_
|
||||
#define _CHMEMCORE_H_
|
||||
|
||||
#if (CH_CFG_USE_MEMCORE == TRUE) || defined(__DOXYGEN__)
|
||||
#ifndef _CHALIGN_H_
|
||||
#define _CHALIGN_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
|
@ -46,43 +44,53 @@
|
|||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Memory get function.
|
||||
*/
|
||||
typedef void *(*memgetfunc_t)(size_t size);
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Alignment support macros
|
||||
* @name Memory alignment support macros
|
||||
*/
|
||||
/**
|
||||
* @brief Alignment size constant.
|
||||
*/
|
||||
#define MEM_ALIGN_SIZE sizeof(stkalign_t)
|
||||
|
||||
/**
|
||||
* @brief Alignment mask constant.
|
||||
*
|
||||
* @param[in] a alignment, must be a power of two
|
||||
*/
|
||||
#define MEM_ALIGN_MASK (MEM_ALIGN_SIZE - 1U)
|
||||
#define MEM_ALIGN_MASK(a) ((size_t)(a) - 1U)
|
||||
|
||||
/**
|
||||
* @brief Alignment helper macro.
|
||||
* @brief Aligns to the previous aligned memory address.
|
||||
*
|
||||
* @param[in] p variable to be aligned
|
||||
* @param[in] a alignment, must be a power of two
|
||||
*/
|
||||
#define MEM_ALIGN_PREV(p) ((size_t)(p) & ~MEM_ALIGN_MASK)
|
||||
#define MEM_ALIGN_PREV(p, a) ((size_t)(p) & ~MEM_ALIGN_MASK(a))
|
||||
|
||||
/**
|
||||
* @brief Alignment helper macro.
|
||||
* @brief Aligns to the new aligned memory address.
|
||||
*
|
||||
* @param[in] p variable to be aligned
|
||||
* @param[in] a alignment, must be a power of two
|
||||
*/
|
||||
#define MEM_ALIGN_NEXT(p) MEM_ALIGN_PREV((size_t)(p) + MEM_ALIGN_MASK)
|
||||
#define MEM_ALIGN_NEXT(p, a) MEM_ALIGN_PREV((size_t)(p) + \
|
||||
MEM_ALIGN_MASK(a), (a))
|
||||
|
||||
/**
|
||||
* @brief Returns whatever a pointer or memory size is aligned to
|
||||
* the type @p stkalign_t.
|
||||
* @brief Returns whatever a pointer or memory size is aligned.
|
||||
*
|
||||
* @param[in] p variable to be aligned
|
||||
* @param[in] a alignment, must be a power of two
|
||||
*/
|
||||
#define MEM_IS_ALIGNED(p) (((size_t)(p) & MEM_ALIGN_MASK) == 0U)
|
||||
#define MEM_IS_ALIGNED(p, a) (((size_t)(p) & MEM_ALIGN_MASK(a)) == 0U)
|
||||
|
||||
/**
|
||||
* @brief Returns whatever a constant is a valid alignment.
|
||||
* @details Valid alignments are powers of two.
|
||||
*
|
||||
* @param[in] a alignment to be checked, must be a constant
|
||||
*/
|
||||
#define MEM_IS_VALID_ALIGNMENT(a) \
|
||||
(((size_t)(a) != 0U) && (((size_t)(a) & ((size_t)(a) - 1U)) == 0U))
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@ -92,10 +100,7 @@ typedef void *(*memgetfunc_t)(size_t size);
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void _core_init(void);
|
||||
void *chCoreAlloc(size_t size);
|
||||
void *chCoreAllocI(size_t size);
|
||||
size_t chCoreGetStatusX(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -104,8 +109,6 @@ extern "C" {
|
|||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#endif /* CH_CFG_USE_MEMCORE == TRUE */
|
||||
|
||||
#endif /* _CHMEMCORE_H_ */
|
||||
#endif /* _CHALIGN_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,311 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chbsem.h
|
||||
* @brief Binary semaphores structures and macros.
|
||||
*
|
||||
* @addtogroup binary_semaphores
|
||||
* @details Binary semaphores related APIs and services.
|
||||
* <h2>Operation mode</h2>
|
||||
* Binary semaphores are implemented as a set of inline functions
|
||||
* that use the existing counting semaphores primitives. The
|
||||
* difference between counting and binary semaphores is that the
|
||||
* counter of binary semaphores is not allowed to grow above the
|
||||
* value 1. Repeated signal operation are ignored. A binary
|
||||
* semaphore can thus have only two defined states:
|
||||
* - <b>Taken</b>, when its counter has a value of zero or lower
|
||||
* than zero. A negative number represent the number of threads
|
||||
* queued on the binary semaphore.
|
||||
* - <b>Not taken</b>, when its counter has a value of one.
|
||||
* .
|
||||
* Binary semaphores are different from mutexes because there is no
|
||||
* concept of ownership, a binary semaphore can be taken by a
|
||||
* thread and signaled by another thread or an interrupt handler,
|
||||
* mutexes can only be taken and released by the same thread. Another
|
||||
* difference is that binary semaphores, unlike mutexes, do not
|
||||
* implement the priority inheritance protocol.<br>
|
||||
* In order to use the binary semaphores APIs the
|
||||
* @p CH_CFG_USE_SEMAPHORES option must be enabled in @p chconf.h.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHBSEM_H_
|
||||
#define _CHBSEM_H_
|
||||
|
||||
#if (CH_CFG_USE_SEMAPHORES == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @extends semaphore_t
|
||||
*
|
||||
* @brief Binary semaphore type.
|
||||
*/
|
||||
typedef struct {
|
||||
semaphore_t bs_sem;
|
||||
} binary_semaphore_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Data part of a static semaphore initializer.
|
||||
* @details This macro should be used when statically initializing a semaphore
|
||||
* that is part of a bigger structure.
|
||||
*
|
||||
* @param[in] name the name of the semaphore variable
|
||||
* @param[in] taken the semaphore initial state
|
||||
*/
|
||||
#define _BSEMAPHORE_DATA(name, taken) \
|
||||
{_SEMAPHORE_DATA(name.bs_sem, ((taken) ? 0 : 1))}
|
||||
|
||||
/**
|
||||
* @brief Static semaphore initializer.
|
||||
* @details Statically initialized semaphores require no explicit
|
||||
* initialization using @p chBSemInit().
|
||||
*
|
||||
* @param[in] name the name of the semaphore variable
|
||||
* @param[in] taken the semaphore initial state
|
||||
*/
|
||||
#define BSEMAPHORE_DECL(name, taken) \
|
||||
binary_semaphore_t name = _BSEMAPHORE_DATA(name, taken)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initializes a binary semaphore.
|
||||
*
|
||||
* @param[out] bsp pointer to a @p binary_semaphore_t structure
|
||||
* @param[in] taken initial state of the binary semaphore:
|
||||
* - @a false, the initial state is not taken.
|
||||
* - @a true, the initial state is taken.
|
||||
* .
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
static inline void chBSemObjectInit(binary_semaphore_t *bsp, bool taken) {
|
||||
|
||||
chSemObjectInit(&bsp->bs_sem, taken ? (cnt_t)0 : (cnt_t)1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait operation on the binary semaphore.
|
||||
*
|
||||
* @param[in] bsp pointer to a @p binary_semaphore_t structure
|
||||
* @return A message specifying how the invoking thread has been
|
||||
* released from the semaphore.
|
||||
* @retval MSG_OK if the binary semaphore has been successfully taken.
|
||||
* @retval MSG_RESET if the binary semaphore has been reset using
|
||||
* @p bsemReset().
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline msg_t chBSemWait(binary_semaphore_t *bsp) {
|
||||
|
||||
return chSemWait(&bsp->bs_sem);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait operation on the binary semaphore.
|
||||
*
|
||||
* @param[in] bsp pointer to a @p binary_semaphore_t structure
|
||||
* @return A message specifying how the invoking thread has been
|
||||
* released from the semaphore.
|
||||
* @retval MSG_OK if the binary semaphore has been successfully taken.
|
||||
* @retval MSG_RESET if the binary semaphore has been reset using
|
||||
* @p bsemReset().
|
||||
*
|
||||
* @sclass
|
||||
*/
|
||||
static inline msg_t chBSemWaitS(binary_semaphore_t *bsp) {
|
||||
|
||||
chDbgCheckClassS();
|
||||
|
||||
return chSemWaitS(&bsp->bs_sem);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait operation on the binary semaphore.
|
||||
*
|
||||
* @param[in] bsp pointer to a @p binary_semaphore_t structure
|
||||
* @param[in] time the number of ticks before the operation timeouts,
|
||||
* the following special values are allowed:
|
||||
* - @a TIME_IMMEDIATE immediate timeout.
|
||||
* - @a TIME_INFINITE no timeout.
|
||||
* .
|
||||
* @return A message specifying how the invoking thread has been
|
||||
* released from the semaphore.
|
||||
* @retval MSG_OK if the binary semaphore has been successfully taken.
|
||||
* @retval MSG_RESET if the binary semaphore has been reset using
|
||||
* @p bsemReset().
|
||||
* @retval MSG_TIMEOUT if the binary semaphore has not been signaled or reset
|
||||
* within the specified timeout.
|
||||
*
|
||||
* @sclass
|
||||
*/
|
||||
static inline msg_t chBSemWaitTimeoutS(binary_semaphore_t *bsp,
|
||||
systime_t time) {
|
||||
|
||||
chDbgCheckClassS();
|
||||
|
||||
return chSemWaitTimeoutS(&bsp->bs_sem, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait operation on the binary semaphore.
|
||||
*
|
||||
* @param[in] bsp pointer to a @p binary_semaphore_t structure
|
||||
* @param[in] time the number of ticks before the operation timeouts,
|
||||
* the following special values are allowed:
|
||||
* - @a TIME_IMMEDIATE immediate timeout.
|
||||
* - @a TIME_INFINITE no timeout.
|
||||
* .
|
||||
* @return A message specifying how the invoking thread has been
|
||||
* released from the semaphore.
|
||||
* @retval MSG_OK if the binary semaphore has been successfully taken.
|
||||
* @retval MSG_RESET if the binary semaphore has been reset using
|
||||
* @p bsemReset().
|
||||
* @retval MSG_TIMEOUT if the binary semaphore has not been signaled or reset
|
||||
* within the specified timeout.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline msg_t chBSemWaitTimeout(binary_semaphore_t *bsp,
|
||||
systime_t time) {
|
||||
|
||||
return chSemWaitTimeout(&bsp->bs_sem, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset operation on the binary semaphore.
|
||||
* @note The released threads can recognize they were waked up by a reset
|
||||
* rather than a signal because the @p bsemWait() will return
|
||||
* @p MSG_RESET instead of @p MSG_OK.
|
||||
* @note This function does not reschedule.
|
||||
*
|
||||
* @param[in] bsp pointer to a @p binary_semaphore_t structure
|
||||
* @param[in] taken new state of the binary semaphore
|
||||
* - @a false, the new state is not taken.
|
||||
* - @a true, the new state is taken.
|
||||
* .
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
static inline void chBSemResetI(binary_semaphore_t *bsp, bool taken) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
|
||||
chSemResetI(&bsp->bs_sem, taken ? (cnt_t)0 : (cnt_t)1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset operation on the binary semaphore.
|
||||
* @note The released threads can recognize they were waked up by a reset
|
||||
* rather than a signal because the @p bsemWait() will return
|
||||
* @p MSG_RESET instead of @p MSG_OK.
|
||||
*
|
||||
* @param[in] bsp pointer to a @p binary_semaphore_t structure
|
||||
* @param[in] taken new state of the binary semaphore
|
||||
* - @a false, the new state is not taken.
|
||||
* - @a true, the new state is taken.
|
||||
* .
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline void chBSemReset(binary_semaphore_t *bsp, bool taken) {
|
||||
|
||||
chSemReset(&bsp->bs_sem, taken ? (cnt_t)0 : (cnt_t)1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs a signal operation on a binary semaphore.
|
||||
* @note This function does not reschedule.
|
||||
*
|
||||
* @param[in] bsp pointer to a @p binary_semaphore_t structure
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
static inline void chBSemSignalI(binary_semaphore_t *bsp) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
|
||||
if (bsp->bs_sem.s_cnt < (cnt_t)1) {
|
||||
chSemSignalI(&bsp->bs_sem);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs a signal operation on a binary semaphore.
|
||||
*
|
||||
* @param[in] bsp pointer to a @p binary_semaphore_t structure
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline void chBSemSignal(binary_semaphore_t *bsp) {
|
||||
|
||||
chSysLock();
|
||||
chBSemSignalI(bsp);
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the binary semaphore current state.
|
||||
*
|
||||
* @param[in] bsp pointer to a @p binary_semaphore_t structure
|
||||
* @return The binary semaphore current state.
|
||||
* @retval false if the binary semaphore is not taken.
|
||||
* @retval true if the binary semaphore is taken.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
static inline bool chBSemGetStateI(binary_semaphore_t *bsp) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
|
||||
return (bsp->bs_sem.s_cnt > (cnt_t)0) ? false : true;
|
||||
}
|
||||
|
||||
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
|
||||
|
||||
#endif /* _CHBSEM_H_ */
|
||||
|
||||
/** @} */
|
|
@ -57,7 +57,7 @@
|
|||
* @brief condition_variable_t structure.
|
||||
*/
|
||||
typedef struct condition_variable {
|
||||
threads_queue_t c_queue; /**< @brief Condition variable
|
||||
threads_queue_t queue; /**< @brief Condition variable
|
||||
threads queue. */
|
||||
} condition_variable_t;
|
||||
|
||||
|
@ -72,7 +72,7 @@ typedef struct condition_variable {
|
|||
*
|
||||
* @param[in] name the name of the condition variable
|
||||
*/
|
||||
#define _CONDVAR_DATA(name) {_THREADS_QUEUE_DATA(name.c_queue)}
|
||||
#define _CONDVAR_DATA(name) {_THREADS_QUEUE_DATA(name.queue)}
|
||||
|
||||
/**
|
||||
* @brief Static condition variable initializer.
|
||||
|
|
|
@ -32,6 +32,51 @@
|
|||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Trace record types
|
||||
* @{
|
||||
*/
|
||||
#define CH_TRACE_TYPE_UNUSED 0U
|
||||
#define CH_TRACE_TYPE_SWITCH 1U
|
||||
#define CH_TRACE_TYPE_ISR_ENTER 2U
|
||||
#define CH_TRACE_TYPE_ISR_LEAVE 3U
|
||||
#define CH_TRACE_TYPE_HALT 4U
|
||||
#define CH_TRACE_TYPE_USER 5U
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Trace suspend masks
|
||||
* @{
|
||||
*/
|
||||
#define CH_TRACE_SUSPEND_NONE 0U
|
||||
#define CH_TRACE_SUSPEND_SWITCH (1U << CH_TRACE_TYPE_SWITCH)
|
||||
#define CH_TRACE_SUSPEND_ISR_ENTER (1U << CH_TRACE_TYPE_ISR_ENTER)
|
||||
#define CH_TRACE_SUSPEND_ISR_LEAVE (1U << CH_TRACE_TYPE_ISR_LEAVE)
|
||||
#define CH_TRACE_SUSPEND_HALT (1U << CH_TRACE_TYPE_HALT)
|
||||
#define CH_TRACE_SUSPEND_USER (1U << CH_TRACE_TYPE_USER)
|
||||
#define CH_TRACE_SUSPEND_ALL (CH_TRACE_SUSPEND_SWITCH | \
|
||||
CH_TRACE_SUSPEND_ISR_ENTER | \
|
||||
CH_TRACE_SUSPEND_ISR_LEAVE | \
|
||||
CH_TRACE_SUSPEND_HALT | \
|
||||
CH_TRACE_SUSPEND_USER)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Events to trace
|
||||
* @{
|
||||
*/
|
||||
#define CH_DBG_TRACE_MASK_NONE 0U
|
||||
#define CH_DBG_TRACE_MASK_SWITCH 1U
|
||||
#define CH_DBG_TRACE_MASK_ISR 2U
|
||||
#define CH_DBG_TRACE_MASK_HALT 4U
|
||||
#define CH_DBG_TRACE_MASK_USER 8U
|
||||
#define CH_DBG_TRACE_MASK_ALL (CH_DBG_TRACE_MASK_SWITCH | \
|
||||
CH_DBG_TRACE_MASK_ISR | \
|
||||
CH_DBG_TRACE_MASK_HALT | \
|
||||
CH_DBG_TRACE_MASK_USER)
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
@ -43,8 +88,17 @@
|
|||
/**
|
||||
* @brief Trace buffer entries.
|
||||
*/
|
||||
#if !defined(CH_DBG_TRACE_MASK) || defined(__DOXYGEN__)
|
||||
#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_ALL
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Trace buffer entries.
|
||||
* @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is
|
||||
* different from @p CH_DBG_TRACE_MASK_NONE.
|
||||
*/
|
||||
#if !defined(CH_DBG_TRACE_BUFFER_SIZE) || defined(__DOXYGEN__)
|
||||
#define CH_DBG_TRACE_BUFFER_SIZE 64
|
||||
#define CH_DBG_TRACE_BUFFER_SIZE 128
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -53,68 +107,113 @@
|
|||
#if !defined(CH_DBG_STACK_FILL_VALUE) || defined(__DOXYGEN__)
|
||||
#define CH_DBG_STACK_FILL_VALUE 0x55
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Fill value for thread area in debug mode.
|
||||
* @note The chosen default value is 0xFF in order to make evident which
|
||||
* thread fields were not initialized when inspecting the memory with
|
||||
* a debugger. A uninitialized field is not an error in itself but it
|
||||
* better to know it.
|
||||
*/
|
||||
#if !defined(CH_DBG_THREAD_FILL_VALUE) || defined(__DOXYGEN__)
|
||||
#define CH_DBG_THREAD_FILL_VALUE 0xFF
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(CH_CFG_TRACE_HOOK)
|
||||
#error "CH_CFG_TRACE_HOOK not defined in chconf.h"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if (CH_DBG_ENABLE_TRACE == TRUE) || defined(__DOXYGEN__)
|
||||
#if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Trace buffer record.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Time of the switch event.
|
||||
* @brief Record type.
|
||||
*/
|
||||
systime_t se_time;
|
||||
/**
|
||||
* @brief Switched in thread.
|
||||
*/
|
||||
thread_t *se_tp;
|
||||
/**
|
||||
* @brief Object where going to sleep.
|
||||
*/
|
||||
void *se_wtobjp;
|
||||
uint32_t type:3;
|
||||
/**
|
||||
* @brief Switched out thread state.
|
||||
*/
|
||||
uint8_t se_state;
|
||||
} ch_swc_event_t;
|
||||
uint32_t state:5;
|
||||
/**
|
||||
* @brief Accurate time stamp.
|
||||
* @note This field only available if the post supports
|
||||
* @p PORT_SUPPORTS_RT else it is set to zero.
|
||||
*/
|
||||
uint32_t rtstamp:24;
|
||||
/**
|
||||
* @brief System time stamp of the switch event.
|
||||
*/
|
||||
systime_t time;
|
||||
union {
|
||||
/**
|
||||
* @brief Structure representing a context switch.
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* @brief Switched in thread.
|
||||
*/
|
||||
thread_t *ntp;
|
||||
/**
|
||||
* @brief Object where going to sleep.
|
||||
*/
|
||||
void *wtobjp;
|
||||
} sw;
|
||||
/**
|
||||
* @brief Structure representing an ISR enter.
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* @brief ISR function name taken using @p __func__.
|
||||
*/
|
||||
const char *name;
|
||||
} isr;
|
||||
/**
|
||||
* @brief Structure representing an halt.
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* @brief Halt error string.
|
||||
*/
|
||||
const char *reason;
|
||||
} halt;
|
||||
/**
|
||||
* @brief User trace structure.
|
||||
*/
|
||||
struct {
|
||||
/**
|
||||
* @brief Trace user parameter 1.
|
||||
*/
|
||||
void *up1;
|
||||
/**
|
||||
* @brief Trace user parameter 2.
|
||||
*/
|
||||
void *up2;
|
||||
} user;
|
||||
} u;
|
||||
} ch_trace_event_t;
|
||||
|
||||
/**
|
||||
* @brief Trace buffer header.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Suspended trace sources mask.
|
||||
*/
|
||||
uint16_t suspended;
|
||||
/**
|
||||
* @brief Trace buffer size (entries).
|
||||
*/
|
||||
unsigned tb_size;
|
||||
uint16_t size;
|
||||
/**
|
||||
* @brief Pointer to the buffer front.
|
||||
*/
|
||||
ch_swc_event_t *tb_ptr;
|
||||
ch_trace_event_t *ptr;
|
||||
/**
|
||||
* @brief Ring buffer.
|
||||
*/
|
||||
ch_swc_event_t tb_buffer[CH_DBG_TRACE_BUFFER_SIZE];
|
||||
ch_trace_event_t buffer[CH_DBG_TRACE_BUFFER_SIZE];
|
||||
} ch_trace_buffer_t;
|
||||
#endif /* CH_DBG_ENABLE_TRACE */
|
||||
#endif /* CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
|
@ -143,10 +242,21 @@ typedef struct {
|
|||
#define chDbgCheckClassS()
|
||||
#endif
|
||||
|
||||
/* When the trace feature is disabled this function is replaced by an empty
|
||||
macro.*/
|
||||
#if CH_DBG_ENABLE_TRACE == FALSE
|
||||
#define _dbg_trace(otp)
|
||||
/* When a trace feature is disabled the associated functions are replaced by
|
||||
an empty macro.*/
|
||||
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_SWITCH) == 0
|
||||
#define _dbg_trace_switch(otp)
|
||||
#endif
|
||||
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_ISR) == 0
|
||||
#define _dbg_trace_isr_enter(isr)
|
||||
#define _dbg_trace_isr_leave(isr)
|
||||
#endif
|
||||
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_HALT) == 0
|
||||
#define _dbg_trace_halt(reason)
|
||||
#endif
|
||||
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_USER) == 0
|
||||
#define chDbgWriteTraceI(up1, up2)
|
||||
#define chDbgWriteTrace(up1, up2)
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -222,10 +332,27 @@ extern "C" {
|
|||
void chDbgCheckClassI(void);
|
||||
void chDbgCheckClassS(void);
|
||||
#endif
|
||||
#if (CH_DBG_ENABLE_TRACE == TRUE) || defined(__DOXYGEN__)
|
||||
#if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE) || defined(__DOXYGEN__)
|
||||
void _dbg_trace_init(void);
|
||||
void _dbg_trace(thread_t *otp);
|
||||
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_SWITCH) != 0
|
||||
void _dbg_trace_switch(thread_t *otp);
|
||||
#endif
|
||||
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_ISR) != 0
|
||||
void _dbg_trace_isr_enter(const char *isr);
|
||||
void _dbg_trace_isr_leave(const char *isr);
|
||||
#endif
|
||||
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_HALT) != 0
|
||||
void _dbg_trace_halt(const char *reason);
|
||||
#endif
|
||||
#if (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_USER) != 0
|
||||
void chDbgWriteTraceI(void *up1, void *up2);
|
||||
void chDbgWriteTrace(void *up1, void *up2);
|
||||
void chDbgSuspendTraceI(uint16_t mask);
|
||||
void chDbgSuspendTrace(uint16_t mask);
|
||||
void chDbgResumeTraceI(uint16_t mask);
|
||||
void chDbgResumeTrace(uint16_t mask);
|
||||
#endif
|
||||
#endif /* CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chdynamic.h
|
||||
* @brief Dynamic threads macros and structures.
|
||||
*
|
||||
* @addtogroup dynamic_threads
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHDYNAMIC_H_
|
||||
#define _CHDYNAMIC_H_
|
||||
|
||||
#if (CH_CFG_USE_DYNAMIC == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*
|
||||
* Module dependencies check.
|
||||
*/
|
||||
#if CH_CFG_USE_WAITEXIT == FALSE
|
||||
#error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_WAITEXIT"
|
||||
#endif
|
||||
|
||||
#if (CH_CFG_USE_HEAP == FALSE) && (CH_CFG_USE_MEMPOOLS == FALSE)
|
||||
#error "CH_CFG_USE_DYNAMIC requires CH_CFG_USE_HEAP and/or CH_CFG_USE_MEMPOOLS"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*
|
||||
* Dynamic threads APIs.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
thread_t *chThdAddRef(thread_t *tp);
|
||||
void chThdRelease(thread_t *tp);
|
||||
#if CH_CFG_USE_HEAP == TRUE
|
||||
thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size,
|
||||
tprio_t prio, tfunc_t pf, void *arg);
|
||||
#endif
|
||||
#if CH_CFG_USE_MEMPOOLS == TRUE
|
||||
thread_t *chThdCreateFromMemoryPool(memory_pool_t *mp, tprio_t prio,
|
||||
tfunc_t pf, void *arg);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#endif /* CH_CFG_USE_DYNAMIC == TRUE */
|
||||
|
||||
#endif /* _CHDYNAMIC_H_ */
|
||||
|
||||
/** @} */
|
|
@ -55,16 +55,16 @@ typedef struct event_listener event_listener_t;
|
|||
* @brief Event Listener structure.
|
||||
*/
|
||||
struct event_listener {
|
||||
event_listener_t *el_next; /**< @brief Next Event Listener
|
||||
event_listener_t *next; /**< @brief Next Event Listener
|
||||
registered on the event
|
||||
source. */
|
||||
thread_t *el_listener; /**< @brief Thread interested in the
|
||||
thread_t *listener; /**< @brief Thread interested in the
|
||||
event source. */
|
||||
eventmask_t el_events; /**< @brief Events to be set in
|
||||
eventmask_t events; /**< @brief Events to be set in
|
||||
the listening thread. */
|
||||
eventflags_t el_flags; /**< @brief Flags added to the listener
|
||||
eventflags_t flags; /**< @brief Flags added to the listener
|
||||
by the event source. */
|
||||
eventflags_t el_wflags; /**< @brief Flags that this listener
|
||||
eventflags_t wflags; /**< @brief Flags that this listener
|
||||
interested in. */
|
||||
};
|
||||
|
||||
|
@ -72,7 +72,7 @@ struct event_listener {
|
|||
* @brief Event Source structure.
|
||||
*/
|
||||
typedef struct event_source {
|
||||
event_listener_t *es_next; /**< @brief First Event Listener
|
||||
event_listener_t *next; /**< @brief First Event Listener
|
||||
registered on the Event
|
||||
Source. */
|
||||
} event_source_t;
|
||||
|
@ -169,7 +169,7 @@ extern "C" {
|
|||
*/
|
||||
static inline void chEvtObjectInit(event_source_t *esp) {
|
||||
|
||||
esp->es_next = (event_listener_t *)esp;
|
||||
esp->next = (event_listener_t *)esp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,7 +223,7 @@ static inline void chEvtRegister(event_source_t *esp,
|
|||
*/
|
||||
static inline bool chEvtIsListeningI(event_source_t *esp) {
|
||||
|
||||
return (bool)(esp != (event_source_t *)esp->es_next);
|
||||
return (bool)(esp != (event_source_t *)esp->next);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chheap.h
|
||||
* @brief Heaps macros and structures.
|
||||
*
|
||||
* @addtogroup heaps
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHHEAP_H_
|
||||
#define _CHHEAP_H_
|
||||
|
||||
#if (CH_CFG_USE_HEAP == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if CH_CFG_USE_MEMCORE == FALSE
|
||||
#error "CH_CFG_USE_HEAP requires CH_CFG_USE_MEMCORE"
|
||||
#endif
|
||||
|
||||
#if (CH_CFG_USE_MUTEXES == FALSE) && (CH_CFG_USE_SEMAPHORES == FALSE)
|
||||
#error "CH_CFG_USE_HEAP requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of a memory heap.
|
||||
*/
|
||||
typedef struct memory_heap memory_heap_t;
|
||||
|
||||
/**
|
||||
* @brief Memory heap block header.
|
||||
*/
|
||||
union heap_header {
|
||||
stkalign_t align;
|
||||
struct {
|
||||
union {
|
||||
union heap_header *next; /**< @brief Next block in free list. */
|
||||
memory_heap_t *heap; /**< @brief Block owner heap. */
|
||||
} u; /**< @brief Overlapped fields. */
|
||||
size_t size; /**< @brief Size of the memory block. */
|
||||
} h;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Structure describing a memory heap.
|
||||
*/
|
||||
struct memory_heap {
|
||||
memgetfunc_t h_provider; /**< @brief Memory blocks provider for
|
||||
this heap. */
|
||||
union heap_header h_free; /**< @brief Free blocks list header. */
|
||||
#if CH_CFG_USE_MUTEXES == TRUE
|
||||
mutex_t h_mtx; /**< @brief Heap access mutex. */
|
||||
#else
|
||||
semaphore_t h_sem; /**< @brief Heap access semaphore. */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void _heap_init(void);
|
||||
void chHeapObjectInit(memory_heap_t *heapp, void *buf, size_t size);
|
||||
void *chHeapAlloc(memory_heap_t *heapp, size_t size);
|
||||
void chHeapFree(void *p);
|
||||
size_t chHeapStatus(memory_heap_t *heapp, size_t *sizep);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#endif /* CH_CFG_USE_HEAP == TRUE */
|
||||
|
||||
#endif /* _CHHEAP_H_ */
|
||||
|
||||
/** @} */
|
|
@ -207,17 +207,14 @@
|
|||
#error "CH_CFG_USE_TM == TRUE, Time Measurement functionality restricted"
|
||||
#endif
|
||||
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
#error "CH_CFG_USE_MUTEXES_RECURSIVE == TRUE, Recursive Mutexes functionality restricted"
|
||||
#if CH_CFG_USE_MUTEXES == TRUE
|
||||
#error "CH_CFG_USE_MUTEXES == TRUE, Recursive Mutexes functionality restricted"
|
||||
#endif
|
||||
|
||||
#if CH_CFG_USE_CONDVARS == TRUE
|
||||
#error "CH_CFG_USE_CONDVARS == TRUE, Condition Variables functionality restricted"
|
||||
#endif
|
||||
|
||||
#if CH_CFG_USE_DYNAMIC == TRUE
|
||||
#error "CH_CFG_USE_DYNAMIC == TRUE, Dynamic Threads functionality restricted"
|
||||
#endif
|
||||
#endif /* CH_LICENSE_FEATURES == CH_FEATURES_BASIC */
|
||||
|
||||
#else
|
||||
|
|
|
@ -1,207 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chmboxes.h
|
||||
* @brief Mailboxes macros and structures.
|
||||
*
|
||||
* @addtogroup mailboxes
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHMBOXES_H_
|
||||
#define _CHMBOXES_H_
|
||||
|
||||
#if (CH_CFG_USE_MAILBOXES == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if CH_CFG_USE_SEMAPHORES == FALSE
|
||||
#error "CH_CFG_USE_MAILBOXES requires CH_CFG_USE_SEMAPHORES"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Structure representing a mailbox object.
|
||||
*/
|
||||
typedef struct {
|
||||
msg_t *mb_buffer; /**< @brief Pointer to the mailbox
|
||||
buffer. */
|
||||
msg_t *mb_top; /**< @brief Pointer to the location
|
||||
after the buffer. */
|
||||
msg_t *mb_wrptr; /**< @brief Write pointer. */
|
||||
msg_t *mb_rdptr; /**< @brief Read pointer. */
|
||||
semaphore_t mb_fullsem; /**< @brief Full counter
|
||||
@p semaphore_t. */
|
||||
semaphore_t mb_emptysem; /**< @brief Empty counter
|
||||
@p semaphore_t. */
|
||||
} mailbox_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Data part of a static mailbox initializer.
|
||||
* @details This macro should be used when statically initializing a
|
||||
* mailbox that is part of a bigger structure.
|
||||
*
|
||||
* @param[in] name the name of the mailbox variable
|
||||
* @param[in] buffer pointer to the mailbox buffer area
|
||||
* @param[in] size size of the mailbox buffer area
|
||||
*/
|
||||
#define _MAILBOX_DATA(name, buffer, size) { \
|
||||
(msg_t *)(buffer), \
|
||||
(msg_t *)(buffer) + size, \
|
||||
(msg_t *)(buffer), \
|
||||
(msg_t *)(buffer), \
|
||||
_SEMAPHORE_DATA(name.mb_fullsem, 0), \
|
||||
_SEMAPHORE_DATA(name.mb_emptysem, size), \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Static mailbox initializer.
|
||||
* @details Statically initialized mailboxes require no explicit
|
||||
* initialization using @p chMBInit().
|
||||
*
|
||||
* @param[in] name the name of the mailbox variable
|
||||
* @param[in] buffer pointer to the mailbox buffer area
|
||||
* @param[in] size size of the mailbox buffer area
|
||||
*/
|
||||
#define MAILBOX_DECL(name, buffer, size) \
|
||||
mailbox_t name = _MAILBOX_DATA(name, buffer, size)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void chMBObjectInit(mailbox_t *mbp, msg_t *buf, cnt_t n);
|
||||
void chMBReset(mailbox_t *mbp);
|
||||
void chMBResetI(mailbox_t *mbp);
|
||||
msg_t chMBPost(mailbox_t *mbp, msg_t msg, systime_t timeout);
|
||||
msg_t chMBPostS(mailbox_t *mbp, msg_t msg, systime_t timeout);
|
||||
msg_t chMBPostI(mailbox_t *mbp, msg_t msg);
|
||||
msg_t chMBPostAhead(mailbox_t *mbp, msg_t msg, systime_t timeout);
|
||||
msg_t chMBPostAheadS(mailbox_t *mbp, msg_t msg, systime_t timeout);
|
||||
msg_t chMBPostAheadI(mailbox_t *mbp, msg_t msg);
|
||||
msg_t chMBFetch(mailbox_t *mbp, msg_t *msgp, systime_t timeout);
|
||||
msg_t chMBFetchS(mailbox_t *mbp, msg_t *msgp, systime_t timeout);
|
||||
msg_t chMBFetchI(mailbox_t *mbp, msg_t *msgp);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Returns the mailbox buffer size.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized mailbox_t object
|
||||
* @return The size of the mailbox.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
static inline size_t chMBGetSizeI(mailbox_t *mbp) {
|
||||
|
||||
/*lint -save -e9033 [10.8] Perfectly safe pointers
|
||||
arithmetic.*/
|
||||
return (size_t)(mbp->mb_top - mbp->mb_buffer);
|
||||
/*lint -restore*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of free message slots into a mailbox.
|
||||
* @note Can be invoked in any system state but if invoked out of a locked
|
||||
* state then the returned value may change after reading.
|
||||
* @note The returned value can be less than zero when there are waiting
|
||||
* threads on the internal semaphore.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized mailbox_t object
|
||||
* @return The number of empty message slots.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
static inline cnt_t chMBGetFreeCountI(mailbox_t *mbp) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
|
||||
return chSemGetCounterI(&mbp->mb_emptysem);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of used message slots into a mailbox.
|
||||
* @note Can be invoked in any system state but if invoked out of a locked
|
||||
* state then the returned value may change after reading.
|
||||
* @note The returned value can be less than zero when there are waiting
|
||||
* threads on the internal semaphore.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized mailbox_t object
|
||||
* @return The number of queued messages.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
static inline cnt_t chMBGetUsedCountI(mailbox_t *mbp) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
|
||||
return chSemGetCounterI(&mbp->mb_fullsem);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the next message in the queue without removing it.
|
||||
* @pre A message must be waiting in the queue for this function to work
|
||||
* or it would return garbage. The correct way to use this macro is
|
||||
* to use @p chMBGetFullCountI() and then use this macro, all within
|
||||
* a lock state.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized mailbox_t object
|
||||
* @return The next message in queue.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
static inline msg_t chMBPeekI(mailbox_t *mbp) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
|
||||
return *mbp->mb_rdptr;
|
||||
}
|
||||
|
||||
#endif /* CH_CFG_USE_MAILBOXES == TRUE */
|
||||
|
||||
#endif /* _CHMBOXES_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,168 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chmempools.h
|
||||
* @brief Memory Pools macros and structures.
|
||||
*
|
||||
* @addtogroup pools
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHMEMPOOLS_H_
|
||||
#define _CHMEMPOOLS_H_
|
||||
|
||||
#if (CH_CFG_USE_MEMPOOLS == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if CH_CFG_USE_MEMCORE == FALSE
|
||||
#error "CH_CFG_USE_MEMPOOLS requires CH_CFG_USE_MEMCORE"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Memory pool free object header.
|
||||
*/
|
||||
struct pool_header {
|
||||
struct pool_header *ph_next; /**< @brief Pointer to the next pool
|
||||
header in the list. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Memory pool descriptor.
|
||||
*/
|
||||
typedef struct {
|
||||
struct pool_header *mp_next; /**< @brief Pointer to the header. */
|
||||
size_t mp_object_size; /**< @brief Memory pool objects
|
||||
size. */
|
||||
memgetfunc_t mp_provider; /**< @brief Memory blocks provider
|
||||
for this pool. */
|
||||
} memory_pool_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Data part of a static memory pool initializer.
|
||||
* @details This macro should be used when statically initializing a
|
||||
* memory pool that is part of a bigger structure.
|
||||
*
|
||||
* @param[in] name the name of the memory pool variable
|
||||
* @param[in] size size of the memory pool contained objects
|
||||
* @param[in] provider memory provider function for the memory pool
|
||||
*/
|
||||
#define _MEMORYPOOL_DATA(name, size, provider) \
|
||||
{NULL, size, provider}
|
||||
|
||||
/**
|
||||
* @brief Static memory pool initializer in hungry mode.
|
||||
* @details Statically initialized memory pools require no explicit
|
||||
* initialization using @p chPoolInit().
|
||||
*
|
||||
* @param[in] name the name of the memory pool variable
|
||||
* @param[in] size size of the memory pool contained objects
|
||||
* @param[in] provider memory provider function for the memory pool or @p NULL
|
||||
* if the pool is not allowed to grow automatically
|
||||
*/
|
||||
#define MEMORYPOOL_DECL(name, size, provider) \
|
||||
memory_pool_t name = _MEMORYPOOL_DATA(name, size, provider)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void chPoolObjectInit(memory_pool_t *mp, size_t size, memgetfunc_t provider);
|
||||
void chPoolLoadArray(memory_pool_t *mp, void *p, size_t n);
|
||||
void *chPoolAllocI(memory_pool_t *mp);
|
||||
void *chPoolAlloc(memory_pool_t *mp);
|
||||
void chPoolFreeI(memory_pool_t *mp, void *objp);
|
||||
void chPoolFree(memory_pool_t *mp, void *objp);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Adds an object to a memory pool.
|
||||
* @pre The memory pool must be already been initialized.
|
||||
* @pre The added object must be of the right size for the specified
|
||||
* memory pool.
|
||||
* @pre The added object must be memory aligned to the size of
|
||||
* @p stkalign_t type.
|
||||
* @note This function is just an alias for @p chPoolFree() and has been
|
||||
* added for clarity.
|
||||
*
|
||||
* @param[in] mp pointer to a @p memory_pool_t structure
|
||||
* @param[in] objp the pointer to the object to be added
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
static inline void chPoolAdd(memory_pool_t *mp, void *objp) {
|
||||
|
||||
chPoolFree(mp, objp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an object to a memory pool.
|
||||
* @pre The memory pool must be already been initialized.
|
||||
* @pre The added object must be of the right size for the specified
|
||||
* memory pool.
|
||||
* @pre The added object must be memory aligned to the size of
|
||||
* @p stkalign_t type.
|
||||
* @note This function is just an alias for @p chPoolFree() and has been
|
||||
* added for clarity.
|
||||
*
|
||||
* @param[in] mp pointer to a @p memory_pool_t structure
|
||||
* @param[in] objp the pointer to the object to be added
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
static inline void chPoolAddI(memory_pool_t *mp, void *objp) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
|
||||
chPoolFreeI(mp, objp);
|
||||
}
|
||||
|
||||
#endif /* CH_CFG_USE_MEMPOOLS == TRUE */
|
||||
|
||||
#endif /* _CHMEMPOOLS_H_ */
|
||||
|
||||
/** @} */
|
|
@ -80,7 +80,7 @@ static inline bool chMsgIsPendingI(thread_t *tp) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
|
||||
return (bool)(tp->p_msgqueue.p_next != (thread_t *)&tp->p_msgqueue);
|
||||
return (bool)(tp->msgqueue.next != (thread_t *)&tp->msgqueue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,9 +95,9 @@ static inline bool chMsgIsPendingI(thread_t *tp) {
|
|||
*/
|
||||
static inline msg_t chMsgGet(thread_t *tp) {
|
||||
|
||||
chDbgAssert(tp->p_state == CH_STATE_SNDMSG, "invalid state");
|
||||
chDbgAssert(tp->state == CH_STATE_SNDMSG, "invalid state");
|
||||
|
||||
return tp->p_u.sentmsg;
|
||||
return tp->u.sentmsg;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -55,14 +55,14 @@ typedef struct ch_mutex mutex_t;
|
|||
* @brief Mutex structure.
|
||||
*/
|
||||
struct ch_mutex {
|
||||
threads_queue_t m_queue; /**< @brief Queue of the threads sleeping
|
||||
threads_queue_t queue; /**< @brief Queue of the threads sleeping
|
||||
on this mutex. */
|
||||
thread_t *m_owner; /**< @brief Owner @p thread_t pointer or
|
||||
thread_t *owner; /**< @brief Owner @p thread_t pointer or
|
||||
@p NULL. */
|
||||
mutex_t *m_next; /**< @brief Next @p mutex_t into an
|
||||
mutex_t *next; /**< @brief Next @p mutex_t into an
|
||||
owner-list or @p NULL. */
|
||||
#if (CH_CFG_USE_MUTEXES_RECURSIVE == TRUE) || defined(__DOXYGEN__)
|
||||
cnt_t m_cnt; /**< @brief Mutex recursion counter. */
|
||||
cnt_t cnt; /**< @brief Mutex recursion counter. */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -78,9 +78,9 @@ struct ch_mutex {
|
|||
* @param[in] name the name of the mutex variable
|
||||
*/
|
||||
#if (CH_CFG_USE_MUTEXES_RECURSIVE == TRUE) || defined(__DOXYGEN__)
|
||||
#define _MUTEX_DATA(name) {_THREADS_QUEUE_DATA(name.m_queue), NULL, NULL, 0}
|
||||
#define _MUTEX_DATA(name) {_THREADS_QUEUE_DATA(name.queue), NULL, NULL, 0}
|
||||
#else
|
||||
#define _MUTEX_DATA(name) {_THREADS_QUEUE_DATA(name.m_queue), NULL, NULL}
|
||||
#define _MUTEX_DATA(name) {_THREADS_QUEUE_DATA(name.queue), NULL, NULL}
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -130,7 +130,7 @@ static inline bool chMtxQueueNotEmptyS(mutex_t *mp) {
|
|||
|
||||
chDbgCheckClassS();
|
||||
|
||||
return queue_notempty(&mp->m_queue);
|
||||
return queue_notempty(&mp->queue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,7 +143,7 @@ static inline bool chMtxQueueNotEmptyS(mutex_t *mp) {
|
|||
*/
|
||||
static inline mutex_t *chMtxGetNextMutexS(void) {
|
||||
|
||||
return chThdGetSelfX()->p_mtxlist;
|
||||
return chThdGetSelfX()->mtxlist;
|
||||
}
|
||||
|
||||
#endif /* CH_CFG_USE_MUTEXES == TRUE */
|
||||
|
|
|
@ -75,15 +75,15 @@ typedef void (*qnotify_t)(io_queue_t *qp);
|
|||
* @ref system_states) and is non-blocking.
|
||||
*/
|
||||
struct io_queue {
|
||||
threads_queue_t q_waiting; /**< @brief Queue of waiting threads. */
|
||||
volatile size_t q_counter; /**< @brief Resources counter. */
|
||||
uint8_t *q_buffer; /**< @brief Pointer to the queue buffer.*/
|
||||
uint8_t *q_top; /**< @brief Pointer to the first location
|
||||
threads_queue_t waiting; /**< @brief Queue of waiting threads. */
|
||||
volatile size_t counter; /**< @brief Resources counter. */
|
||||
uint8_t *buffer; /**< @brief Pointer to the queue buffer.*/
|
||||
uint8_t *top; /**< @brief Pointer to the first location
|
||||
after the buffer. */
|
||||
uint8_t *q_wrptr; /**< @brief Write pointer. */
|
||||
uint8_t *q_rdptr; /**< @brief Read pointer. */
|
||||
qnotify_t q_notify; /**< @brief Data notification callback. */
|
||||
void *q_link; /**< @brief Application defined field. */
|
||||
uint8_t *wrptr; /**< @brief Write pointer. */
|
||||
uint8_t *rdptr; /**< @brief Read pointer. */
|
||||
qnotify_t notify; /**< @brief Data notification callback. */
|
||||
void *link; /**< @brief Application defined field. */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -202,7 +202,7 @@ typedef io_queue_t output_queue_t;
|
|||
*/
|
||||
#define chQSizeX(qp) \
|
||||
/*lint -save -e9033 [10.8] The cast is safe.*/ \
|
||||
((size_t)((qp)->q_top - (qp)->q_buffer)) \
|
||||
((size_t)((qp)->top - (qp)->buffer)) \
|
||||
/*lint -restore*/
|
||||
|
||||
/**
|
||||
|
@ -215,7 +215,7 @@ typedef io_queue_t output_queue_t;
|
|||
*
|
||||
* @iclass
|
||||
*/
|
||||
#define chQSpaceI(qp) ((qp)->q_counter)
|
||||
#define chQSpaceI(qp) ((qp)->counter)
|
||||
|
||||
/**
|
||||
* @brief Returns the queue application-defined link.
|
||||
|
@ -225,7 +225,7 @@ typedef io_queue_t output_queue_t;
|
|||
*
|
||||
* @xclass
|
||||
*/
|
||||
#define chQGetLinkX(qp) ((qp)->q_link)
|
||||
#define chQGetLinkX(qp) ((qp)->link)
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@ -322,7 +322,7 @@ static inline bool chIQIsFullI(input_queue_t *iqp) {
|
|||
chDbgCheckClassI();
|
||||
|
||||
/*lint -save -e9007 [13.5] No side effects.*/
|
||||
return (bool)((iqp->q_wrptr == iqp->q_rdptr) && (iqp->q_counter != 0U));
|
||||
return (bool)((iqp->wrptr == iqp->rdptr) && (iqp->counter != 0U));
|
||||
/*lint -restore*/
|
||||
}
|
||||
|
||||
|
@ -390,7 +390,7 @@ static inline bool chOQIsEmptyI(output_queue_t *oqp) {
|
|||
chDbgCheckClassI();
|
||||
|
||||
/*lint -save -e9007 [13.5] No side effects.*/
|
||||
return (bool)((oqp->q_wrptr == oqp->q_rdptr) && (oqp->q_counter != 0U));
|
||||
return (bool)((oqp->wrptr == oqp->rdptr) && (oqp->counter != 0U));
|
||||
/*lint -restore*/
|
||||
}
|
||||
|
||||
|
|
|
@ -50,26 +50,24 @@
|
|||
* @brief ChibiOS/RT memory signature record.
|
||||
*/
|
||||
typedef struct {
|
||||
char ch_identifier[4]; /**< @brief Always set to "main". */
|
||||
uint8_t ch_zero; /**< @brief Must be zero. */
|
||||
uint8_t ch_size; /**< @brief Size of this structure. */
|
||||
uint16_t ch_version; /**< @brief Encoded ChibiOS/RT version. */
|
||||
uint8_t ch_ptrsize; /**< @brief Size of a pointer. */
|
||||
uint8_t ch_timesize; /**< @brief Size of a @p systime_t. */
|
||||
uint8_t ch_threadsize; /**< @brief Size of a @p thread_t. */
|
||||
uint8_t cf_off_prio; /**< @brief Offset of @p p_prio field. */
|
||||
uint8_t cf_off_ctx; /**< @brief Offset of @p p_ctx field. */
|
||||
uint8_t cf_off_newer; /**< @brief Offset of @p p_newer field. */
|
||||
uint8_t cf_off_older; /**< @brief Offset of @p p_older field. */
|
||||
uint8_t cf_off_name; /**< @brief Offset of @p p_name field. */
|
||||
uint8_t cf_off_stklimit; /**< @brief Offset of @p p_stklimit
|
||||
field. */
|
||||
uint8_t cf_off_state; /**< @brief Offset of @p p_state field. */
|
||||
uint8_t cf_off_flags; /**< @brief Offset of @p p_flags field. */
|
||||
uint8_t cf_off_refs; /**< @brief Offset of @p p_refs field. */
|
||||
uint8_t cf_off_preempt; /**< @brief Offset of @p p_preempt
|
||||
field. */
|
||||
uint8_t cf_off_time; /**< @brief Offset of @p p_time field. */
|
||||
char identifier[4]; /**< @brief Always set to "main". */
|
||||
uint8_t zero; /**< @brief Must be zero. */
|
||||
uint8_t size; /**< @brief Size of this structure. */
|
||||
uint16_t version; /**< @brief Encoded ChibiOS/RT version. */
|
||||
uint8_t ptrsize; /**< @brief Size of a pointer. */
|
||||
uint8_t timesize; /**< @brief Size of a @p systime_t. */
|
||||
uint8_t threadsize; /**< @brief Size of a @p thread_t. */
|
||||
uint8_t off_prio; /**< @brief Offset of @p prio field. */
|
||||
uint8_t off_ctx; /**< @brief Offset of @p ctx field. */
|
||||
uint8_t off_newer; /**< @brief Offset of @p newer field. */
|
||||
uint8_t off_older; /**< @brief Offset of @p older field. */
|
||||
uint8_t off_name; /**< @brief Offset of @p name field. */
|
||||
uint8_t off_stklimit; /**< @brief Offset of @p stklimit field.*/
|
||||
uint8_t off_state; /**< @brief Offset of @p state field. */
|
||||
uint8_t off_flags; /**< @brief Offset of @p flags field. */
|
||||
uint8_t off_refs; /**< @brief Offset of @p refs field. */
|
||||
uint8_t off_preempt; /**< @brief Offset of @p preempt field. */
|
||||
uint8_t off_time; /**< @brief Offset of @p time field. */
|
||||
} chdebug_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@ -83,8 +81,8 @@ typedef struct {
|
|||
* @param[in] tp thread to remove from the registry
|
||||
*/
|
||||
#define REG_REMOVE(tp) { \
|
||||
(tp)->p_older->p_newer = (tp)->p_newer; \
|
||||
(tp)->p_newer->p_older = (tp)->p_older; \
|
||||
(tp)->older->newer = (tp)->newer; \
|
||||
(tp)->newer->older = (tp)->older; \
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,10 +92,10 @@ typedef struct {
|
|||
* @param[in] tp thread to add to the registry
|
||||
*/
|
||||
#define REG_INSERT(tp) { \
|
||||
(tp)->p_newer = (thread_t *)&ch.rlist; \
|
||||
(tp)->p_older = ch.rlist.r_older; \
|
||||
(tp)->p_older->p_newer = (tp); \
|
||||
ch.rlist.r_older = (tp); \
|
||||
(tp)->newer = (thread_t *)&ch.rlist; \
|
||||
(tp)->older = ch.rlist.older; \
|
||||
(tp)->older->newer = (tp); \
|
||||
ch.rlist.older = (tp); \
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@ -132,7 +130,7 @@ extern "C" {
|
|||
static inline void chRegSetThreadName(const char *name) {
|
||||
|
||||
#if CH_CFG_USE_REGISTRY == TRUE
|
||||
ch.rlist.r_current->p_name = name;
|
||||
ch.rlist.current->name = name;
|
||||
#else
|
||||
(void)name;
|
||||
#endif
|
||||
|
@ -152,7 +150,7 @@ static inline void chRegSetThreadName(const char *name) {
|
|||
static inline const char *chRegGetThreadNameX(thread_t *tp) {
|
||||
|
||||
#if CH_CFG_USE_REGISTRY == TRUE
|
||||
return tp->p_name;
|
||||
return tp->name;
|
||||
#else
|
||||
(void)tp;
|
||||
return NULL;
|
||||
|
@ -172,7 +170,7 @@ static inline const char *chRegGetThreadNameX(thread_t *tp) {
|
|||
static inline void chRegSetThreadNameX(thread_t *tp, const char *name) {
|
||||
|
||||
#if CH_CFG_USE_REGISTRY == TRUE
|
||||
tp->p_name = name;
|
||||
tp->name = name;
|
||||
#else
|
||||
(void)tp;
|
||||
(void)name;
|
||||
|
|
|
@ -108,20 +108,8 @@
|
|||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Working Areas and Alignment
|
||||
* @name Working Areas
|
||||
*/
|
||||
/**
|
||||
* @brief Enforces a correct alignment for a stack area size value.
|
||||
*
|
||||
* @param[in] n the stack size to be aligned to the next stack
|
||||
* alignment boundary
|
||||
* @return The aligned stack size.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
#define THD_ALIGN_STACK_SIZE(n) \
|
||||
(((((size_t)(n)) - 1U) | (sizeof(stkalign_t) - 1U)) + 1U)
|
||||
|
||||
/**
|
||||
* @brief Calculates the total Working Area size.
|
||||
*
|
||||
|
@ -131,7 +119,7 @@
|
|||
* @api
|
||||
*/
|
||||
#define THD_WORKING_AREA_SIZE(n) \
|
||||
THD_ALIGN_STACK_SIZE(sizeof(thread_t) + PORT_WA_SIZE(n))
|
||||
MEM_ALIGN_NEXT(sizeof(thread_t) + PORT_WA_SIZE(n), PORT_STACK_ALIGN)
|
||||
|
||||
/**
|
||||
* @brief Static working area allocation.
|
||||
|
@ -143,8 +131,22 @@
|
|||
*
|
||||
* @api
|
||||
*/
|
||||
#define THD_WORKING_AREA(s, n) \
|
||||
stkalign_t s[THD_WORKING_AREA_SIZE(n) / sizeof(stkalign_t)]
|
||||
#define THD_WORKING_AREA(s, n) PORT_WORKING_AREA(s, n)
|
||||
|
||||
/**
|
||||
* @brief Base of a working area casted to the correct type.
|
||||
*
|
||||
* @param[in] s name of the working area
|
||||
*/
|
||||
#define THD_WORKING_AREA_BASE(s) ((stkalign_t *)(s))
|
||||
|
||||
/**
|
||||
* @brief End of a working area casted to the correct type.
|
||||
*
|
||||
* @param[in] s name of the working area
|
||||
*/
|
||||
#define THD_WORKING_AREA_END(s) (THD_WORKING_AREA_BASE(s) + \
|
||||
(sizeof (s) / sizeof (stkalign_t)))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -166,6 +168,18 @@
|
|||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(CH_CFG_IDLE_ENTER_HOOK)
|
||||
#error "CH_CFG_IDLE_ENTER_HOOK not defined in chconf.h"
|
||||
#endif
|
||||
|
||||
#if !defined(CH_CFG_IDLE_LEAVE_HOOK)
|
||||
#error "CH_CFG_IDLE_LEAVE_HOOK not defined in chconf.h"
|
||||
#endif
|
||||
|
||||
#if !defined(CH_CFG_IDLE_LOOP_HOOK)
|
||||
#error "CH_CFG_IDLE_LOOP_HOOK not defined in chconf.h"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
@ -174,15 +188,15 @@
|
|||
* @brief Generic threads single link list, it works like a stack.
|
||||
*/
|
||||
struct ch_threads_list {
|
||||
thread_t *p_next; /**< @brief Next in the list/queue. */
|
||||
thread_t *next; /**< @brief Next in the list/queue. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Generic threads bidirectional linked list header and element.
|
||||
*/
|
||||
struct ch_threads_queue {
|
||||
thread_t *p_next; /**< @brief Next in the list/queue. */
|
||||
thread_t *p_prev; /**< @brief Previous in the queue. */
|
||||
thread_t *next; /**< @brief Next in the list/queue. */
|
||||
thread_t *prev; /**< @brief Previous in the queue. */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -192,55 +206,44 @@ struct ch_threads_queue {
|
|||
* by shrinking this structure.
|
||||
*/
|
||||
struct ch_thread {
|
||||
thread_t *p_next; /**< @brief Next in the list/queue. */
|
||||
thread_t *next; /**< @brief Next in the list/queue. */
|
||||
/* End of the fields shared with the threads_list_t structure.*/
|
||||
thread_t *p_prev; /**< @brief Previous in the queue. */
|
||||
thread_t *prev; /**< @brief Previous in the queue. */
|
||||
/* End of the fields shared with the threads_queue_t structure.*/
|
||||
tprio_t p_prio; /**< @brief Thread priority. */
|
||||
struct context p_ctx; /**< @brief Processor context. */
|
||||
tprio_t prio; /**< @brief Thread priority. */
|
||||
struct port_context ctx; /**< @brief Processor context. */
|
||||
#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
|
||||
thread_t *p_newer; /**< @brief Newer registry element. */
|
||||
thread_t *p_older; /**< @brief Older registry element. */
|
||||
thread_t *newer; /**< @brief Newer registry element. */
|
||||
thread_t *older; /**< @brief Older registry element. */
|
||||
#endif
|
||||
/* End of the fields shared with the ReadyList structure. */
|
||||
#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Thread name or @p NULL.
|
||||
*/
|
||||
const char *p_name;
|
||||
const char *name;
|
||||
#endif
|
||||
#if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Thread stack boundary.
|
||||
* @note This pointer matches with the working area base address.
|
||||
*/
|
||||
stkalign_t *p_stklimit;
|
||||
#endif
|
||||
stkalign_t *stklimit;
|
||||
/**
|
||||
* @brief Current thread state.
|
||||
*/
|
||||
tstate_t p_state;
|
||||
/**
|
||||
* @brief Various thread flags.
|
||||
*/
|
||||
tmode_t p_flags;
|
||||
#if (CH_CFG_USE_DYNAMIC == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief References to this thread.
|
||||
*/
|
||||
trefs_t p_refs;
|
||||
#endif
|
||||
tstate_t state;
|
||||
/**
|
||||
* @brief Number of ticks remaining to this thread.
|
||||
*/
|
||||
#if (CH_CFG_TIME_QUANTUM > 0) || defined(__DOXYGEN__)
|
||||
tslices_t p_preempt;
|
||||
tslices_t preempt;
|
||||
#endif
|
||||
#if (CH_DBG_THREADS_PROFILING == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Thread consumed time in ticks.
|
||||
* @note This field can overflow.
|
||||
*/
|
||||
volatile systime_t p_time;
|
||||
volatile systime_t time;
|
||||
#endif
|
||||
/**
|
||||
* @brief State-specific fields.
|
||||
|
@ -308,48 +311,41 @@ struct ch_thread {
|
|||
*/
|
||||
eventmask_t ewmask;
|
||||
#endif
|
||||
} p_u;
|
||||
} u;
|
||||
#if (CH_CFG_USE_WAITEXIT == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Termination waiting list.
|
||||
*/
|
||||
threads_list_t p_waiting;
|
||||
threads_list_t waiting;
|
||||
#endif
|
||||
#if (CH_CFG_USE_MESSAGES == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Messages queue.
|
||||
*/
|
||||
threads_queue_t p_msgqueue;
|
||||
threads_queue_t msgqueue;
|
||||
#endif
|
||||
#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Pending events mask.
|
||||
*/
|
||||
eventmask_t p_epending;
|
||||
eventmask_t epending;
|
||||
#endif
|
||||
#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief List of the mutexes owned by this thread.
|
||||
* @note The list is terminated by a @p NULL in this field.
|
||||
*/
|
||||
struct ch_mutex *p_mtxlist;
|
||||
struct ch_mutex *mtxlist;
|
||||
/**
|
||||
* @brief Thread's own, non-inherited, priority.
|
||||
*/
|
||||
tprio_t p_realprio;
|
||||
#endif
|
||||
#if ((CH_CFG_USE_DYNAMIC == TRUE) && (CH_CFG_USE_MEMPOOLS == TRUE)) || \
|
||||
defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Memory Pool where the thread workspace is returned.
|
||||
*/
|
||||
void *p_mpool;
|
||||
tprio_t realprio;
|
||||
#endif
|
||||
#if (CH_DBG_STATISTICS == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Thread statistics.
|
||||
*/
|
||||
time_measurement_t p_stats;
|
||||
time_measurement_t stats;
|
||||
#endif
|
||||
#if defined(CH_CFG_THREAD_EXTRA_FIELDS)
|
||||
/* Extra fields defined in chconf.h.*/
|
||||
|
@ -363,12 +359,12 @@ struct ch_thread {
|
|||
* @brief Virtual Timer descriptor structure.
|
||||
*/
|
||||
struct ch_virtual_timer {
|
||||
virtual_timer_t *vt_next; /**< @brief Next timer in the list. */
|
||||
virtual_timer_t *vt_prev; /**< @brief Previous timer in the list. */
|
||||
systime_t vt_delta; /**< @brief Time delta before timeout. */
|
||||
vtfunc_t vt_func; /**< @brief Timer callback function
|
||||
virtual_timer_t *next; /**< @brief Next timer in the list. */
|
||||
virtual_timer_t *prev; /**< @brief Previous timer in the list. */
|
||||
systime_t delta; /**< @brief Time delta before timeout. */
|
||||
vtfunc_t func; /**< @brief Timer callback function
|
||||
pointer. */
|
||||
void *vt_par; /**< @brief Timer callback function
|
||||
void *par; /**< @brief Timer callback function
|
||||
parameter. */
|
||||
};
|
||||
|
||||
|
@ -379,19 +375,19 @@ struct ch_virtual_timer {
|
|||
* timer is often used in the code.
|
||||
*/
|
||||
struct ch_virtual_timers_list {
|
||||
virtual_timer_t *vt_next; /**< @brief Next timer in the delta
|
||||
virtual_timer_t *next; /**< @brief Next timer in the delta
|
||||
list. */
|
||||
virtual_timer_t *vt_prev; /**< @brief Last timer in the delta
|
||||
virtual_timer_t *prev; /**< @brief Last timer in the delta
|
||||
list. */
|
||||
systime_t vt_delta; /**< @brief Must be initialized to -1. */
|
||||
systime_t delta; /**< @brief Must be initialized to -1. */
|
||||
#if (CH_CFG_ST_TIMEDELTA == 0) || defined(__DOXYGEN__)
|
||||
volatile systime_t vt_systime; /**< @brief System Time counter. */
|
||||
volatile systime_t systime; /**< @brief System Time counter. */
|
||||
#endif
|
||||
#if (CH_CFG_ST_TIMEDELTA > 0) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief System time of the last tick event.
|
||||
*/
|
||||
systime_t vt_lasttime;/**< @brief System time of the last
|
||||
systime_t lasttime; /**< @brief System time of the last
|
||||
tick event. */
|
||||
#endif
|
||||
};
|
||||
|
@ -400,17 +396,17 @@ struct ch_virtual_timers_list {
|
|||
* @extends threads_queue_t
|
||||
*/
|
||||
struct ch_ready_list {
|
||||
threads_queue_t r_queue; /**< @brief Threads queue. */
|
||||
tprio_t r_prio; /**< @brief This field must be
|
||||
threads_queue_t queue; /**< @brief Threads queue. */
|
||||
tprio_t prio; /**< @brief This field must be
|
||||
initialized to zero. */
|
||||
struct context r_ctx; /**< @brief Not used, present because
|
||||
struct port_context ctx; /**< @brief Not used, present because
|
||||
offsets. */
|
||||
#if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
|
||||
thread_t *r_newer; /**< @brief Newer registry element. */
|
||||
thread_t *r_older; /**< @brief Older registry element. */
|
||||
thread_t *newer; /**< @brief Newer registry element. */
|
||||
thread_t *older; /**< @brief Older registry element. */
|
||||
#endif
|
||||
/* End of the fields shared with the thread_t structure.*/
|
||||
thread_t *r_current; /**< @brief The currently running
|
||||
thread_t *current; /**< @brief The currently running
|
||||
thread. */
|
||||
};
|
||||
|
||||
|
@ -436,7 +432,7 @@ struct ch_system_debug {
|
|||
*/
|
||||
cnt_t lock_cnt;
|
||||
#endif
|
||||
#if (CH_DBG_ENABLE_TRACE == TRUE) || defined(__DOXYGEN__)
|
||||
#if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Public trace buffer.
|
||||
*/
|
||||
|
@ -478,7 +474,7 @@ struct ch_system {
|
|||
*/
|
||||
kernel_stats_t kernel_stats;
|
||||
#endif
|
||||
#if (CH_CFG_NO_IDLE_THREAD == FALSE) || defined(__DOXYGEN__)
|
||||
#if CH_CFG_NO_IDLE_THREAD == FALSE
|
||||
/**
|
||||
* @brief Idle thread working area.
|
||||
*/
|
||||
|
@ -495,25 +491,14 @@ struct ch_system {
|
|||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define firstprio(rlp) ((rlp)->p_next->p_prio)
|
||||
#define firstprio(rlp) ((rlp)->next->prio)
|
||||
|
||||
/**
|
||||
* @brief Current thread pointer access macro.
|
||||
* @note This macro is not meant to be used in the application code but
|
||||
* only from within the kernel, use the @p chThdSelf() API instead.
|
||||
* @note It is forbidden to use this macro in order to change the pointer
|
||||
* (currp = something), use @p setcurrp() instead.
|
||||
* only from within the kernel, use @p chThdGetSelfX() instead.
|
||||
*/
|
||||
#define currp ch.rlist.r_current
|
||||
|
||||
/**
|
||||
* @brief Current thread pointer change macro.
|
||||
* @note This macro is not meant to be used in the application code but
|
||||
* only from within the kernel.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define setcurrp(tp) (currp = (tp))
|
||||
#define currp ch.rlist.current
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
|
@ -531,6 +516,7 @@ extern "C" {
|
|||
#endif
|
||||
void _scheduler_init(void);
|
||||
thread_t *chSchReadyI(thread_t *tp);
|
||||
thread_t *chSchReadyAheadI(thread_t *tp);
|
||||
void chSchGoSleepS(tstate_t newstate);
|
||||
msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time);
|
||||
void chSchWakeupS(thread_t *ntp, msg_t msg);
|
||||
|
@ -565,7 +551,7 @@ extern "C" {
|
|||
*/
|
||||
static inline void list_init(threads_list_t *tlp) {
|
||||
|
||||
tlp->p_next = (thread_t *)tlp;
|
||||
tlp->next = (thread_t *)tlp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -578,7 +564,7 @@ static inline void list_init(threads_list_t *tlp) {
|
|||
*/
|
||||
static inline bool list_isempty(threads_list_t *tlp) {
|
||||
|
||||
return (bool)(tlp->p_next == (thread_t *)tlp);
|
||||
return (bool)(tlp->next == (thread_t *)tlp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -591,7 +577,7 @@ static inline bool list_isempty(threads_list_t *tlp) {
|
|||
*/
|
||||
static inline bool list_notempty(threads_list_t *tlp) {
|
||||
|
||||
return (bool)(tlp->p_next != (thread_t *)tlp);
|
||||
return (bool)(tlp->next != (thread_t *)tlp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -603,8 +589,8 @@ static inline bool list_notempty(threads_list_t *tlp) {
|
|||
*/
|
||||
static inline void queue_init(threads_queue_t *tqp) {
|
||||
|
||||
tqp->p_next = (thread_t *)tqp;
|
||||
tqp->p_prev = (thread_t *)tqp;
|
||||
tqp->next = (thread_t *)tqp;
|
||||
tqp->prev = (thread_t *)tqp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -617,7 +603,7 @@ static inline void queue_init(threads_queue_t *tqp) {
|
|||
*/
|
||||
static inline bool queue_isempty(const threads_queue_t *tqp) {
|
||||
|
||||
return (bool)(tqp->p_next == (const thread_t *)tqp);
|
||||
return (bool)(tqp->next == (const thread_t *)tqp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -630,7 +616,7 @@ static inline bool queue_isempty(const threads_queue_t *tqp) {
|
|||
*/
|
||||
static inline bool queue_notempty(const threads_queue_t *tqp) {
|
||||
|
||||
return (bool)(tqp->p_next != (const thread_t *)tqp);
|
||||
return (bool)(tqp->next != (const thread_t *)tqp);
|
||||
}
|
||||
|
||||
/* If the performance code path has been chosen then all the following
|
||||
|
@ -638,14 +624,14 @@ static inline bool queue_notempty(const threads_queue_t *tqp) {
|
|||
#if CH_CFG_OPTIMIZE_SPEED == TRUE
|
||||
static inline void list_insert(thread_t *tp, threads_list_t *tlp) {
|
||||
|
||||
tp->p_next = tlp->p_next;
|
||||
tlp->p_next = tp;
|
||||
tp->next = tlp->next;
|
||||
tlp->next = tp;
|
||||
}
|
||||
|
||||
static inline thread_t *list_remove(threads_list_t *tlp) {
|
||||
|
||||
thread_t *tp = tlp->p_next;
|
||||
tlp->p_next = tp->p_next;
|
||||
thread_t *tp = tlp->next;
|
||||
tlp->next = tp->next;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
@ -654,44 +640,44 @@ static inline void queue_prio_insert(thread_t *tp, threads_queue_t *tqp) {
|
|||
|
||||
thread_t *cp = (thread_t *)tqp;
|
||||
do {
|
||||
cp = cp->p_next;
|
||||
} while ((cp != (thread_t *)tqp) && (cp->p_prio >= tp->p_prio));
|
||||
tp->p_next = cp;
|
||||
tp->p_prev = cp->p_prev;
|
||||
tp->p_prev->p_next = tp;
|
||||
cp->p_prev = tp;
|
||||
cp = cp->next;
|
||||
} while ((cp != (thread_t *)tqp) && (cp->prio >= tp->prio));
|
||||
tp->next = cp;
|
||||
tp->prev = cp->prev;
|
||||
tp->prev->next = tp;
|
||||
cp->prev = tp;
|
||||
}
|
||||
|
||||
static inline void queue_insert(thread_t *tp, threads_queue_t *tqp) {
|
||||
|
||||
tp->p_next = (thread_t *)tqp;
|
||||
tp->p_prev = tqp->p_prev;
|
||||
tp->p_prev->p_next = tp;
|
||||
tqp->p_prev = tp;
|
||||
tp->next = (thread_t *)tqp;
|
||||
tp->prev = tqp->prev;
|
||||
tp->prev->next = tp;
|
||||
tqp->prev = tp;
|
||||
}
|
||||
|
||||
static inline thread_t *queue_fifo_remove(threads_queue_t *tqp) {
|
||||
thread_t *tp = tqp->p_next;
|
||||
thread_t *tp = tqp->next;
|
||||
|
||||
tqp->p_next = tp->p_next;
|
||||
tqp->p_next->p_prev = (thread_t *)tqp;
|
||||
tqp->next = tp->next;
|
||||
tqp->next->prev = (thread_t *)tqp;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
static inline thread_t *queue_lifo_remove(threads_queue_t *tqp) {
|
||||
thread_t *tp = tqp->p_prev;
|
||||
thread_t *tp = tqp->prev;
|
||||
|
||||
tqp->p_prev = tp->p_prev;
|
||||
tqp->p_prev->p_next = (thread_t *)tqp;
|
||||
tqp->prev = tp->prev;
|
||||
tqp->prev->next = (thread_t *)tqp;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
static inline thread_t *queue_dequeue(thread_t *tp) {
|
||||
|
||||
tp->p_prev->p_next = tp->p_next;
|
||||
tp->p_next->p_prev = tp->p_prev;
|
||||
tp->prev->next = tp->next;
|
||||
tp->next->prev = tp->prev;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
@ -712,7 +698,7 @@ static inline bool chSchIsRescRequiredI(void) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
|
||||
return firstprio(&ch.rlist.r_queue) > currp->p_prio;
|
||||
return firstprio(&ch.rlist.queue) > currp->prio;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -730,7 +716,7 @@ static inline bool chSchCanYieldS(void) {
|
|||
|
||||
chDbgCheckClassS();
|
||||
|
||||
return firstprio(&ch.rlist.r_queue) >= currp->p_prio;
|
||||
return firstprio(&ch.rlist.queue) >= currp->prio;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -757,11 +743,11 @@ static inline void chSchDoYieldS(void) {
|
|||
* @special
|
||||
*/
|
||||
static inline void chSchPreemption(void) {
|
||||
tprio_t p1 = firstprio(&ch.rlist.r_queue);
|
||||
tprio_t p2 = currp->p_prio;
|
||||
tprio_t p1 = firstprio(&ch.rlist.queue);
|
||||
tprio_t p2 = currp->prio;
|
||||
|
||||
#if CH_CFG_TIME_QUANTUM > 0
|
||||
if (currp->p_preempt > (tslices_t)0) {
|
||||
if (currp->preempt > (tslices_t)0) {
|
||||
if (p1 > p2) {
|
||||
chSchDoRescheduleAhead();
|
||||
}
|
||||
|
|
|
@ -50,9 +50,9 @@
|
|||
* @brief Semaphore structure.
|
||||
*/
|
||||
typedef struct ch_semaphore {
|
||||
threads_queue_t s_queue; /**< @brief Queue of the threads sleeping
|
||||
threads_queue_t queue; /**< @brief Queue of the threads sleeping
|
||||
on this semaphore. */
|
||||
cnt_t s_cnt; /**< @brief The semaphore counter. */
|
||||
cnt_t cnt; /**< @brief The semaphore counter. */
|
||||
} semaphore_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
|
@ -68,7 +68,7 @@ typedef struct ch_semaphore {
|
|||
* @param[in] n the counter initial value, this value must be
|
||||
* non-negative
|
||||
*/
|
||||
#define _SEMAPHORE_DATA(name, n) {_THREADS_QUEUE_DATA(name.s_queue), n}
|
||||
#define _SEMAPHORE_DATA(name, n) {_THREADS_QUEUE_DATA(name.queue), n}
|
||||
|
||||
/**
|
||||
* @brief Static semaphore initializer.
|
||||
|
@ -119,7 +119,7 @@ static inline void chSemFastWaitI(semaphore_t *sp) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
|
||||
sp->s_cnt--;
|
||||
sp->cnt--;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,7 +135,7 @@ static inline void chSemFastSignalI(semaphore_t *sp) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
|
||||
sp->s_cnt++;
|
||||
sp->cnt++;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,7 +150,7 @@ static inline cnt_t chSemGetCounterI(semaphore_t *sp) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
|
||||
return sp->s_cnt;
|
||||
return sp->cnt;
|
||||
}
|
||||
|
||||
#endif /* CH_CFG_USE_SEMAPHORES == TRUE */
|
||||
|
|
|
@ -52,6 +52,26 @@
|
|||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(CH_CFG_IRQ_PROLOGUE_HOOK)
|
||||
#error "CH_CFG_IRQ_PROLOGUE_HOOK not defined in chconf.h"
|
||||
#endif
|
||||
|
||||
#if !defined(CH_CFG_IRQ_EPILOGUE_HOOK)
|
||||
#error "CH_CFG_IRQ_EPILOGUE_HOOK not defined in chconf.h"
|
||||
#endif
|
||||
|
||||
#if !defined(CH_CFG_CONTEXT_SWITCH_HOOK)
|
||||
#error "CH_CFG_CONTEXT_SWITCH_HOOK not defined in chconf.h"
|
||||
#endif
|
||||
|
||||
#if !defined(CH_CFG_SYSTEM_TICK_HOOK)
|
||||
#error "CH_CFG_SYSTEM_TICK_HOOK not defined in chconf.h"
|
||||
#endif
|
||||
|
||||
#if !defined(CH_CFG_SYSTEM_HALT_HOOK)
|
||||
#error "CH_CFG_SYSTEM_HALT_HOOK not defined in chconf.h"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
@ -108,7 +128,9 @@
|
|||
*/
|
||||
#define CH_IRQ_PROLOGUE() \
|
||||
PORT_IRQ_PROLOGUE(); \
|
||||
CH_CFG_IRQ_PROLOGUE_HOOK(); \
|
||||
_stats_increase_irq(); \
|
||||
_dbg_trace_isr_enter(__func__); \
|
||||
_dbg_check_enter_isr()
|
||||
|
||||
/**
|
||||
|
@ -121,6 +143,8 @@
|
|||
*/
|
||||
#define CH_IRQ_EPILOGUE() \
|
||||
_dbg_check_leave_isr(); \
|
||||
_dbg_trace_isr_leave(__func__); \
|
||||
CH_CFG_IRQ_EPILOGUE_HOOK(); \
|
||||
PORT_IRQ_EPILOGUE()
|
||||
|
||||
/**
|
||||
|
@ -261,7 +285,7 @@
|
|||
*/
|
||||
#define chSysSwitch(ntp, otp) { \
|
||||
\
|
||||
_dbg_trace(otp); \
|
||||
_dbg_trace_switch(otp); \
|
||||
_stats_ctxswc(ntp, otp); \
|
||||
CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp); \
|
||||
port_switch(ntp, otp); \
|
||||
|
@ -280,7 +304,7 @@ extern "C" {
|
|||
void chSysTimerHandlerI(void);
|
||||
syssts_t chSysGetStatusAndLockX(void);
|
||||
void chSysRestoreStatusX(syssts_t sts);
|
||||
#if PORT_SUPPORTS_RT
|
||||
#if PORT_SUPPORTS_RT == TRUE
|
||||
bool chSysIsCounterWithinX(rtcnt_t cnt, rtcnt_t start, rtcnt_t end);
|
||||
void chSysPolledDelayX(rtcnt_t cycles);
|
||||
#endif
|
||||
|
@ -364,8 +388,8 @@ static inline void chSysUnlock(void) {
|
|||
in a critical section not followed by a chSchResceduleS(), this means
|
||||
that the current thread has a lower priority than the next thread in
|
||||
the ready list.*/
|
||||
chDbgAssert((ch.rlist.r_queue.p_next == (thread_t *)&ch.rlist.r_queue) ||
|
||||
(ch.rlist.r_current->p_prio >= ch.rlist.r_queue.p_next->p_prio),
|
||||
chDbgAssert((ch.rlist.queue.next == (thread_t *)&ch.rlist.queue) ||
|
||||
(ch.rlist.current->prio >= ch.rlist.queue.next->prio),
|
||||
"priority order violation");
|
||||
|
||||
port_unlock();
|
||||
|
@ -453,7 +477,7 @@ static inline void chSysUnconditionalUnlock(void) {
|
|||
*/
|
||||
static inline thread_t *chSysGetIdleThreadX(void) {
|
||||
|
||||
return ch.rlist.r_queue.p_prev;
|
||||
return ch.rlist.queue.prev;
|
||||
}
|
||||
#endif /* CH_CFG_NO_IDLE_THREAD == FALSE */
|
||||
|
||||
|
|
|
@ -38,6 +38,18 @@
|
|||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(CH_CFG_THREAD_EXTRA_FIELDS)
|
||||
#error "CH_CFG_THREAD_EXTRA_FIELDS not defined in chconf.h"
|
||||
#endif
|
||||
|
||||
#if !defined(CH_CFG_THREAD_INIT_HOOK)
|
||||
#error "CH_CFG_THREAD_INIT_HOOK not defined in chconf.h"
|
||||
#endif
|
||||
|
||||
#if !defined(CH_CFG_THREAD_EXIT_HOOK)
|
||||
#error "CH_CFG_THREAD_EXIT_HOOK not defined in chconf.h"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
@ -51,6 +63,36 @@
|
|||
*/
|
||||
typedef void (*tfunc_t)(void *p);
|
||||
|
||||
/**
|
||||
* @brief Type of a thread descriptor.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Thread name.
|
||||
*/
|
||||
const char *name;
|
||||
/**
|
||||
* @brief Pointer to the working area base.
|
||||
*/
|
||||
stkalign_t *wbase;
|
||||
/**
|
||||
* @brief End of the working area.
|
||||
*/
|
||||
stkalign_t *wend;
|
||||
/**
|
||||
* @brief Thread priority.
|
||||
*/
|
||||
tprio_t prio;
|
||||
/**
|
||||
* @brief Thread function pointer.
|
||||
*/
|
||||
tfunc_t funcp;
|
||||
/**
|
||||
* @brief Thread argument.
|
||||
*/
|
||||
void *arg;
|
||||
} thread_descriptor_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
@ -128,12 +170,14 @@ typedef void (*tfunc_t)(void *p);
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
thread_t *_thread_init(thread_t *tp, tprio_t prio);
|
||||
thread_t *_thread_init(thread_t *tp, const char *name, tprio_t prio);
|
||||
#if CH_DBG_FILL_THREADS == TRUE
|
||||
void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v);
|
||||
#endif
|
||||
thread_t *chThdCreateI(void *wsp, size_t size,
|
||||
tprio_t prio, tfunc_t pf, void *arg);
|
||||
thread_t *chThdCreateSuspendedI(const thread_descriptor_t *tdp);
|
||||
thread_t *chThdCreateSuspended(const thread_descriptor_t *tdp);
|
||||
thread_t *chThdCreateI(const thread_descriptor_t *tdp);
|
||||
thread_t *chThdCreate(const thread_descriptor_t *tdp);
|
||||
thread_t *chThdCreateStatic(void *wsp, size_t size,
|
||||
tprio_t prio, tfunc_t pf, void *arg);
|
||||
thread_t *chThdStart(thread_t *tp);
|
||||
|
@ -146,7 +190,6 @@ extern "C" {
|
|||
msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, systime_t timeout);
|
||||
void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg);
|
||||
void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg);
|
||||
void chThdTerminate(thread_t *tp);
|
||||
void chThdSleep(systime_t time);
|
||||
void chThdSleepUntil(systime_t time);
|
||||
systime_t chThdSleepUntilWindowed(systime_t prev, systime_t next);
|
||||
|
@ -173,7 +216,7 @@ extern "C" {
|
|||
*/
|
||||
static inline thread_t *chThdGetSelfX(void) {
|
||||
|
||||
return ch.rlist.r_current;
|
||||
return ch.rlist.current;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -186,7 +229,7 @@ static inline thread_t *chThdGetSelfX(void) {
|
|||
*/
|
||||
static inline tprio_t chThdGetPriorityX(void) {
|
||||
|
||||
return chThdGetSelfX()->p_prio;
|
||||
return chThdGetSelfX()->prio;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -202,10 +245,23 @@ static inline tprio_t chThdGetPriorityX(void) {
|
|||
#if (CH_DBG_THREADS_PROFILING == TRUE) || defined(__DOXYGEN__)
|
||||
static inline systime_t chThdGetTicksX(thread_t *tp) {
|
||||
|
||||
return tp->p_time;
|
||||
return tp->time;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Returns the stack limit of the specified thread.
|
||||
*
|
||||
* @param[in] tp pointer to the thread
|
||||
* @return The stack limit pointer.
|
||||
*
|
||||
* @xclass
|
||||
*/
|
||||
static inline stkalign_t *chthdGetStackLimitX(thread_t *tp) {
|
||||
|
||||
return tp->stklimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Verifies if the specified thread is in the @p CH_STATE_FINAL state.
|
||||
*
|
||||
|
@ -217,20 +273,7 @@ static inline systime_t chThdGetTicksX(thread_t *tp) {
|
|||
*/
|
||||
static inline bool chThdTerminatedX(thread_t *tp) {
|
||||
|
||||
return (bool)(tp->p_state == CH_STATE_FINAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Verifies if the current thread has a termination request pending.
|
||||
*
|
||||
* @retval true termination request pending.
|
||||
* @retval false termination request not pending.
|
||||
*
|
||||
* @xclass
|
||||
*/
|
||||
static inline bool chThdShouldTerminateX(void) {
|
||||
|
||||
return (bool)((chThdGetSelfX()->p_flags & CH_FLAG_TERMINATE) != (tmode_t)0);
|
||||
return (bool)(tp->state == CH_STATE_FINAL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,7 +287,7 @@ static inline bool chThdShouldTerminateX(void) {
|
|||
*/
|
||||
static inline thread_t *chThdStartI(thread_t *tp) {
|
||||
|
||||
chDbgAssert(tp->p_state == CH_STATE_WTSTART, "wrong state");
|
||||
chDbgAssert(tp->state == CH_STATE_WTSTART, "wrong state");
|
||||
|
||||
return chSchReadyI(tp);
|
||||
}
|
||||
|
@ -316,9 +359,9 @@ static inline void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg) {
|
|||
|
||||
tp = queue_fifo_remove(tqp);
|
||||
|
||||
chDbgAssert(tp->p_state == CH_STATE_QUEUED, "invalid state");
|
||||
chDbgAssert(tp->state == CH_STATE_QUEUED, "invalid state");
|
||||
|
||||
tp->p_u.rdymsg = msg;
|
||||
tp->u.rdymsg = msg;
|
||||
(void) chSchReadyI(tp);
|
||||
}
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ extern "C" {
|
|||
*/
|
||||
static inline void chVTObjectInit(virtual_timer_t *vtp) {
|
||||
|
||||
vtp->vt_func = NULL;
|
||||
vtp->func = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,7 +228,7 @@ static inline void chVTObjectInit(virtual_timer_t *vtp) {
|
|||
static inline systime_t chVTGetSystemTimeX(void) {
|
||||
|
||||
#if CH_CFG_ST_TIMEDELTA == 0
|
||||
return ch.vtlist.vt_systime;
|
||||
return ch.vtlist.systime;
|
||||
#else /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||
return port_timer_get_time();
|
||||
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||
|
@ -344,15 +344,15 @@ static inline bool chVTGetTimersStateI(systime_t *timep) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
|
||||
if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.vt_next) {
|
||||
if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.next) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (timep != NULL) {
|
||||
#if CH_CFG_ST_TIMEDELTA == 0
|
||||
*timep = ch.vtlist.vt_next->vt_delta;
|
||||
*timep = ch.vtlist.next->delta;
|
||||
#else
|
||||
*timep = ch.vtlist.vt_lasttime + ch.vtlist.vt_next->vt_delta +
|
||||
*timep = ch.vtlist.lasttime + ch.vtlist.next->delta +
|
||||
CH_CFG_ST_TIMEDELTA - chVTGetSystemTimeX();
|
||||
#endif
|
||||
}
|
||||
|
@ -374,7 +374,7 @@ static inline bool chVTIsArmedI(virtual_timer_t *vtp) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
|
||||
return (bool)(vtp->vt_func != NULL);
|
||||
return (bool)(vtp->func != NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -504,21 +504,21 @@ static inline void chVTDoTickI(void) {
|
|||
chDbgCheckClassI();
|
||||
|
||||
#if CH_CFG_ST_TIMEDELTA == 0
|
||||
ch.vtlist.vt_systime++;
|
||||
if (&ch.vtlist != (virtual_timers_list_t *)ch.vtlist.vt_next) {
|
||||
ch.vtlist.systime++;
|
||||
if (&ch.vtlist != (virtual_timers_list_t *)ch.vtlist.next) {
|
||||
/* The list is not empty, processing elements on top.*/
|
||||
--ch.vtlist.vt_next->vt_delta;
|
||||
while (ch.vtlist.vt_next->vt_delta == (systime_t)0) {
|
||||
--ch.vtlist.next->delta;
|
||||
while (ch.vtlist.next->delta == (systime_t)0) {
|
||||
virtual_timer_t *vtp;
|
||||
vtfunc_t fn;
|
||||
|
||||
vtp = ch.vtlist.vt_next;
|
||||
fn = vtp->vt_func;
|
||||
vtp->vt_func = NULL;
|
||||
vtp->vt_next->vt_prev = (virtual_timer_t *)&ch.vtlist;
|
||||
ch.vtlist.vt_next = vtp->vt_next;
|
||||
vtp = ch.vtlist.next;
|
||||
fn = vtp->func;
|
||||
vtp->func = NULL;
|
||||
vtp->next->prev = (virtual_timer_t *)&ch.vtlist;
|
||||
ch.vtlist.next = vtp->next;
|
||||
chSysUnlockFromISR();
|
||||
fn(vtp->vt_par);
|
||||
fn(vtp->par);
|
||||
chSysLockFromISR();
|
||||
}
|
||||
}
|
||||
|
@ -527,26 +527,26 @@ static inline void chVTDoTickI(void) {
|
|||
systime_t now, delta;
|
||||
|
||||
/* First timer to be processed.*/
|
||||
vtp = ch.vtlist.vt_next;
|
||||
vtp = ch.vtlist.next;
|
||||
now = chVTGetSystemTimeX();
|
||||
|
||||
/* All timers within the time window are triggered and removed,
|
||||
note that the loop is stopped by the timers header having
|
||||
"ch.vtlist.vt_delta == (systime_t)-1" which is greater than
|
||||
all deltas.*/
|
||||
while (vtp->vt_delta <= (systime_t)(now - ch.vtlist.vt_lasttime)) {
|
||||
while (vtp->delta <= (systime_t)(now - ch.vtlist.lasttime)) {
|
||||
vtfunc_t fn;
|
||||
|
||||
/* The "last time" becomes this timer's expiration time.*/
|
||||
ch.vtlist.vt_lasttime += vtp->vt_delta;
|
||||
ch.vtlist.lasttime += vtp->delta;
|
||||
|
||||
vtp->vt_next->vt_prev = (virtual_timer_t *)&ch.vtlist;
|
||||
ch.vtlist.vt_next = vtp->vt_next;
|
||||
fn = vtp->vt_func;
|
||||
vtp->vt_func = NULL;
|
||||
vtp->next->prev = (virtual_timer_t *)&ch.vtlist;
|
||||
ch.vtlist.next = vtp->next;
|
||||
fn = vtp->func;
|
||||
vtp->func = NULL;
|
||||
|
||||
/* if the list becomes empty then the timer is stopped.*/
|
||||
if (ch.vtlist.vt_next == (virtual_timer_t *)&ch.vtlist) {
|
||||
if (ch.vtlist.next == (virtual_timer_t *)&ch.vtlist) {
|
||||
port_timer_stop_alarm();
|
||||
}
|
||||
|
||||
|
@ -556,7 +556,7 @@ static inline void chVTDoTickI(void) {
|
|||
chSysUnlockFromISR();
|
||||
|
||||
/* The callback is invoked outside the kernel critical zone.*/
|
||||
fn(vtp->vt_par);
|
||||
fn(vtp->par);
|
||||
|
||||
/* Re-entering the critical zone in order to continue the exploration
|
||||
of the list.*/
|
||||
|
@ -564,24 +564,24 @@ static inline void chVTDoTickI(void) {
|
|||
|
||||
/* Next element in the list, the current time could have advanced so
|
||||
recalculating the time window.*/
|
||||
vtp = ch.vtlist.vt_next;
|
||||
vtp = ch.vtlist.next;
|
||||
now = chVTGetSystemTimeX();
|
||||
}
|
||||
|
||||
/* if the list is empty, nothing else to do.*/
|
||||
if (ch.vtlist.vt_next == (virtual_timer_t *)&ch.vtlist) {
|
||||
if (ch.vtlist.next == (virtual_timer_t *)&ch.vtlist) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Recalculating the next alarm time.*/
|
||||
delta = ch.vtlist.vt_lasttime + vtp->vt_delta - now;
|
||||
delta = ch.vtlist.lasttime + vtp->delta - now;
|
||||
if (delta < (systime_t)CH_CFG_ST_TIMEDELTA) {
|
||||
delta = (systime_t)CH_CFG_ST_TIMEDELTA;
|
||||
}
|
||||
port_timer_set_alarm(now + delta);
|
||||
|
||||
chDbgAssert((chVTGetSystemTimeX() - ch.vtlist.vt_lasttime) <=
|
||||
(now + delta - ch.vtlist.vt_lasttime),
|
||||
chDbgAssert((chVTGetSystemTimeX() - ch.vtlist.lasttime) <=
|
||||
(now + delta - ch.vtlist.lasttime),
|
||||
"exceeding delta");
|
||||
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||
}
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ARM/chcore.c
|
||||
* @brief ARM port code.
|
||||
*
|
||||
* @addtogroup ARM_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/** @} */
|
|
@ -1,531 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ARM/chcore.h
|
||||
* @brief ARM7/9 architecture port macros and structures.
|
||||
*
|
||||
* @addtogroup ARM_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHCORE_H_
|
||||
#define _CHCORE_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Architecture and Compiler
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Macro defining a generic ARM architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_ARM
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module because those intrinsic macros are not necessarily defined
|
||||
by the assembler too.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
/**
|
||||
* @brief Compiler name and version.
|
||||
*/
|
||||
#if defined(__GNUC__) || defined(__DOXYGEN__)
|
||||
#define PORT_COMPILER_NAME "GCC " __VERSION__
|
||||
|
||||
#else
|
||||
#error "unsupported compiler"
|
||||
#endif
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name ARM variants
|
||||
* @{
|
||||
*/
|
||||
#define ARM_CORE_ARM7TDMI 7
|
||||
#define ARM_CORE_ARM9 9
|
||||
#define ARM_CORE_CORTEX_A8 108
|
||||
#define ARM_CORE_CORTEX_A9 109
|
||||
/** @} */
|
||||
|
||||
/* Inclusion of the ARM implementation specific parameters.*/
|
||||
#include "armparams.h"
|
||||
|
||||
/**
|
||||
* @brief This port supports a realtime counter.
|
||||
*/
|
||||
#define PORT_SUPPORTS_RT FALSE
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Enables an alternative timer implementation.
|
||||
* @details Usually the port uses a timer interface defined in the file
|
||||
* @p chcore_timer.h, if this option is enabled then the file
|
||||
* @p chcore_timer_alt.h is included instead.
|
||||
*/
|
||||
#if !defined(PORT_USE_ALT_TIMER)
|
||||
#define PORT_USE_ALT_TIMER FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Stack size for the system idle thread.
|
||||
* @details This size depends on the idle thread implementation, usually
|
||||
* the idle thread should take no more space than those reserved
|
||||
* by @p PORT_INT_REQUIRED_STACK.
|
||||
* @note In this port it is set to 32 because the idle thread does have
|
||||
* a stack frame when compiling without optimizations. You may
|
||||
* reduce this value to zero when compiling with optimizations.
|
||||
*/
|
||||
#if !defined(PORT_IDLE_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
|
||||
#define PORT_IDLE_THREAD_STACK_SIZE 32
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Per-thread stack overhead for interrupts servicing.
|
||||
* @details This constant is used in the calculation of the correct working
|
||||
* area size.
|
||||
*/
|
||||
#if !defined(PORT_INT_REQUIRED_STACK) || defined(__DOXYGEN__)
|
||||
#define PORT_INT_REQUIRED_STACK 32
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief If enabled allows the idle thread to enter a low power mode.
|
||||
*/
|
||||
#ifndef ARM_ENABLE_WFI_IDLE
|
||||
#define ARM_ENABLE_WFI_IDLE FALSE
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
/* ARM core check.*/
|
||||
#if (ARM_CORE == ARM_CORE_ARM7TDMI) || defined(__DOXYGEN__)
|
||||
#define PORT_ARCHITECTURE_ARM_ARM7
|
||||
#define PORT_ARCHITECTURE_NAME "ARMv4T"
|
||||
#define PORT_CORE_VARIANT_NAME "ARM7"
|
||||
|
||||
#elif ARM_CORE == ARM_CORE_ARM9
|
||||
#define PORT_ARCHITECTURE_ARM_ARM9
|
||||
#define PORT_ARCHITECTURE_NAME "ARMv5T"
|
||||
#define PORT_CORE_VARIANT_NAME "ARM9"
|
||||
|
||||
#elif ARM_CORE == ARM_CORE_CORTEX_A8
|
||||
#define PORT_ARCHITECTURE_ARM_CORTEXA8
|
||||
#define PORT_ARCHITECTURE_NAME "ARMv7"
|
||||
#define PORT_CORE_VARIANT_NAME "ARM Cortex-A8"
|
||||
|
||||
#elif ARM_CORE == ARM_CORE_CORTEX_A9
|
||||
#define PORT_ARCHITECTURE_ARM_CORTEXA9
|
||||
#define PORT_ARCHITECTURE_NAME "ARMv7"
|
||||
#define PORT_CORE_VARIANT_NAME "ARM Cortex-A9"
|
||||
|
||||
#else
|
||||
#error "unknown or unsupported ARM core"
|
||||
#endif
|
||||
|
||||
#if defined(THUMB_PRESENT)
|
||||
#if defined(THUMB_NO_INTERWORKING)
|
||||
#define PORT_INFO "Pure THUMB mode"
|
||||
#else
|
||||
#define PORT_INFO "Interworking mode"
|
||||
#endif
|
||||
#else
|
||||
#define PORT_INFO "Pure ARM mode"
|
||||
#endif
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
/**
|
||||
* @brief Type of stack and memory alignment enforcement.
|
||||
* @note In this architecture the stack alignment is enforced to 64 bits.
|
||||
*/
|
||||
typedef uint64_t stkalign_t;
|
||||
|
||||
/**
|
||||
* @brief Generic ARM register.
|
||||
*/
|
||||
typedef void *regarm_t;
|
||||
|
||||
/**
|
||||
* @brief Interrupt saved context.
|
||||
* @details This structure represents the stack frame saved during an
|
||||
* interrupt handler.
|
||||
*/
|
||||
struct port_extctx {
|
||||
regarm_t spsr_irq;
|
||||
regarm_t lr_irq;
|
||||
regarm_t r0;
|
||||
regarm_t r1;
|
||||
regarm_t r2;
|
||||
regarm_t r3;
|
||||
regarm_t r12;
|
||||
regarm_t lr_usr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief System saved context.
|
||||
* @details This structure represents the inner stack frame during a context
|
||||
* switch.
|
||||
*/
|
||||
struct port_intctx {
|
||||
regarm_t r4;
|
||||
regarm_t r5;
|
||||
regarm_t r6;
|
||||
regarm_t r7;
|
||||
regarm_t r8;
|
||||
regarm_t r9;
|
||||
regarm_t r10;
|
||||
regarm_t r11;
|
||||
regarm_t lr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p thread_t structure.
|
||||
* @details In this port the structure just holds a pointer to the
|
||||
* @p port_intctx structure representing the stack pointer
|
||||
* at context switch time.
|
||||
*/
|
||||
struct context {
|
||||
struct port_intctx *r13;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p chThdCreateI() API.
|
||||
* @details This code usually setup the context switching frame represented
|
||||
* by an @p port_intctx structure.
|
||||
*/
|
||||
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
|
||||
(tp)->p_ctx.r13 = (struct port_intctx *)((uint8_t *)(workspace) + \
|
||||
(wsize) - \
|
||||
sizeof(struct port_intctx)); \
|
||||
(tp)->p_ctx.r13->r4 = (regarm_t)(pf); \
|
||||
(tp)->p_ctx.r13->r5 = (regarm_t)(arg); \
|
||||
(tp)->p_ctx.r13->lr = (regarm_t)(_port_thread_start); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the thread working area global size.
|
||||
* @note There is no need to perform alignments in this macro.
|
||||
*/
|
||||
#define PORT_WA_SIZE(n) (sizeof(struct port_intctx) + \
|
||||
sizeof(struct port_extctx) + \
|
||||
((size_t)(n)) + ((size_t)(PORT_INT_REQUIRED_STACK)))
|
||||
|
||||
/**
|
||||
* @brief Priority level verification macro.
|
||||
* @todo Add the required parameters to armparams.h.
|
||||
*/
|
||||
#define PORT_IRQ_IS_VALID_PRIORITY(n) false
|
||||
|
||||
/**
|
||||
* @brief IRQ prologue code.
|
||||
* @details This macro must be inserted at the start of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#define PORT_IRQ_PROLOGUE()
|
||||
|
||||
/**
|
||||
* @brief IRQ epilogue code.
|
||||
* @details This macro must be inserted at the end of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#define PORT_IRQ_EPILOGUE() return chSchIsPreemptionRequired()
|
||||
|
||||
/**
|
||||
* @brief IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_IRQ_HANDLER(id) bool id(void)
|
||||
|
||||
/**
|
||||
* @brief Fast IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_FAST_IRQ_HANDLER(id) \
|
||||
__attribute__((interrupt("FIQ"))) void id(void)
|
||||
|
||||
/**
|
||||
* @brief Performs a context switch between two threads.
|
||||
* @details This is the most critical code in any port, this function
|
||||
* is responsible for the context switch between 2 threads.
|
||||
* @note The implementation of this code affects <b>directly</b> the context
|
||||
* switch performance so optimize here as much as you can.
|
||||
* @note Implemented as inlined code for performance reasons.
|
||||
*
|
||||
* @param[in] ntp the thread to be switched in
|
||||
* @param[in] otp the thread to be switched out
|
||||
*/
|
||||
#if defined(THUMB)
|
||||
|
||||
#if CH_DBG_ENABLE_STACK_CHECK == TRUE
|
||||
#define port_switch(ntp, otp) { \
|
||||
register struct port_intctx *r13 asm ("r13"); \
|
||||
if ((stkalign_t *)(r13 - 1) < otp->p_stklimit) \
|
||||
chSysHalt("stack overflow"); \
|
||||
_port_switch_thumb(ntp, otp); \
|
||||
}
|
||||
#else
|
||||
#define port_switch(ntp, otp) _port_switch_thumb(ntp, otp)
|
||||
#endif
|
||||
|
||||
#else /* !defined(THUMB) */
|
||||
|
||||
#if CH_DBG_ENABLE_STACK_CHECK == TRUE
|
||||
#define port_switch(ntp, otp) { \
|
||||
register struct port_intctx *r13 asm ("r13"); \
|
||||
if ((stkalign_t *)(r13 - 1) < otp->p_stklimit) \
|
||||
chSysHalt("stack overflow"); \
|
||||
_port_switch_arm(ntp, otp); \
|
||||
}
|
||||
#else
|
||||
#define port_switch(ntp, otp) _port_switch_arm(ntp, otp)
|
||||
#endif
|
||||
|
||||
#endif /* !defined(THUMB) */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#if defined(THUMB_PRESENT)
|
||||
syssts_t _port_get_cpsr(void);
|
||||
#endif
|
||||
#if defined(THUMB)
|
||||
void _port_switch_thumb(thread_t *ntp, thread_t *otp);
|
||||
#else
|
||||
void _port_switch_arm(thread_t *ntp, thread_t *otp);
|
||||
#endif
|
||||
void _port_thread_start(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Port-related initialization code.
|
||||
*/
|
||||
static inline void port_init(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a word encoding the current interrupts status.
|
||||
*
|
||||
* @return The interrupts status.
|
||||
*/
|
||||
static inline syssts_t port_get_irq_status(void) {
|
||||
syssts_t sts;
|
||||
|
||||
#if defined(THUMB)
|
||||
sts = _port_get_cpsr();
|
||||
#else
|
||||
__asm volatile ("mrs %[p0], CPSR" : [p0] "=r" (sts) :);
|
||||
#endif
|
||||
/*lint -save -e530 [9.1] Asm instruction not seen by lint.*/
|
||||
return sts;
|
||||
/*lint -restore*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the interrupt status.
|
||||
*
|
||||
* @param[in] sts the interrupt status word
|
||||
*
|
||||
* @return The interrupt status.
|
||||
* @retvel false the word specified a disabled interrupts status.
|
||||
* @retvel true the word specified an enabled interrupts status.
|
||||
*/
|
||||
static inline bool port_irq_enabled(syssts_t sts) {
|
||||
|
||||
return (sts & (syssts_t)0x80) == (syssts_t)0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines the current execution context.
|
||||
*
|
||||
* @return The execution context.
|
||||
* @retval false not running in ISR mode.
|
||||
* @retval true running in ISR mode.
|
||||
*/
|
||||
static inline bool port_is_isr_context(void) {
|
||||
syssts_t sts;
|
||||
|
||||
#if defined(THUMB)
|
||||
sts = _port_get_cpsr();
|
||||
#else
|
||||
__asm volatile ("mrs %[p0], CPSR" : [p0] "=r" (sts) :);
|
||||
#endif
|
||||
|
||||
/*lint -save -e530 [9.1] Asm instruction not seen by lint.*/
|
||||
return (sts & (syssts_t)0x1F) == (syssts_t)0x12;
|
||||
/*lint -restore*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action.
|
||||
* @details In this port it disables the IRQ sources and keeps FIQ sources
|
||||
* enabled.
|
||||
*/
|
||||
static inline void port_lock(void) {
|
||||
|
||||
#if defined(THUMB)
|
||||
__asm volatile ("bl _port_lock_thumb" : : : "r3", "lr", "memory");
|
||||
#else
|
||||
__asm volatile ("msr CPSR_c, #0x9F" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action.
|
||||
* @details In this port it enables both the IRQ and FIQ sources.
|
||||
*/
|
||||
static inline void port_unlock(void) {
|
||||
|
||||
#if defined(THUMB)
|
||||
__asm volatile ("bl _port_unlock_thumb" : : : "r3", "lr", "memory");
|
||||
#else
|
||||
__asm volatile ("msr CPSR_c, #0x1F" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action from an interrupt handler.
|
||||
* @note Empty in this port.
|
||||
*/
|
||||
static inline void port_lock_from_isr(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action from an interrupt handler.
|
||||
* @note Empty in this port.
|
||||
*/
|
||||
static inline void port_unlock_from_isr(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables all the interrupt sources.
|
||||
* @details In this port it disables both the IRQ and FIQ sources.
|
||||
* @note Implements a workaround for spurious interrupts taken from the NXP
|
||||
* LPC214x datasheet.
|
||||
*/
|
||||
static inline void port_disable(void) {
|
||||
|
||||
#if defined(THUMB)
|
||||
__asm volatile ("bl _port_disable_thumb" : : : "r3", "lr", "memory");
|
||||
#else
|
||||
__asm volatile ("mrs r3, CPSR \n\t"
|
||||
"orr r3, #0x80 \n\t"
|
||||
"msr CPSR_c, r3 \n\t"
|
||||
"orr r3, #0x40 \n\t"
|
||||
"msr CPSR_c, r3" : : : "r3", "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables the interrupt sources below kernel-level priority.
|
||||
* @note Interrupt sources above kernel level remains enabled.
|
||||
* @note In this port it disables the IRQ sources and enables the
|
||||
* FIQ sources.
|
||||
*/
|
||||
static inline void port_suspend(void) {
|
||||
|
||||
#if defined(THUMB)
|
||||
__asm volatile ("bl _port_suspend_thumb" : : : "r3", "lr", "memory");
|
||||
#else
|
||||
__asm volatile ("msr CPSR_c, #0x9F" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables all the interrupt sources.
|
||||
* @note In this port it enables both the IRQ and FIQ sources.
|
||||
*/
|
||||
static inline void port_enable(void) {
|
||||
|
||||
#if defined(THUMB)
|
||||
__asm volatile ("bl _port_enable_thumb" : : : "r3", "lr", "memory");
|
||||
#else
|
||||
__asm volatile ("msr CPSR_c, #0x1F" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enters an architecture-dependent IRQ-waiting mode.
|
||||
* @details The function is meant to return when an interrupt becomes pending.
|
||||
* The simplest implementation is an empty function or macro but this
|
||||
* would not take advantage of architecture-specific power saving
|
||||
* modes.
|
||||
* @note Implemented as an inlined @p WFI instruction.
|
||||
*/
|
||||
static inline void port_wait_for_interrupt(void) {
|
||||
|
||||
#if ARM_ENABLE_WFI_IDLE == TRUE
|
||||
ARM_WFI_IMPL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CH_CFG_ST_TIMEDELTA > 0
|
||||
#if PORT_USE_ALT_TIMER == FALSE
|
||||
#include "chcore_timer.h"
|
||||
#else /* PORT_USE_ALT_TIMER */
|
||||
#include "chcore_timer_alt.h"
|
||||
#endif /* PORT_USE_ALT_TIMER */
|
||||
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
#endif /* _CHCORE_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chcore_timer.h
|
||||
* @brief System timer header file.
|
||||
*
|
||||
* @addtogroup ARM_TIMER
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHCORE_TIMER_H_
|
||||
#define _CHCORE_TIMER_H_
|
||||
|
||||
/* This is the only header in the HAL designed to be include-able alone.*/
|
||||
#include "st.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Starts the alarm.
|
||||
* @note Makes sure that no spurious alarms are triggered after
|
||||
* this call.
|
||||
*
|
||||
* @param[in] time the time to be set for the first alarm
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void port_timer_start_alarm(systime_t time) {
|
||||
|
||||
stStartAlarm(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the alarm interrupt.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void port_timer_stop_alarm(void) {
|
||||
|
||||
stStopAlarm();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the alarm time.
|
||||
*
|
||||
* @param[in] time the time to be set for the next alarm
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void port_timer_set_alarm(systime_t time) {
|
||||
|
||||
stSetAlarm(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the system time.
|
||||
*
|
||||
* @return The system time.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline systime_t port_timer_get_time(void) {
|
||||
|
||||
return stGetCounter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current alarm time.
|
||||
*
|
||||
* @return The currently set alarm time.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline systime_t port_timer_get_alarm(void) {
|
||||
|
||||
return stGetAlarm();
|
||||
}
|
||||
|
||||
#endif /* _CHCORE_TIMER_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,278 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ARM/compilers/GCC/chcoreasm.s
|
||||
* @brief ARM architecture port low level code.
|
||||
*
|
||||
* @addtogroup ARM_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define _FROM_ASM_
|
||||
#include "chconf.h"
|
||||
#include "armparams.h"
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
.set MODE_USR, 0x10
|
||||
.set MODE_FIQ, 0x11
|
||||
.set MODE_IRQ, 0x12
|
||||
.set MODE_SVC, 0x13
|
||||
.set MODE_ABT, 0x17
|
||||
.set MODE_UND, 0x1B
|
||||
.set MODE_SYS, 0x1F
|
||||
|
||||
.equ I_BIT, 0x80
|
||||
.equ F_BIT, 0x40
|
||||
|
||||
.text
|
||||
|
||||
/*
|
||||
* The following functions are only present if there is THUMB code in
|
||||
* the system.
|
||||
*/
|
||||
#if defined(THUMB_PRESENT)
|
||||
.balign 16
|
||||
.code 16
|
||||
.thumb_func
|
||||
.global _port_get_cpsr
|
||||
_port_get_cpsr:
|
||||
mov r0, pc
|
||||
bx r0
|
||||
.code 32
|
||||
mrs r0, CPSR
|
||||
bx lr
|
||||
|
||||
.balign 16
|
||||
.code 16
|
||||
.thumb_func
|
||||
.global _port_disable_thumb
|
||||
_port_disable_thumb:
|
||||
mov r3, pc
|
||||
bx r3
|
||||
.code 32
|
||||
mrs r3, CPSR
|
||||
orr r3, #I_BIT
|
||||
msr CPSR_c, r3
|
||||
orr r3, #F_BIT
|
||||
msr CPSR_c, r3
|
||||
bx lr
|
||||
|
||||
.balign 16
|
||||
.code 16
|
||||
.thumb_func
|
||||
.global _port_suspend_thumb
|
||||
_port_suspend_thumb:
|
||||
// Goes into _port_unlock_thumb
|
||||
|
||||
.code 16
|
||||
.global _port_lock_thumb
|
||||
_port_lock_thumb:
|
||||
mov r3, pc
|
||||
bx r3
|
||||
.code 32
|
||||
msr CPSR_c, #MODE_SYS | I_BIT
|
||||
bx lr
|
||||
|
||||
.balign 16
|
||||
.code 16
|
||||
.thumb_func
|
||||
.global _port_enable_thumb
|
||||
_port_enable_thumb:
|
||||
// Goes into _port_unlock_thumb
|
||||
|
||||
.code 16
|
||||
.global _port_unlock_thumb
|
||||
_port_unlock_thumb:
|
||||
mov r3, pc
|
||||
bx r3
|
||||
.code 32
|
||||
msr CPSR_c, #MODE_SYS
|
||||
bx lr
|
||||
#endif /* defined(THUMB_PRESENT) */
|
||||
|
||||
.balign 16
|
||||
#if defined(THUMB_PRESENT)
|
||||
.code 16
|
||||
.thumb_func
|
||||
.global _port_switch_thumb
|
||||
_port_switch_thumb:
|
||||
mov r2, pc
|
||||
bx r2
|
||||
// Goes into _port_switch_arm in ARM mode
|
||||
#endif /* defined(THUMB_PRESENT) */
|
||||
|
||||
.code 32
|
||||
.global _port_switch_arm
|
||||
_port_switch_arm:
|
||||
stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
|
||||
str sp, [r1, #12]
|
||||
ldr sp, [r0, #12]
|
||||
#if defined(THUMB_PRESENT)
|
||||
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
|
||||
bx lr
|
||||
#else /* !defined(THUMB_PRESENT)T */
|
||||
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||
#endif /* !defined(THUMB_PRESENT) */
|
||||
|
||||
/*
|
||||
* Common IRQ code. It expects a macro ARM_IRQ_VECTOR_REG with the address
|
||||
* of a register holding the address of the ISR to be invoked, the ISR
|
||||
* then returns in the common epilogue code where the context switch will
|
||||
* be performed, if required.
|
||||
* System stack frame structure after a context switch in the
|
||||
* interrupt handler:
|
||||
*
|
||||
* High +------------+
|
||||
* | LR_USR | -+
|
||||
* | r12 | |
|
||||
* | r3 | |
|
||||
* | r2 | | External context: IRQ handler frame
|
||||
* | r1 | |
|
||||
* | r0 | |
|
||||
* | LR_IRQ | | (user code return address)
|
||||
* | PSR_USR | -+ (user code status)
|
||||
* | .... | <- chSchDoReschedule() stack frame, optimize it for space
|
||||
* | LR | -+ (system code return address)
|
||||
* | r11 | |
|
||||
* | r10 | |
|
||||
* | r9 | |
|
||||
* | r8 | | Internal context: chSysSwitch() frame
|
||||
* | r7 | |
|
||||
* | r6 | |
|
||||
* | r5 | |
|
||||
* SP-> | r4 | -+
|
||||
* Low +------------+
|
||||
*/
|
||||
.balign 16
|
||||
.code 32
|
||||
.global Irq_Handler
|
||||
Irq_Handler:
|
||||
stmfd sp!, {r0-r3, r12, lr}
|
||||
ldr r0, =ARM_IRQ_VECTOR_REG
|
||||
ldr r0, [r0]
|
||||
#if !defined(THUMB_NO_INTERWORKING)
|
||||
ldr lr, =_irq_ret_arm // ISR return point.
|
||||
bx r0 // Calling the ISR.
|
||||
_irq_ret_arm:
|
||||
#else /* defined(THUMB_NO_INTERWORKING) */
|
||||
add r1, pc, #1
|
||||
bx r1
|
||||
.code 16
|
||||
bl _bxr0 // Calling the ISR.
|
||||
mov lr, pc
|
||||
bx lr
|
||||
.code 32
|
||||
#endif /* defined(THUMB_NO_INTERWORKING) */
|
||||
cmp r0, #0
|
||||
ldmfd sp!, {r0-r3, r12, lr}
|
||||
subeqs pc, lr, #4 // No reschedule, returns.
|
||||
|
||||
// Now the frame is created in the system stack, the IRQ
|
||||
// stack is empty.
|
||||
msr CPSR_c, #MODE_SYS | I_BIT
|
||||
stmfd sp!, {r0-r3, r12, lr}
|
||||
msr CPSR_c, #MODE_IRQ | I_BIT
|
||||
mrs r0, SPSR
|
||||
mov r1, lr
|
||||
msr CPSR_c, #MODE_SYS | I_BIT
|
||||
stmfd sp!, {r0, r1} // Push R0=SPSR, R1=LR_IRQ.
|
||||
|
||||
// Context switch.
|
||||
#if defined(THUMB_NO_INTERWORKING)
|
||||
add r0, pc, #1
|
||||
bx r0
|
||||
.code 16
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_lock
|
||||
#endif
|
||||
bl chSchDoReschedule
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
mov lr, pc
|
||||
bx lr
|
||||
.code 32
|
||||
#else /* !defined(THUMB_NO_INTERWORKING) */
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_lock
|
||||
#endif
|
||||
bl chSchDoReschedule
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#endif /* !defined(THUMB_NO_INTERWORKING) */
|
||||
|
||||
// Re-establish the IRQ conditions again.
|
||||
ldmfd sp!, {r0, r1} // Pop R0=SPSR, R1=LR_IRQ.
|
||||
msr CPSR_c, #MODE_IRQ | I_BIT
|
||||
msr SPSR_fsxc, r0
|
||||
mov lr, r1
|
||||
msr CPSR_c, #MODE_SYS | I_BIT
|
||||
ldmfd sp!, {r0-r3, r12, lr}
|
||||
msr CPSR_c, #MODE_IRQ | I_BIT
|
||||
subs pc, lr, #4
|
||||
#if defined(THUMB_NO_INTERWORKING)
|
||||
.code 16
|
||||
_bxr0: bx r0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Threads trampoline code.
|
||||
* NOTE: The threads always start in ARM mode and then switches to the
|
||||
* thread-function mode.
|
||||
*/
|
||||
.balign 16
|
||||
.code 32
|
||||
.globl _port_thread_start
|
||||
_port_thread_start:
|
||||
#if defined(THUMB_NO_INTERWORKING)
|
||||
add r0, pc, #1
|
||||
bx r0
|
||||
.code 16
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
bl _port_unlock_thumb
|
||||
mov r0, r5
|
||||
bl _bxr4
|
||||
bl chThdExit
|
||||
_zombies: b _zombies
|
||||
_bxr4: bx r4
|
||||
|
||||
#else /* !defined(THUMB_NO_INTERWORKING) */
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
msr CPSR_c, #MODE_SYS
|
||||
mov r0, r5
|
||||
mov lr, pc
|
||||
bx r4
|
||||
mov r0, #0 /* MSG_OK */
|
||||
bl chThdExit
|
||||
_zombies: b _zombies
|
||||
#endif /* !defined(THUMB_NO_INTERWORKING) */
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/** @} */
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ARM/compilers/GCC/chtypes.h
|
||||
* @brief ARM port system types.
|
||||
*
|
||||
* @addtogroup ARM_GCC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHTYPES_H_
|
||||
#define _CHTYPES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @name Common constants
|
||||
*/
|
||||
/**
|
||||
* @brief Generic 'false' boolean constant.
|
||||
*/
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generic 'true' boolean constant.
|
||||
*/
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Kernel types
|
||||
* @{
|
||||
*/
|
||||
typedef uint32_t rtcnt_t; /**< Realtime counter. */
|
||||
typedef uint64_t rttime_t; /**< Realtime accumulator. */
|
||||
typedef uint32_t syssts_t; /**< System status word. */
|
||||
typedef uint8_t tmode_t; /**< Thread flags. */
|
||||
typedef uint8_t tstate_t; /**< Thread state. */
|
||||
typedef uint8_t trefs_t; /**< Thread references counter. */
|
||||
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
|
||||
typedef uint32_t tprio_t; /**< Thread priority. */
|
||||
typedef int32_t msg_t; /**< Inter-thread message. */
|
||||
typedef int32_t eventid_t; /**< Numeric event identifier. */
|
||||
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
|
||||
typedef uint32_t eventflags_t; /**< Mask of event flags. */
|
||||
typedef int32_t cnt_t; /**< Generic signed counter. */
|
||||
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief ROM constant modifier.
|
||||
* @note It is set to use the "const" keyword in this port.
|
||||
*/
|
||||
#define ROMCONST const
|
||||
|
||||
/**
|
||||
* @brief Makes functions not inlineable.
|
||||
* @note If the compiler does not support such attribute then the
|
||||
* realtime counter precision could be degraded.
|
||||
*/
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
|
||||
/**
|
||||
* @brief Optimized thread function declaration macro.
|
||||
*/
|
||||
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
|
||||
|
||||
/**
|
||||
* @brief Packed variable specifier.
|
||||
*/
|
||||
#define PACKED_VAR __attribute__((packed))
|
||||
|
||||
#endif /* _CHTYPES_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,7 +0,0 @@
|
|||
# List of the ChibiOS/RT ARM generic port files.
|
||||
PORTSRC = ${CHIBIOS}/os/rt/ports/ARM/chcore.c
|
||||
|
||||
PORTASM = $(CHIBIOS)/os/rt/ports/ARM/compilers/GCC/chcoreasm.s
|
||||
|
||||
PORTINC = ${CHIBIOS}/os/rt/ports/ARM \
|
||||
${CHIBIOS}/os/rt/ports/ARM/compilers/GCC
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ARMCMx/chcore.c
|
||||
* @brief ARM Cortex-Mx port code.
|
||||
*
|
||||
* @addtogroup ARMCMx_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/** @} */
|
|
@ -1,214 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ARMCMx/chcore.h
|
||||
* @brief ARM Cortex-Mx port macros and structures.
|
||||
*
|
||||
* @addtogroup ARMCMx_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHCORE_H_
|
||||
#define _CHCORE_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Architecture and Compiler
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Macro defining a generic ARM architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_ARM
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module because those intrinsic macros are not necessarily defined
|
||||
by the assembler too.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
/**
|
||||
* @brief Compiler name and version.
|
||||
*/
|
||||
#if defined(__GNUC__) || defined(__DOXYGEN__)
|
||||
#define PORT_COMPILER_NAME "GCC " __VERSION__
|
||||
|
||||
#elif defined(__ICCARM__)
|
||||
#define PORT_COMPILER_NAME "IAR"
|
||||
|
||||
#elif defined(__CC_ARM)
|
||||
#define PORT_COMPILER_NAME "RVCT"
|
||||
|
||||
#else
|
||||
#error "unsupported compiler"
|
||||
#endif
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
/** @} */
|
||||
|
||||
/* Inclusion of the Cortex-Mx implementation specific parameters.*/
|
||||
#include "cmparams.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Enables an alternative timer implementation.
|
||||
* @details Usually the port uses a timer interface defined in the file
|
||||
* @p chcore_timer.h, if this option is enabled then the file
|
||||
* @p chcore_timer_alt.h is included instead.
|
||||
*/
|
||||
#if !defined(PORT_USE_ALT_TIMER)
|
||||
#define PORT_USE_ALT_TIMER FALSE
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
/**
|
||||
* @brief Type of a generic ARM register.
|
||||
*/
|
||||
typedef void *regarm_t;
|
||||
|
||||
/**
|
||||
* @brief Type of stack and memory alignment enforcement.
|
||||
* @note In this architecture the stack alignment is enforced to 64 bits,
|
||||
* 32 bits alignment is supported by hardware but deprecated by ARM,
|
||||
* the implementation choice is to not offer the option.
|
||||
*/
|
||||
typedef uint64_t stkalign_t;
|
||||
|
||||
/* The following declarations are there just for Doxygen documentation, the
|
||||
real declarations are inside the sub-headers being specific for the
|
||||
sub-architectures.*/
|
||||
#if defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Interrupt saved context.
|
||||
* @details This structure represents the stack frame saved during a
|
||||
* preemption-capable interrupt handler.
|
||||
* @note It is implemented to match the Cortex-Mx exception context.
|
||||
*/
|
||||
struct port_extctx {};
|
||||
|
||||
/**
|
||||
* @brief System saved context.
|
||||
* @details This structure represents the inner stack frame during a context
|
||||
* switch.
|
||||
*/
|
||||
struct port_intctx {};
|
||||
#endif /* defined(__DOXYGEN__) */
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p thread_t structure.
|
||||
* @details In this port the structure just holds a pointer to the
|
||||
* @p port_intctx structure representing the stack pointer
|
||||
* at context switch time.
|
||||
*/
|
||||
struct context {
|
||||
struct port_intctx *r13;
|
||||
};
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Total priority levels.
|
||||
*/
|
||||
#define CORTEX_PRIORITY_LEVELS (1U << CORTEX_PRIORITY_BITS)
|
||||
|
||||
/**
|
||||
* @brief Minimum priority level.
|
||||
* @details This minimum priority level is calculated from the number of
|
||||
* priority bits supported by the specific Cortex-Mx implementation.
|
||||
*/
|
||||
#define CORTEX_MINIMUM_PRIORITY (CORTEX_PRIORITY_LEVELS - 1)
|
||||
|
||||
/**
|
||||
* @brief Maximum priority level.
|
||||
* @details The maximum allowed priority level is always zero.
|
||||
*/
|
||||
#define CORTEX_MAXIMUM_PRIORITY 0U
|
||||
|
||||
/**
|
||||
* @brief Priority level to priority mask conversion macro.
|
||||
*/
|
||||
#define CORTEX_PRIO_MASK(n) \
|
||||
((n) << (8U - (unsigned)CORTEX_PRIORITY_BITS))
|
||||
|
||||
/**
|
||||
* @brief Priority level verification macro.
|
||||
*/
|
||||
#define PORT_IRQ_IS_VALID_PRIORITY(n) \
|
||||
(((n) >= 0U) && ((n) < CORTEX_PRIORITY_LEVELS))
|
||||
|
||||
/**
|
||||
* @brief Priority level verification macro.
|
||||
*/
|
||||
#define PORT_IRQ_IS_VALID_KERNEL_PRIORITY(n) \
|
||||
(((n) >= CORTEX_MAX_KERNEL_PRIORITY) && ((n) < CORTEX_PRIORITY_LEVELS))
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* Includes the sub-architecture-specific part.*/
|
||||
#if (CORTEX_MODEL == 0) || (CORTEX_MODEL == 1)
|
||||
#include "chcore_v6m.h"
|
||||
#elif (CORTEX_MODEL == 3) || (CORTEX_MODEL == 4) || (CORTEX_MODEL == 7)
|
||||
#include "chcore_v7m.h"
|
||||
#else
|
||||
#error "unknown Cortex-M variant"
|
||||
#endif
|
||||
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
#if CH_CFG_ST_TIMEDELTA > 0
|
||||
#if PORT_USE_ALT_TIMER == FALSE
|
||||
#include "chcore_timer.h"
|
||||
#else /* PORT_USE_ALT_TIMER != FALSE */
|
||||
#include "chcore_timer_alt.h"
|
||||
#endif /* PORT_USE_ALT_TIMER != FALSE */
|
||||
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
#endif /* _CHCORE_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chcore_timer.h
|
||||
* @brief System timer header file.
|
||||
*
|
||||
* @addtogroup ARMCMx_TIMER
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHCORE_TIMER_H_
|
||||
#define _CHCORE_TIMER_H_
|
||||
|
||||
/* This is the only header in the HAL designed to be include-able alone.*/
|
||||
#include "st.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Starts the alarm.
|
||||
* @note Makes sure that no spurious alarms are triggered after
|
||||
* this call.
|
||||
*
|
||||
* @param[in] time the time to be set for the first alarm
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void port_timer_start_alarm(systime_t time) {
|
||||
|
||||
stStartAlarm(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the alarm interrupt.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void port_timer_stop_alarm(void) {
|
||||
|
||||
stStopAlarm();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the alarm time.
|
||||
*
|
||||
* @param[in] time the time to be set for the next alarm
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void port_timer_set_alarm(systime_t time) {
|
||||
|
||||
stSetAlarm(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the system time.
|
||||
*
|
||||
* @return The system time.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline systime_t port_timer_get_time(void) {
|
||||
|
||||
return stGetCounter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current alarm time.
|
||||
*
|
||||
* @return The currently set alarm time.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline systime_t port_timer_get_alarm(void) {
|
||||
|
||||
return stGetAlarm();
|
||||
}
|
||||
|
||||
#endif /* _CHCORE_TIMER_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chcore_v6m.c
|
||||
* @brief ARMv6-M architecture port code.
|
||||
*
|
||||
* @addtogroup ARMCMx_V6M_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if (CORTEX_ALTERNATE_SWITCH == FALSE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief NMI vector.
|
||||
* @details The NMI vector is used for exception mode re-entering after a
|
||||
* context switch.
|
||||
*/
|
||||
/*lint -save -e9075 [8.4] All symbols are invoked from asm context.*/
|
||||
void NMI_Handler(void) {
|
||||
/*lint -restore*/
|
||||
|
||||
/* The port_extctx structure is pointed by the PSP register.*/
|
||||
struct port_extctx *ctxp = (struct port_extctx *)__get_PSP();
|
||||
|
||||
/* Discarding the current exception context and positioning the stack to
|
||||
point to the real one.*/
|
||||
ctxp++;
|
||||
|
||||
/* Writing back the modified PSP value.*/
|
||||
__set_PSP((uint32_t)ctxp);
|
||||
|
||||
/* Restoring the normal interrupts status.*/
|
||||
port_unlock_from_isr();
|
||||
}
|
||||
#endif /* !CORTEX_ALTERNATE_SWITCH */
|
||||
|
||||
#if (CORTEX_ALTERNATE_SWITCH == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief PendSV vector.
|
||||
* @details The PendSV vector is used for exception mode re-entering after a
|
||||
* context switch.
|
||||
*/
|
||||
/*lint -save -e9075 [8.4] All symbols are invoked from asm context.*/
|
||||
void PendSV_Handler(void) {
|
||||
/*lint -restore*/
|
||||
|
||||
/* The port_extctx structure is pointed by the PSP register.*/
|
||||
struct port_extctx *ctxp = (struct port_extctx *)__get_PSP();
|
||||
|
||||
/* Discarding the current exception context and positioning the stack to
|
||||
point to the real one.*/
|
||||
ctxp++;
|
||||
|
||||
/* Writing back the modified PSP value.*/
|
||||
__set_PSP((uint32_t)ctxp);
|
||||
}
|
||||
#endif /* CORTEX_ALTERNATE_SWITCH */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief IRQ epilogue code.
|
||||
*
|
||||
* @param[in] lr value of the @p LR register on ISR entry
|
||||
*/
|
||||
void _port_irq_epilogue(regarm_t lr) {
|
||||
|
||||
if (lr != (regarm_t)0xFFFFFFF1U) {
|
||||
struct port_extctx *ctxp;
|
||||
|
||||
port_lock_from_isr();
|
||||
|
||||
/* The extctx structure is pointed by the PSP register.*/
|
||||
ctxp = (struct port_extctx *)__get_PSP();
|
||||
|
||||
/* Adding an artificial exception return context, there is no need to
|
||||
populate it fully.*/
|
||||
ctxp--;
|
||||
|
||||
/* Writing back the modified PSP value.*/
|
||||
__set_PSP((uint32_t)ctxp);
|
||||
|
||||
/* Setting up a fake XPSR register value.*/
|
||||
ctxp->xpsr = (regarm_t)0x01000000;
|
||||
|
||||
/* The exit sequence is different depending on if a preemption is
|
||||
required or not.*/
|
||||
if (chSchIsPreemptionRequired()) {
|
||||
/* Preemption is required we need to enforce a context switch.*/
|
||||
ctxp->pc = (regarm_t)_port_switch_from_isr;
|
||||
}
|
||||
else {
|
||||
/* Preemption not required, we just need to exit the exception
|
||||
atomically.*/
|
||||
ctxp->pc = (regarm_t)_port_exit_from_isr;
|
||||
}
|
||||
|
||||
/* Note, returning without unlocking is intentional, this is done in
|
||||
order to keep the rest of the context switch atomic.*/
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,407 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chcore_v6m.h
|
||||
* @brief ARMv6-M architecture port macros and structures.
|
||||
*
|
||||
* @addtogroup ARMCMx_V6M_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHCORE_V6M_H_
|
||||
#define _CHCORE_V6M_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief This port does not support a realtime counter.
|
||||
*/
|
||||
#define PORT_SUPPORTS_RT FALSE
|
||||
|
||||
/**
|
||||
* @brief PendSV priority level.
|
||||
* @note This priority is enforced to be equal to @p 0,
|
||||
* this handler always has the highest priority that cannot preempt
|
||||
* the kernel.
|
||||
*/
|
||||
#define CORTEX_PRIORITY_PENDSV 0
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Stack size for the system idle thread.
|
||||
* @details This size depends on the idle thread implementation, usually
|
||||
* the idle thread should take no more space than those reserved
|
||||
* by @p PORT_INT_REQUIRED_STACK.
|
||||
* @note In this port it is set to 16 because the idle thread does have
|
||||
* a stack frame when compiling without optimizations. You may
|
||||
* reduce this value to zero when compiling with optimizations.
|
||||
*/
|
||||
#if !defined(PORT_IDLE_THREAD_STACK_SIZE)
|
||||
#define PORT_IDLE_THREAD_STACK_SIZE 16
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Per-thread stack overhead for interrupts servicing.
|
||||
* @details This constant is used in the calculation of the correct working
|
||||
* area size.
|
||||
* @note In this port this value is conservatively set to 64 because the
|
||||
* function @p chSchDoReschedule() can have a stack frame, especially
|
||||
* with compiler optimizations disabled. The value can be reduced
|
||||
* when compiler optimizations are enabled.
|
||||
*/
|
||||
#if !defined(PORT_INT_REQUIRED_STACK)
|
||||
#define PORT_INT_REQUIRED_STACK 64
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enables the use of the WFI instruction in the idle thread loop.
|
||||
*/
|
||||
#if !defined(CORTEX_ENABLE_WFI_IDLE)
|
||||
#define CORTEX_ENABLE_WFI_IDLE FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Alternate preemption method.
|
||||
* @details Activating this option will make the Kernel use the PendSV
|
||||
* handler for preemption instead of the NMI handler.
|
||||
*/
|
||||
#ifndef CORTEX_ALTERNATE_SWITCH
|
||||
#define CORTEX_ALTERNATE_SWITCH FALSE
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Architecture and Compiler
|
||||
* @{
|
||||
*/
|
||||
#if ((CORTEX_MODEL == 0) && !defined(__CORE_CM0PLUS_H_DEPENDANT)) || \
|
||||
defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Macro defining the specific ARM architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_ARM_v6M
|
||||
|
||||
/**
|
||||
* @brief Name of the implemented architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_NAME "ARMv6-M"
|
||||
|
||||
/**
|
||||
* @brief Name of the architecture variant.
|
||||
*/
|
||||
#define PORT_CORE_VARIANT_NAME "Cortex-M0"
|
||||
|
||||
#elif (CORTEX_MODEL == 0) && defined(__CORE_CM0PLUS_H_DEPENDANT)
|
||||
#define PORT_ARCHITECTURE_ARM_v6M
|
||||
#define PORT_ARCHITECTURE_NAME "ARMv6-M"
|
||||
#define PORT_CORE_VARIANT_NAME "Cortex-M0+"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Port-specific information string.
|
||||
*/
|
||||
#if (CORTEX_ALTERNATE_SWITCH == FALSE) || defined(__DOXYGEN__)
|
||||
#define PORT_INFO "Preemption through NMI"
|
||||
#else
|
||||
#define PORT_INFO "Preemption through PendSV"
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Maximum usable priority for normal ISRs.
|
||||
*/
|
||||
#if (CORTEX_ALTERNATE_SWITCH == TRUE) || defined(__DOXYGEN__)
|
||||
#define CORTEX_MAX_KERNEL_PRIORITY 1
|
||||
#else
|
||||
#define CORTEX_MAX_KERNEL_PRIORITY 0
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
/* The documentation of the following declarations is in chconf.h in order
|
||||
to not have duplicated structure names into the documentation.*/
|
||||
#if !defined(__DOXYGEN__)
|
||||
struct port_extctx {
|
||||
regarm_t r0;
|
||||
regarm_t r1;
|
||||
regarm_t r2;
|
||||
regarm_t r3;
|
||||
regarm_t r12;
|
||||
regarm_t lr_thd;
|
||||
regarm_t pc;
|
||||
regarm_t xpsr;
|
||||
};
|
||||
|
||||
struct port_intctx {
|
||||
regarm_t r8;
|
||||
regarm_t r9;
|
||||
regarm_t r10;
|
||||
regarm_t r11;
|
||||
regarm_t r4;
|
||||
regarm_t r5;
|
||||
regarm_t r6;
|
||||
regarm_t r7;
|
||||
regarm_t lr;
|
||||
};
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p chThdCreateI() API.
|
||||
* @details This code usually setup the context switching frame represented
|
||||
* by an @p port_intctx structure.
|
||||
*/
|
||||
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
|
||||
(tp)->p_ctx.r13 = (struct port_intctx *)((uint8_t *)(workspace) + \
|
||||
(wsize) - \
|
||||
sizeof(struct port_intctx)); \
|
||||
(tp)->p_ctx.r13->r4 = (regarm_t)(pf); \
|
||||
(tp)->p_ctx.r13->r5 = (regarm_t)(arg); \
|
||||
(tp)->p_ctx.r13->lr = (regarm_t)_port_thread_start; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the thread working area global size.
|
||||
* @note There is no need to perform alignments in this macro.
|
||||
*/
|
||||
#define PORT_WA_SIZE(n) (sizeof(struct port_intctx) + \
|
||||
sizeof(struct port_extctx) + \
|
||||
((size_t)(n)) + ((size_t)(PORT_INT_REQUIRED_STACK)))
|
||||
|
||||
/**
|
||||
* @brief IRQ prologue code.
|
||||
* @details This macro must be inserted at the start of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#if defined(__GNUC__) || defined(__DOXYGEN__)
|
||||
#define PORT_IRQ_PROLOGUE() \
|
||||
regarm_t _saved_lr = (regarm_t)__builtin_return_address(0)
|
||||
#elif defined(__ICCARM__)
|
||||
#define PORT_IRQ_PROLOGUE() \
|
||||
regarm_t _saved_lr = (regarm_t)__get_LR()
|
||||
#elif defined(__CC_ARM)
|
||||
#define PORT_IRQ_PROLOGUE() \
|
||||
regarm_t _saved_lr = (regarm_t)__return_address()
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief IRQ epilogue code.
|
||||
* @details This macro must be inserted at the end of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#define PORT_IRQ_EPILOGUE() _port_irq_epilogue(_saved_lr)
|
||||
|
||||
/**
|
||||
* @brief IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_IRQ_HANDLER(id) void id(void)
|
||||
|
||||
/**
|
||||
* @brief Fast IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_FAST_IRQ_HANDLER(id) void id(void)
|
||||
|
||||
/**
|
||||
* @brief Performs a context switch between two threads.
|
||||
* @details This is the most critical code in any port, this function
|
||||
* is responsible for the context switch between 2 threads.
|
||||
* @note The implementation of this code affects <b>directly</b> the context
|
||||
* switch performance so optimize here as much as you can.
|
||||
*
|
||||
* @param[in] ntp the thread to be switched in
|
||||
* @param[in] otp the thread to be switched out
|
||||
*/
|
||||
#if (CH_DBG_ENABLE_STACK_CHECK == FALSE) || defined(__DOXYGEN__)
|
||||
#define port_switch(ntp, otp) _port_switch(ntp, otp)
|
||||
#else
|
||||
#define port_switch(ntp, otp) { \
|
||||
struct port_intctx *r13 = (struct port_intctx *)__get_PSP(); \
|
||||
if ((stkalign_t *)(r13 - 1) < (otp)->p_stklimit) { \
|
||||
chSysHalt("stack overflow"); \
|
||||
} \
|
||||
_port_switch(ntp, otp); \
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void _port_irq_epilogue(regarm_t lr);
|
||||
void _port_switch(thread_t *ntp, thread_t *otp);
|
||||
void _port_thread_start(void);
|
||||
void _port_switch_from_isr(void);
|
||||
void _port_exit_from_isr(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Port-related initialization code.
|
||||
*/
|
||||
static inline void port_init(void) {
|
||||
|
||||
NVIC_SetPriority(PendSV_IRQn, CORTEX_PRIORITY_PENDSV);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a word encoding the current interrupts status.
|
||||
*
|
||||
* @return The interrupts status.
|
||||
*/
|
||||
static inline syssts_t port_get_irq_status(void) {
|
||||
|
||||
return (syssts_t)__get_PRIMASK();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the interrupt status.
|
||||
*
|
||||
* @param[in] sts the interrupt status word
|
||||
*
|
||||
* @return The interrupt status.
|
||||
* @retvel false the word specified a disabled interrupts status.
|
||||
* @retvel true the word specified an enabled interrupts status.
|
||||
*/
|
||||
static inline bool port_irq_enabled(syssts_t sts) {
|
||||
|
||||
return (sts & (syssts_t)1) == (syssts_t)0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines the current execution context.
|
||||
*
|
||||
* @return The execution context.
|
||||
* @retval false not running in ISR mode.
|
||||
* @retval true running in ISR mode.
|
||||
*/
|
||||
static inline bool port_is_isr_context(void) {
|
||||
|
||||
return (bool)((__get_IPSR() & 0x1FFU) != 0U);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action.
|
||||
* @details In this port this function disables interrupts globally.
|
||||
*/
|
||||
static inline void port_lock(void) {
|
||||
|
||||
__disable_irq();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action.
|
||||
* @details In this port this function enables interrupts globally.
|
||||
*/
|
||||
static inline void port_unlock(void) {
|
||||
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action from an interrupt handler.
|
||||
* @details In this port this function disables interrupts globally.
|
||||
* @note Same as @p port_lock() in this port.
|
||||
*/
|
||||
static inline void port_lock_from_isr(void) {
|
||||
|
||||
port_lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action from an interrupt handler.
|
||||
* @details In this port this function enables interrupts globally.
|
||||
* @note Same as @p port_lock() in this port.
|
||||
*/
|
||||
static inline void port_unlock_from_isr(void) {
|
||||
|
||||
port_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables all the interrupt sources.
|
||||
*/
|
||||
static inline void port_disable(void) {
|
||||
|
||||
__disable_irq();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables the interrupt sources below kernel-level priority.
|
||||
*/
|
||||
static inline void port_suspend(void) {
|
||||
|
||||
__disable_irq();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables all the interrupt sources.
|
||||
*/
|
||||
static inline void port_enable(void) {
|
||||
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enters an architecture-dependent IRQ-waiting mode.
|
||||
* @details The function is meant to return when an interrupt becomes pending.
|
||||
* The simplest implementation is an empty function or macro but this
|
||||
* would not take advantage of architecture-specific power saving
|
||||
* modes.
|
||||
* @note Implemented as an inlined @p WFI instruction.
|
||||
*/
|
||||
static inline void port_wait_for_interrupt(void) {
|
||||
|
||||
#if CORTEX_ENABLE_WFI_IDLE == TRUE
|
||||
__WFI();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* _FROM_ASM_ */
|
||||
|
||||
#endif /* _CHCORE_V6M_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,168 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chcore_v7m.c
|
||||
* @brief ARMv7-M architecture port code.
|
||||
*
|
||||
* @addtogroup ARMCMx_V7M_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief SVC vector.
|
||||
* @details The SVC vector is used for exception mode re-entering after a
|
||||
* context switch.
|
||||
* @note The PendSV vector is only used in advanced kernel mode.
|
||||
*/
|
||||
/*lint -save -e9075 [8.4] All symbols are invoked from asm context.*/
|
||||
void SVC_Handler(void) {
|
||||
/*lint -restore*/
|
||||
struct port_extctx *ctxp;
|
||||
|
||||
#if CORTEX_USE_FPU
|
||||
/* Enforcing unstacking of the FP part of the context.*/
|
||||
FPU->FPCCR &= ~FPU_FPCCR_LSPACT_Msk;
|
||||
#endif
|
||||
|
||||
/* The port_extctx structure is pointed by the PSP register.*/
|
||||
ctxp = (struct port_extctx *)__get_PSP();
|
||||
|
||||
/* Discarding the current exception context and positioning the stack to
|
||||
point to the real one.*/
|
||||
ctxp++;
|
||||
|
||||
/* Restoring real position of the original stack frame.*/
|
||||
__set_PSP((uint32_t)ctxp);
|
||||
|
||||
/* Restoring the normal interrupts status.*/
|
||||
port_unlock_from_isr();
|
||||
}
|
||||
#endif /* CORTEX_SIMPLIFIED_PRIORITY == FALSE */
|
||||
|
||||
#if (CORTEX_SIMPLIFIED_PRIORITY == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief PendSV vector.
|
||||
* @details The PendSV vector is used for exception mode re-entering after a
|
||||
* context switch.
|
||||
* @note The PendSV vector is only used in compact kernel mode.
|
||||
*/
|
||||
/*lint -save -e9075 [8.4] All symbols are invoked from asm context.*/
|
||||
void PendSV_Handler(void) {
|
||||
/*lint -restore*/
|
||||
struct port_extctx *ctxp;
|
||||
|
||||
#if CORTEX_USE_FPU
|
||||
/* Enforcing unstacking of the FP part of the context.*/
|
||||
FPU->FPCCR &= ~FPU_FPCCR_LSPACT_Msk;
|
||||
#endif
|
||||
|
||||
/* The port_extctx structure is pointed by the PSP register.*/
|
||||
ctxp = (struct port_extctx *)__get_PSP();
|
||||
|
||||
/* Discarding the current exception context and positioning the stack to
|
||||
point to the real one.*/
|
||||
ctxp++;
|
||||
|
||||
/* Writing back the modified PSP value.*/
|
||||
__set_PSP((uint32_t)ctxp);
|
||||
}
|
||||
#endif /* CORTEX_SIMPLIFIED_PRIORITY == TRUE */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Exception exit redirection to _port_switch_from_isr().
|
||||
*/
|
||||
void _port_irq_epilogue(void) {
|
||||
|
||||
port_lock_from_isr();
|
||||
if ((SCB->ICSR & SCB_ICSR_RETTOBASE_Msk) != 0U) {
|
||||
struct port_extctx *ctxp;
|
||||
|
||||
#if CORTEX_USE_FPU == TRUE
|
||||
/* Enforcing a lazy FPU state save by accessing the FPCSR register.*/
|
||||
(void) __get_FPSCR();
|
||||
#endif
|
||||
|
||||
/* The port_extctx structure is pointed by the PSP register.*/
|
||||
ctxp = (struct port_extctx *)__get_PSP();
|
||||
|
||||
/* Adding an artificial exception return context, there is no need to
|
||||
populate it fully.*/
|
||||
ctxp--;
|
||||
|
||||
/* Setting up a fake XPSR register value.*/
|
||||
ctxp->xpsr = (regarm_t)0x01000000;
|
||||
#if CORTEX_USE_FPU == TRUE
|
||||
ctxp->fpscr = (regarm_t)FPU->FPDSCR;
|
||||
#endif
|
||||
|
||||
/* Writing back the modified PSP value.*/
|
||||
__set_PSP((uint32_t)ctxp);
|
||||
|
||||
/* The exit sequence is different depending on if a preemption is
|
||||
required or not.*/
|
||||
if (chSchIsPreemptionRequired()) {
|
||||
/* Preemption is required we need to enforce a context switch.*/
|
||||
ctxp->pc = (regarm_t)_port_switch_from_isr;
|
||||
}
|
||||
else {
|
||||
/* Preemption not required, we just need to exit the exception
|
||||
atomically.*/
|
||||
ctxp->pc = (regarm_t)_port_exit_from_isr;
|
||||
}
|
||||
|
||||
/* Note, returning without unlocking is intentional, this is done in
|
||||
order to keep the rest of the context switch atomic.*/
|
||||
return;
|
||||
}
|
||||
port_unlock_from_isr();
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,577 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chcore_v7m.h
|
||||
* @brief ARMv7-M architecture port macros and structures.
|
||||
*
|
||||
* @addtogroup ARMCMx_V7M_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHCORE_V7M_H_
|
||||
#define _CHCORE_V7M_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief This port supports a realtime counter.
|
||||
*/
|
||||
#define PORT_SUPPORTS_RT TRUE
|
||||
|
||||
/**
|
||||
* @brief Disabled value for BASEPRI register.
|
||||
*/
|
||||
#define CORTEX_BASEPRI_DISABLED 0U
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Stack size for the system idle thread.
|
||||
* @details This size depends on the idle thread implementation, usually
|
||||
* the idle thread should take no more space than those reserved
|
||||
* by @p PORT_INT_REQUIRED_STACK.
|
||||
* @note In this port it is set to 16 because the idle thread does have
|
||||
* a stack frame when compiling without optimizations. You may
|
||||
* reduce this value to zero when compiling with optimizations.
|
||||
*/
|
||||
#if !defined(PORT_IDLE_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
|
||||
#define PORT_IDLE_THREAD_STACK_SIZE 16
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Per-thread stack overhead for interrupts servicing.
|
||||
* @details This constant is used in the calculation of the correct working
|
||||
* area size.
|
||||
* @note In this port this value is conservatively set to 64 because the
|
||||
* function @p chSchDoReschedule() can have a stack frame, especially
|
||||
* with compiler optimizations disabled. The value can be reduced
|
||||
* when compiler optimizations are enabled.
|
||||
*/
|
||||
#if !defined(PORT_INT_REQUIRED_STACK) || defined(__DOXYGEN__)
|
||||
#define PORT_INT_REQUIRED_STACK 64
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enables the use of the WFI instruction in the idle thread loop.
|
||||
*/
|
||||
#if !defined(CORTEX_ENABLE_WFI_IDLE)
|
||||
#define CORTEX_ENABLE_WFI_IDLE FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief FPU support in context switch.
|
||||
* @details Activating this option activates the FPU support in the kernel.
|
||||
*/
|
||||
#if !defined(CORTEX_USE_FPU)
|
||||
#define CORTEX_USE_FPU CORTEX_HAS_FPU
|
||||
#elif (CORTEX_USE_FPU == TRUE) && (CORTEX_HAS_FPU == FALSE)
|
||||
/* This setting requires an FPU presence check in case it is externally
|
||||
redefined.*/
|
||||
#error "the selected core does not have an FPU"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Simplified priority handling flag.
|
||||
* @details Activating this option makes the Kernel work in compact mode.
|
||||
* In compact mode interrupts are disabled globally instead of
|
||||
* raising the priority mask to some intermediate level.
|
||||
*/
|
||||
#if !defined(CORTEX_SIMPLIFIED_PRIORITY)
|
||||
#define CORTEX_SIMPLIFIED_PRIORITY FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief SVCALL handler priority.
|
||||
* @note The default SVCALL handler priority is defaulted to
|
||||
* @p CORTEX_MAXIMUM_PRIORITY+1, this reserves the
|
||||
* @p CORTEX_MAXIMUM_PRIORITY priority level as fast interrupts
|
||||
* priority level.
|
||||
*/
|
||||
#if !defined(CORTEX_PRIORITY_SVCALL)
|
||||
#define CORTEX_PRIORITY_SVCALL (CORTEX_MAXIMUM_PRIORITY + 1U)
|
||||
#elif !PORT_IRQ_IS_VALID_PRIORITY(CORTEX_PRIORITY_SVCALL)
|
||||
/* If it is externally redefined then better perform a validity check on it.*/
|
||||
#error "invalid priority level specified for CORTEX_PRIORITY_SVCALL"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief NVIC VTOR initialization expression.
|
||||
*/
|
||||
#if !defined(CORTEX_VTOR_INIT) || defined(__DOXYGEN__)
|
||||
#define CORTEX_VTOR_INIT 0x00000000U
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief NVIC PRIGROUP initialization expression.
|
||||
* @details The default assigns all available priority bits as preemption
|
||||
* priority with no sub-priority.
|
||||
*/
|
||||
#if !defined(CORTEX_PRIGROUP_INIT) || defined(__DOXYGEN__)
|
||||
#define CORTEX_PRIGROUP_INIT (7 - CORTEX_PRIORITY_BITS)
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Architecture and Compiler
|
||||
* @{
|
||||
*/
|
||||
#if (CORTEX_MODEL == 3) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Macro defining the specific ARM architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_ARM_v7M
|
||||
|
||||
/**
|
||||
* @brief Name of the implemented architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_NAME "ARMv7-M"
|
||||
|
||||
/**
|
||||
* @brief Name of the architecture variant.
|
||||
*/
|
||||
#define PORT_CORE_VARIANT_NAME "Cortex-M3"
|
||||
|
||||
#elif (CORTEX_MODEL == 4)
|
||||
#define PORT_ARCHITECTURE_ARM_v7ME
|
||||
#define PORT_ARCHITECTURE_NAME "ARMv7E-M"
|
||||
#if CORTEX_USE_FPU
|
||||
#define PORT_CORE_VARIANT_NAME "Cortex-M4F"
|
||||
#else
|
||||
#define PORT_CORE_VARIANT_NAME "Cortex-M4"
|
||||
#endif
|
||||
|
||||
#elif (CORTEX_MODEL == 7)
|
||||
#define PORT_ARCHITECTURE_ARM_v7ME
|
||||
#define PORT_ARCHITECTURE_NAME "ARMv7E-M"
|
||||
#if CORTEX_USE_FPU
|
||||
#define PORT_CORE_VARIANT_NAME "Cortex-M7F"
|
||||
#else
|
||||
#define PORT_CORE_VARIANT_NAME "Cortex-M7"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Port-specific information string.
|
||||
*/
|
||||
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) || defined(__DOXYGEN__)
|
||||
#define PORT_INFO "Advanced kernel mode"
|
||||
#else
|
||||
#define PORT_INFO "Compact kernel mode"
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Maximum usable priority for normal ISRs.
|
||||
*/
|
||||
#define CORTEX_MAX_KERNEL_PRIORITY (CORTEX_PRIORITY_SVCALL + 1U)
|
||||
|
||||
/**
|
||||
* @brief BASEPRI level within kernel lock.
|
||||
*/
|
||||
#define CORTEX_BASEPRI_KERNEL \
|
||||
CORTEX_PRIO_MASK(CORTEX_MAX_KERNEL_PRIORITY)
|
||||
#else
|
||||
|
||||
#define CORTEX_MAX_KERNEL_PRIORITY 0U
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PendSV priority level.
|
||||
* @note This priority is enforced to be equal to
|
||||
* @p CORTEX_MAX_KERNEL_PRIORITY, this handler always have the
|
||||
* highest priority that cannot preempt the kernel.
|
||||
*/
|
||||
#define CORTEX_PRIORITY_PENDSV CORTEX_MAX_KERNEL_PRIORITY
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
/* The documentation of the following declarations is in chconf.h in order
|
||||
to not have duplicated structure names into the documentation.*/
|
||||
#if !defined(__DOXYGEN__)
|
||||
struct port_extctx {
|
||||
regarm_t r0;
|
||||
regarm_t r1;
|
||||
regarm_t r2;
|
||||
regarm_t r3;
|
||||
regarm_t r12;
|
||||
regarm_t lr_thd;
|
||||
regarm_t pc;
|
||||
regarm_t xpsr;
|
||||
#if CORTEX_USE_FPU
|
||||
regarm_t s0;
|
||||
regarm_t s1;
|
||||
regarm_t s2;
|
||||
regarm_t s3;
|
||||
regarm_t s4;
|
||||
regarm_t s5;
|
||||
regarm_t s6;
|
||||
regarm_t s7;
|
||||
regarm_t s8;
|
||||
regarm_t s9;
|
||||
regarm_t s10;
|
||||
regarm_t s11;
|
||||
regarm_t s12;
|
||||
regarm_t s13;
|
||||
regarm_t s14;
|
||||
regarm_t s15;
|
||||
regarm_t fpscr;
|
||||
regarm_t reserved;
|
||||
#endif /* CORTEX_USE_FPU */
|
||||
};
|
||||
|
||||
struct port_intctx {
|
||||
#if CORTEX_USE_FPU
|
||||
regarm_t s16;
|
||||
regarm_t s17;
|
||||
regarm_t s18;
|
||||
regarm_t s19;
|
||||
regarm_t s20;
|
||||
regarm_t s21;
|
||||
regarm_t s22;
|
||||
regarm_t s23;
|
||||
regarm_t s24;
|
||||
regarm_t s25;
|
||||
regarm_t s26;
|
||||
regarm_t s27;
|
||||
regarm_t s28;
|
||||
regarm_t s29;
|
||||
regarm_t s30;
|
||||
regarm_t s31;
|
||||
#endif /* CORTEX_USE_FPU */
|
||||
regarm_t r4;
|
||||
regarm_t r5;
|
||||
regarm_t r6;
|
||||
regarm_t r7;
|
||||
regarm_t r8;
|
||||
regarm_t r9;
|
||||
regarm_t r10;
|
||||
regarm_t r11;
|
||||
regarm_t lr;
|
||||
};
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p chThdCreateI() API.
|
||||
* @details This code usually setup the context switching frame represented
|
||||
* by an @p port_intctx structure.
|
||||
*/
|
||||
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
|
||||
(tp)->p_ctx.r13 = (struct port_intctx *)((uint8_t *)(workspace) + \
|
||||
(size_t)(wsize) - \
|
||||
sizeof(struct port_intctx)); \
|
||||
(tp)->p_ctx.r13->r4 = (regarm_t)(pf); \
|
||||
(tp)->p_ctx.r13->r5 = (regarm_t)(arg); \
|
||||
(tp)->p_ctx.r13->lr = (regarm_t)_port_thread_start; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the thread working area global size.
|
||||
* @note There is no need to perform alignments in this macro.
|
||||
*/
|
||||
#define PORT_WA_SIZE(n) (sizeof(struct port_intctx) + \
|
||||
sizeof(struct port_extctx) + \
|
||||
((size_t)(n)) + ((size_t)(PORT_INT_REQUIRED_STACK)))
|
||||
|
||||
/**
|
||||
* @brief IRQ prologue code.
|
||||
* @details This macro must be inserted at the start of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#define PORT_IRQ_PROLOGUE()
|
||||
|
||||
/**
|
||||
* @brief IRQ epilogue code.
|
||||
* @details This macro must be inserted at the end of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#define PORT_IRQ_EPILOGUE() _port_irq_epilogue()
|
||||
|
||||
/**
|
||||
* @brief IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_IRQ_HANDLER(id) void id(void)
|
||||
|
||||
/**
|
||||
* @brief Fast IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_FAST_IRQ_HANDLER(id) void id(void)
|
||||
|
||||
/**
|
||||
* @brief Performs a context switch between two threads.
|
||||
* @details This is the most critical code in any port, this function
|
||||
* is responsible for the context switch between 2 threads.
|
||||
* @note The implementation of this code affects <b>directly</b> the context
|
||||
* switch performance so optimize here as much as you can.
|
||||
*
|
||||
* @param[in] ntp the thread to be switched in
|
||||
* @param[in] otp the thread to be switched out
|
||||
*/
|
||||
#if (CH_DBG_ENABLE_STACK_CHECK == FALSE) || defined(__DOXYGEN__)
|
||||
#define port_switch(ntp, otp) _port_switch(ntp, otp)
|
||||
#else
|
||||
#define port_switch(ntp, otp) { \
|
||||
struct port_intctx *r13 = (struct port_intctx *)__get_PSP(); \
|
||||
if ((stkalign_t *)(r13 - 1) < (otp)->p_stklimit) { \
|
||||
chSysHalt("stack overflow"); \
|
||||
} \
|
||||
_port_switch(ntp, otp); \
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void _port_irq_epilogue(void);
|
||||
void _port_switch(thread_t *ntp, thread_t *otp);
|
||||
void _port_thread_start(void);
|
||||
void _port_switch_from_isr(void);
|
||||
void _port_exit_from_isr(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Port-related initialization code.
|
||||
*/
|
||||
static inline void port_init(void) {
|
||||
|
||||
/* Initialization of the vector table and priority related settings.*/
|
||||
SCB->VTOR = CORTEX_VTOR_INIT;
|
||||
|
||||
/* Initializing priority grouping.*/
|
||||
NVIC_SetPriorityGrouping(CORTEX_PRIGROUP_INIT);
|
||||
|
||||
/* DWT cycle counter enable, note, the M7 requires DWT unlocking.*/
|
||||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||
#if CORTEX_MODEL == 7
|
||||
DWT->LAR = 0xC5ACCE55U;
|
||||
#endif
|
||||
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
||||
|
||||
/* Initialization of the system vectors used by the port.*/
|
||||
#if CORTEX_SIMPLIFIED_PRIORITY == FALSE
|
||||
NVIC_SetPriority(SVCall_IRQn, CORTEX_PRIORITY_SVCALL);
|
||||
#endif
|
||||
NVIC_SetPriority(PendSV_IRQn, CORTEX_PRIORITY_PENDSV);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a word encoding the current interrupts status.
|
||||
*
|
||||
* @return The interrupts status.
|
||||
*/
|
||||
static inline syssts_t port_get_irq_status(void) {
|
||||
syssts_t sts;
|
||||
|
||||
#if CORTEX_SIMPLIFIED_PRIORITY == FALSE
|
||||
sts = (syssts_t)__get_BASEPRI();
|
||||
#else /* CORTEX_SIMPLIFIED_PRIORITY */
|
||||
sts = (syssts_t)__get_PRIMASK();
|
||||
#endif /* CORTEX_SIMPLIFIED_PRIORITY */
|
||||
return sts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the interrupt status.
|
||||
*
|
||||
* @param[in] sts the interrupt status word
|
||||
*
|
||||
* @return The interrupt status.
|
||||
* @retvel false the word specified a disabled interrupts status.
|
||||
* @retvel true the word specified an enabled interrupts status.
|
||||
*/
|
||||
static inline bool port_irq_enabled(syssts_t sts) {
|
||||
|
||||
#if CORTEX_SIMPLIFIED_PRIORITY == FALSE
|
||||
return sts == (syssts_t)CORTEX_BASEPRI_DISABLED;
|
||||
#else /* CORTEX_SIMPLIFIED_PRIORITY */
|
||||
return (sts & (syssts_t)1) == (syssts_t)0;
|
||||
#endif /* CORTEX_SIMPLIFIED_PRIORITY */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines the current execution context.
|
||||
*
|
||||
* @return The execution context.
|
||||
* @retval false not running in ISR mode.
|
||||
* @retval true running in ISR mode.
|
||||
*/
|
||||
static inline bool port_is_isr_context(void) {
|
||||
|
||||
return (bool)((__get_IPSR() & 0x1FFU) != 0U);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action.
|
||||
* @details In this port this function raises the base priority to kernel
|
||||
* level.
|
||||
*/
|
||||
static inline void port_lock(void) {
|
||||
|
||||
#if CORTEX_SIMPLIFIED_PRIORITY == FALSE
|
||||
#if defined(__CM7_REV)
|
||||
#if __CM7_REV <= 1
|
||||
__disable_irq();
|
||||
#endif
|
||||
#endif
|
||||
__set_BASEPRI(CORTEX_BASEPRI_KERNEL);
|
||||
#if defined(__CM7_REV)
|
||||
#if __CM7_REV <= 1
|
||||
__enable_irq();
|
||||
#endif
|
||||
#endif
|
||||
#else /* CORTEX_SIMPLIFIED_PRIORITY */
|
||||
__disable_irq();
|
||||
#endif /* CORTEX_SIMPLIFIED_PRIORITY */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action.
|
||||
* @details In this port this function lowers the base priority to user
|
||||
* level.
|
||||
*/
|
||||
static inline void port_unlock(void) {
|
||||
|
||||
#if CORTEX_SIMPLIFIED_PRIORITY == FALSE
|
||||
__set_BASEPRI(CORTEX_BASEPRI_DISABLED);
|
||||
#else /* CORTEX_SIMPLIFIED_PRIORITY */
|
||||
__enable_irq();
|
||||
#endif /* CORTEX_SIMPLIFIED_PRIORITY */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action from an interrupt handler.
|
||||
* @details In this port this function raises the base priority to kernel
|
||||
* level.
|
||||
* @note Same as @p port_lock() in this port.
|
||||
*/
|
||||
static inline void port_lock_from_isr(void) {
|
||||
|
||||
port_lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action from an interrupt handler.
|
||||
* @details In this port this function lowers the base priority to user
|
||||
* level.
|
||||
* @note Same as @p port_unlock() in this port.
|
||||
*/
|
||||
static inline void port_unlock_from_isr(void) {
|
||||
|
||||
port_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables all the interrupt sources.
|
||||
* @note In this port it disables all the interrupt sources by raising
|
||||
* the priority mask to level 0.
|
||||
*/
|
||||
static inline void port_disable(void) {
|
||||
|
||||
__disable_irq();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables the interrupt sources below kernel-level priority.
|
||||
* @note Interrupt sources above kernel level remains enabled.
|
||||
* @note In this port it raises/lowers the base priority to kernel level.
|
||||
*/
|
||||
static inline void port_suspend(void) {
|
||||
|
||||
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) || defined(__DOXYGEN__)
|
||||
__set_BASEPRI(CORTEX_BASEPRI_KERNEL);
|
||||
__enable_irq();
|
||||
#else
|
||||
__disable_irq();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables all the interrupt sources.
|
||||
* @note In this port it lowers the base priority to user level.
|
||||
*/
|
||||
static inline void port_enable(void) {
|
||||
|
||||
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) || defined(__DOXYGEN__)
|
||||
__set_BASEPRI(CORTEX_BASEPRI_DISABLED);
|
||||
#endif
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enters an architecture-dependent IRQ-waiting mode.
|
||||
* @details The function is meant to return when an interrupt becomes pending.
|
||||
* The simplest implementation is an empty function or macro but this
|
||||
* would not take advantage of architecture-specific power saving
|
||||
* modes.
|
||||
* @note Implemented as an inlined @p WFI instruction.
|
||||
*/
|
||||
static inline void port_wait_for_interrupt(void) {
|
||||
|
||||
#if CORTEX_ENABLE_WFI_IDLE == TRUE
|
||||
__WFI();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current value of the realtime counter.
|
||||
*
|
||||
* @return The realtime counter value.
|
||||
*/
|
||||
static inline rtcnt_t port_rt_get_counter_value(void) {
|
||||
|
||||
return DWT->CYCCNT;
|
||||
}
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
#endif /* _CHCORE_V7M_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,554 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Concepts and parts of this file have been contributed by Andre R.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file cmsis_os.c
|
||||
* @brief CMSIS RTOS module code.
|
||||
*
|
||||
* @addtogroup CMSIS_OS
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "cmsis_os.h"
|
||||
#include <string.h>
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
int32_t cmsis_os_started;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
static memory_pool_t sempool;
|
||||
static semaphore_t semaphores[CMSIS_CFG_NUM_SEMAPHORES];
|
||||
|
||||
static memory_pool_t timpool;
|
||||
static struct os_timer_cb timers[CMSIS_CFG_NUM_TIMERS];
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Virtual timers common callback.
|
||||
*/
|
||||
static void timer_cb(void const *arg) {
|
||||
|
||||
osTimerId timer_id = (osTimerId)arg;
|
||||
timer_id->ptimer(timer_id->argument);
|
||||
if (timer_id->type == osTimerPeriodic) {
|
||||
chSysLockFromISR();
|
||||
chVTDoSetI(&timer_id->vt, MS2ST(timer_id->millisec),
|
||||
(vtfunc_t)timer_cb, timer_id);
|
||||
chSysUnlockFromISR();
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Kernel initialization.
|
||||
*/
|
||||
osStatus osKernelInitialize(void) {
|
||||
|
||||
cmsis_os_started = 0;
|
||||
|
||||
chSysInit();
|
||||
chThdSetPriority(HIGHPRIO);
|
||||
|
||||
chPoolObjectInit(&sempool, sizeof(semaphore_t), chCoreAlloc);
|
||||
chPoolLoadArray(&sempool, semaphores, CMSIS_CFG_NUM_SEMAPHORES);
|
||||
|
||||
chPoolObjectInit(&timpool, sizeof(virtual_timer_t), chCoreAlloc);
|
||||
chPoolLoadArray(&timpool, timers, CMSIS_CFG_NUM_TIMERS);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel start.
|
||||
*/
|
||||
osStatus osKernelStart(void) {
|
||||
|
||||
cmsis_os_started = 1;
|
||||
|
||||
chThdSetPriority(NORMALPRIO);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a thread.
|
||||
*/
|
||||
osThreadId osThreadCreate(const osThreadDef_t *thread_def, void *argument) {
|
||||
size_t size;
|
||||
|
||||
size = thread_def->stacksize == 0 ? CMSIS_CFG_DEFAULT_STACK :
|
||||
thread_def->stacksize;
|
||||
return (osThreadId)chThdCreateFromHeap(0,
|
||||
THD_WORKING_AREA_SIZE(size),
|
||||
NORMALPRIO+thread_def->tpriority,
|
||||
(tfunc_t)thread_def->pthread,
|
||||
argument);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Thread termination.
|
||||
* @note The thread is not really terminated but asked to terminate which
|
||||
* is not compliant.
|
||||
*/
|
||||
osStatus osThreadTerminate(osThreadId thread_id) {
|
||||
|
||||
if (thread_id == osThreadGetId()) {
|
||||
/* Note, no memory will be recovered unless a cleaner thread is
|
||||
implemented using the registry.*/
|
||||
chThdExit(0);
|
||||
}
|
||||
chThdTerminate(thread_id);
|
||||
chThdWait((thread_t *)thread_id);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Change thread priority.
|
||||
* @note This can interfere with the priority inheritance mechanism.
|
||||
*/
|
||||
osStatus osThreadSetPriority(osThreadId thread_id, osPriority newprio) {
|
||||
osPriority oldprio;
|
||||
thread_t * tp = (thread_t *)thread_id;
|
||||
|
||||
chSysLock();
|
||||
|
||||
/* Changing priority.*/
|
||||
#if CH_CFG_USE_MUTEXES
|
||||
oldprio = (osPriority)tp->p_realprio;
|
||||
if ((tp->p_prio == tp->p_realprio) || ((tprio_t)newprio > tp->p_prio))
|
||||
tp->p_prio = (tprio_t)newprio;
|
||||
tp->p_realprio = (tprio_t)newprio;
|
||||
#else
|
||||
oldprio = tp->p_prio;
|
||||
tp->p_prio = (tprio_t)newprio;
|
||||
#endif
|
||||
|
||||
/* The following states need priority queues reordering.*/
|
||||
switch (tp->p_state) {
|
||||
#if CH_CFG_USE_MUTEXES | \
|
||||
CH_CFG_USE_CONDVARS | \
|
||||
(CH_CFG_USE_SEMAPHORES && CH_CFG_USE_SEMAPHORES_PRIORITY) | \
|
||||
(CH_CFG_USE_MESSAGES && CH_CFG_USE_MESSAGES_PRIORITY)
|
||||
#if CH_CFG_USE_MUTEXES
|
||||
case CH_STATE_WTMTX:
|
||||
#endif
|
||||
#if CH_CFG_USE_CONDVARS
|
||||
case CH_STATE_WTCOND:
|
||||
#endif
|
||||
#if CH_CFG_USE_SEMAPHORES && CH_CFG_USE_SEMAPHORES_PRIORITY
|
||||
case CH_STATE_WTSEM:
|
||||
#endif
|
||||
#if CH_CFG_USE_MESSAGES && CH_CFG_USE_MESSAGES_PRIORITY
|
||||
case CH_STATE_SNDMSGQ:
|
||||
#endif
|
||||
/* Re-enqueues tp with its new priority on the queue.*/
|
||||
queue_prio_insert(queue_dequeue(tp),
|
||||
(threads_queue_t *)tp->p_u.wtobjp);
|
||||
break;
|
||||
#endif
|
||||
case CH_STATE_READY:
|
||||
#if CH_DBG_ENABLE_ASSERTS
|
||||
/* Prevents an assertion in chSchReadyI().*/
|
||||
tp->p_state = CH_STATE_CURRENT;
|
||||
#endif
|
||||
/* Re-enqueues tp with its new priority on the ready list.*/
|
||||
chSchReadyI(queue_dequeue(tp));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Rescheduling.*/
|
||||
chSchRescheduleS();
|
||||
|
||||
chSysUnlock();
|
||||
|
||||
return oldprio;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a timer.
|
||||
*/
|
||||
osTimerId osTimerCreate(const osTimerDef_t *timer_def,
|
||||
os_timer_type type,
|
||||
void *argument) {
|
||||
|
||||
osTimerId timer = chPoolAlloc(&timpool);
|
||||
chVTObjectInit(&timer->vt);
|
||||
timer->ptimer = timer_def->ptimer;
|
||||
timer->type = type;
|
||||
timer->argument = argument;
|
||||
return timer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start a timer.
|
||||
*/
|
||||
osStatus osTimerStart(osTimerId timer_id, uint32_t millisec) {
|
||||
|
||||
if ((millisec == 0) || (millisec == osWaitForever))
|
||||
return osErrorValue;
|
||||
|
||||
timer_id->millisec = millisec;
|
||||
chVTSet(&timer_id->vt, MS2ST(millisec), (vtfunc_t)timer_cb, timer_id);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stop a timer.
|
||||
*/
|
||||
osStatus osTimerStop(osTimerId timer_id) {
|
||||
|
||||
chVTReset(&timer_id->vt);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delete a timer.
|
||||
*/
|
||||
osStatus osTimerDelete(osTimerId timer_id) {
|
||||
|
||||
chVTReset(&timer_id->vt);
|
||||
chPoolFree(&timpool, (void *)timer_id);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send signals.
|
||||
*/
|
||||
int32_t osSignalSet(osThreadId thread_id, int32_t signals) {
|
||||
int32_t oldsignals;
|
||||
|
||||
syssts_t sts = chSysGetStatusAndLockX();
|
||||
oldsignals = (int32_t)thread_id->p_epending;
|
||||
chEvtSignalI((thread_t *)thread_id, (eventmask_t)signals);
|
||||
chSysRestoreStatusX(sts);
|
||||
|
||||
return oldsignals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear signals.
|
||||
*/
|
||||
int32_t osSignalClear(osThreadId thread_id, int32_t signals) {
|
||||
eventmask_t m;
|
||||
|
||||
chSysLock();
|
||||
|
||||
m = thread_id->p_epending & (eventmask_t)signals;
|
||||
thread_id->p_epending &= ~(eventmask_t)signals;
|
||||
|
||||
chSysUnlock();
|
||||
|
||||
return (int32_t)m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait for signals.
|
||||
*/
|
||||
osEvent osSignalWait(int32_t signals, uint32_t millisec) {
|
||||
osEvent event;
|
||||
systime_t timeout = ((millisec == 0) || (millisec == osWaitForever)) ?
|
||||
TIME_INFINITE : MS2ST(millisec);
|
||||
|
||||
if (signals == 0)
|
||||
event.value.signals = (uint32_t)chEvtWaitAnyTimeout(ALL_EVENTS, timeout);
|
||||
else
|
||||
event.value.signals = (uint32_t)chEvtWaitAllTimeout((eventmask_t)signals,
|
||||
timeout);
|
||||
|
||||
/* Type of event.*/
|
||||
if (event.value.signals == 0)
|
||||
event.status = osEventTimeout;
|
||||
else
|
||||
event.status = osEventSignal;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a semaphore.
|
||||
* @note @p semaphore_def is not used.
|
||||
* @note Can involve memory allocation.
|
||||
*/
|
||||
osSemaphoreId osSemaphoreCreate(const osSemaphoreDef_t *semaphore_def,
|
||||
int32_t count) {
|
||||
|
||||
(void)semaphore_def;
|
||||
|
||||
semaphore_t *sem = chPoolAlloc(&sempool);
|
||||
chSemObjectInit(sem, (cnt_t)count);
|
||||
return sem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait on a semaphore.
|
||||
*/
|
||||
int32_t osSemaphoreWait(osSemaphoreId semaphore_id, uint32_t millisec) {
|
||||
systime_t timeout = ((millisec == 0) || (millisec == osWaitForever)) ?
|
||||
TIME_INFINITE : MS2ST(millisec);
|
||||
|
||||
msg_t msg = chSemWaitTimeout((semaphore_t *)semaphore_id, timeout);
|
||||
switch (msg) {
|
||||
case MSG_OK:
|
||||
return osOK;
|
||||
case MSG_TIMEOUT:
|
||||
return osErrorTimeoutResource;
|
||||
}
|
||||
return osErrorResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release a semaphore.
|
||||
*/
|
||||
osStatus osSemaphoreRelease(osSemaphoreId semaphore_id) {
|
||||
|
||||
syssts_t sts = chSysGetStatusAndLockX();
|
||||
chSemSignalI((semaphore_t *)semaphore_id);
|
||||
chSysRestoreStatusX(sts);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deletes a semaphore.
|
||||
* @note After deletion there could be references in the system to a
|
||||
* non-existent semaphore.
|
||||
*/
|
||||
osStatus osSemaphoreDelete(osSemaphoreId semaphore_id) {
|
||||
|
||||
chSemReset((semaphore_t *)semaphore_id, 0);
|
||||
chPoolFree(&sempool, (void *)semaphore_id);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a mutex.
|
||||
* @note @p mutex_def is not used.
|
||||
* @note Can involve memory allocation.
|
||||
*/
|
||||
osMutexId osMutexCreate(const osMutexDef_t *mutex_def) {
|
||||
|
||||
(void)mutex_def;
|
||||
|
||||
binary_semaphore_t *mtx = chPoolAlloc(&sempool);
|
||||
chBSemObjectInit(mtx, false);
|
||||
return mtx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait on a mutex.
|
||||
*/
|
||||
osStatus osMutexWait(osMutexId mutex_id, uint32_t millisec) {
|
||||
systime_t timeout = ((millisec == 0) || (millisec == osWaitForever)) ?
|
||||
TIME_INFINITE : MS2ST(millisec);
|
||||
|
||||
msg_t msg = chBSemWaitTimeout((binary_semaphore_t *)mutex_id, timeout);
|
||||
switch (msg) {
|
||||
case MSG_OK:
|
||||
return osOK;
|
||||
case MSG_TIMEOUT:
|
||||
return osErrorTimeoutResource;
|
||||
}
|
||||
return osErrorResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release a mutex.
|
||||
*/
|
||||
osStatus osMutexRelease(osMutexId mutex_id) {
|
||||
|
||||
syssts_t sts = chSysGetStatusAndLockX();
|
||||
chBSemSignalI((binary_semaphore_t *)mutex_id);
|
||||
chSysRestoreStatusX(sts);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deletes a mutex.
|
||||
* @note After deletion there could be references in the system to a
|
||||
* non-existent semaphore.
|
||||
*/
|
||||
osStatus osMutexDelete(osMutexId mutex_id) {
|
||||
|
||||
chSemReset((semaphore_t *)mutex_id, 0);
|
||||
chPoolFree(&sempool, (void *)mutex_id);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a memory pool.
|
||||
* @note The pool is not really created because it is allocated statically,
|
||||
* this function just re-initializes it.
|
||||
*/
|
||||
osPoolId osPoolCreate(const osPoolDef_t *pool_def) {
|
||||
|
||||
chPoolObjectInit(pool_def->pool, (size_t)pool_def->item_sz, NULL);
|
||||
chPoolLoadArray(pool_def->pool, pool_def->items, (size_t)pool_def->pool_sz);
|
||||
|
||||
return (osPoolId)pool_def->pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate an object.
|
||||
*/
|
||||
void *osPoolAlloc(osPoolId pool_id) {
|
||||
void *object;
|
||||
|
||||
syssts_t sts = chSysGetStatusAndLockX();
|
||||
object = chPoolAllocI((memory_pool_t *)pool_id);
|
||||
chSysRestoreStatusX(sts);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocate an object clearing it.
|
||||
*/
|
||||
void *osPoolCAlloc(osPoolId pool_id) {
|
||||
void *object;
|
||||
|
||||
object = chPoolAllocI((memory_pool_t *)pool_id);
|
||||
memset(object, 0, pool_id->mp_object_size);
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free an object.
|
||||
*/
|
||||
osStatus osPoolFree(osPoolId pool_id, void *block) {
|
||||
|
||||
syssts_t sts = chSysGetStatusAndLockX();
|
||||
chPoolFreeI((memory_pool_t *)pool_id, block);
|
||||
chSysRestoreStatusX(sts);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a message queue.
|
||||
* @note The queue is not really created because it is allocated statically,
|
||||
* this function just re-initializes it.
|
||||
*/
|
||||
osMessageQId osMessageCreate(const osMessageQDef_t *queue_def,
|
||||
osThreadId thread_id) {
|
||||
|
||||
/* Ignoring this parameter for now.*/
|
||||
(void)thread_id;
|
||||
|
||||
if (queue_def->item_sz > sizeof (msg_t))
|
||||
return NULL;
|
||||
|
||||
chMBObjectInit(queue_def->mailbox,
|
||||
queue_def->items,
|
||||
(size_t)queue_def->queue_sz);
|
||||
|
||||
return (osMessageQId) queue_def->mailbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put a message in the queue.
|
||||
*/
|
||||
osStatus osMessagePut(osMessageQId queue_id,
|
||||
uint32_t info,
|
||||
uint32_t millisec) {
|
||||
msg_t msg;
|
||||
systime_t timeout = ((millisec == 0) || (millisec == osWaitForever)) ?
|
||||
TIME_INFINITE : MS2ST(millisec);
|
||||
|
||||
if (port_is_isr_context()) {
|
||||
|
||||
/* Waiting makes no sense in ISRs so any value except "immediate"
|
||||
makes no sense.*/
|
||||
if (millisec != 0)
|
||||
return osErrorValue;
|
||||
|
||||
chSysLockFromISR();
|
||||
msg = chMBPostI((mailbox_t *)queue_id, (msg_t)info);
|
||||
chSysUnlockFromISR();
|
||||
}
|
||||
else
|
||||
msg = chMBPost((mailbox_t *)queue_id, (msg_t)info, timeout);
|
||||
|
||||
return msg == MSG_OK ? osOK : osEventTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a message from the queue.
|
||||
*/
|
||||
osEvent osMessageGet(osMessageQId queue_id,
|
||||
uint32_t millisec) {
|
||||
msg_t msg;
|
||||
osEvent event;
|
||||
systime_t timeout = ((millisec == 0) || (millisec == osWaitForever)) ?
|
||||
TIME_INFINITE : MS2ST(millisec);
|
||||
|
||||
event.def.message_id = queue_id;
|
||||
|
||||
if (port_is_isr_context()) {
|
||||
|
||||
/* Waiting makes no sense in ISRs so any value except "immediate"
|
||||
makes no sense.*/
|
||||
if (millisec != 0) {
|
||||
event.status = osErrorValue;
|
||||
return event;
|
||||
}
|
||||
|
||||
chSysLockFromISR();
|
||||
msg = chMBFetchI((mailbox_t *)queue_id, (msg_t*)&event.value.v);
|
||||
chSysUnlockFromISR();
|
||||
}
|
||||
else {
|
||||
msg = chMBFetch((mailbox_t *)queue_id, (msg_t*)&event.value.v, timeout);
|
||||
}
|
||||
|
||||
/* Returned event type.*/
|
||||
event.status = msg == MSG_OK ? osEventMessage : osEventTimeout;
|
||||
return event;
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,520 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Concepts and parts of this file have been contributed by Andre R.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file cmsis_os.h
|
||||
* @brief CMSIS RTOS module macros and structures.
|
||||
*
|
||||
* @addtogroup CMSIS_OS
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CMSIS_OS_H_
|
||||
#define _CMSIS_OS_H_
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief API version.
|
||||
*/
|
||||
#define osCMSIS 0x10002
|
||||
|
||||
/**
|
||||
* @brief Kernel version.
|
||||
*/
|
||||
#define osKernelSystemId "KERNEL V1.00"
|
||||
|
||||
/**
|
||||
* @brief ChibiOS/RT version encoded for CMSIS.
|
||||
*/
|
||||
#define osCMSIS_KERNEL ((CH_KERNEL_MAJOR << 16) | \
|
||||
(CH_KERNEL_MINOR << 8) | \
|
||||
(CH_KERNEL_PATCH))
|
||||
|
||||
/**
|
||||
* @name CMSIS Capabilities
|
||||
* @{
|
||||
*/
|
||||
#define osFeature_MainThread 1
|
||||
#define osFeature_Pool 1
|
||||
#define osFeature_MailQ 0
|
||||
#define osFeature_MessageQ 1
|
||||
#define osFeature_Signals 24
|
||||
#define osFeature_Semaphore ((1U << 31) - 1U)
|
||||
#define osFeature_Wait 0
|
||||
#define osFeature_SysTick 1
|
||||
/**< @} */
|
||||
|
||||
/**
|
||||
* @brief Wait forever specification for timeouts.
|
||||
*/
|
||||
#define osWaitForever TIME_INFINITE
|
||||
|
||||
/**
|
||||
* @brief System tick frequency.
|
||||
*/
|
||||
#define osKernelSysTickFrequency CH_CFG_FREQUENCY
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Number of pre-allocated static semaphores/mutexes.
|
||||
*/
|
||||
#if !defined(CMSIS_CFG_DEFAULT_STACK)
|
||||
#define CMSIS_CFG_DEFAULT_STACK 256
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of pre-allocated static semaphores/mutexes.
|
||||
*/
|
||||
#if !defined(CMSIS_CFG_NUM_SEMAPHORES)
|
||||
#define CMSIS_CFG_NUM_SEMAPHORES 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of pre-allocated static timers.
|
||||
*/
|
||||
#if !defined(CMSIS_CFG_NUM_TIMERS)
|
||||
#define CMSIS_CFG_NUM_TIMERS 4
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !CH_CFG_USE_MEMPOOLS
|
||||
#error "CMSIS RTOS requires CH_CFG_USE_MEMPOOLS"
|
||||
#endif
|
||||
|
||||
#if !CH_CFG_USE_EVENTS
|
||||
#error "CMSIS RTOS requires CH_CFG_USE_EVENTS"
|
||||
#endif
|
||||
|
||||
#if !CH_CFG_USE_EVENTS_TIMEOUT
|
||||
#error "CMSIS RTOS requires CH_CFG_USE_EVENTS_TIMEOUT"
|
||||
#endif
|
||||
|
||||
#if !CH_CFG_USE_SEMAPHORES
|
||||
#error "CMSIS RTOS requires CH_CFG_USE_SEMAPHORES"
|
||||
#endif
|
||||
|
||||
#if !CH_CFG_USE_DYNAMIC
|
||||
#error "CMSIS RTOS requires CH_CFG_USE_DYNAMIC"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Type of priority levels.
|
||||
*/
|
||||
typedef enum {
|
||||
osPriorityIdle = -3,
|
||||
osPriorityLow = -2,
|
||||
osPriorityBelowNormal = -1,
|
||||
osPriorityNormal = 0,
|
||||
osPriorityAboveNormal = +1,
|
||||
osPriorityHigh = +2,
|
||||
osPriorityRealtime = +3,
|
||||
osPriorityError = 0x84
|
||||
} osPriority;
|
||||
|
||||
/**
|
||||
* @brief Type of error codes.
|
||||
*/
|
||||
typedef enum {
|
||||
osOK = 0,
|
||||
osEventSignal = 0x08,
|
||||
osEventMessage = 0x10,
|
||||
osEventMail = 0x20,
|
||||
osEventTimeout = 0x40,
|
||||
osErrorParameter = 0x80,
|
||||
osErrorResource = 0x81,
|
||||
osErrorTimeoutResource = 0xC1,
|
||||
osErrorISR = 0x82,
|
||||
osErrorISRRecursive = 0x83,
|
||||
osErrorPriority = 0x84,
|
||||
osErrorNoMemory = 0x85,
|
||||
osErrorValue = 0x86,
|
||||
osErrorOS = 0xFF,
|
||||
os_status_reserved = 0x7FFFFFFF
|
||||
} osStatus;
|
||||
|
||||
/**
|
||||
* @brief Type of a timer mode.
|
||||
*/
|
||||
typedef enum {
|
||||
osTimerOnce = 0,
|
||||
osTimerPeriodic = 1
|
||||
} os_timer_type;
|
||||
|
||||
/**
|
||||
* @brief Type of thread functions.
|
||||
*/
|
||||
typedef void (*os_pthread) (void const *argument);
|
||||
|
||||
/**
|
||||
* @brief Type of timer callback.
|
||||
*/
|
||||
typedef void (*os_ptimer) (void const *argument);
|
||||
|
||||
/**
|
||||
* @brief Type of pointer to thread control block.
|
||||
*/
|
||||
typedef thread_t *osThreadId;
|
||||
|
||||
/**
|
||||
* @brief Type of pointer to timer control block.
|
||||
*/
|
||||
typedef struct os_timer_cb {
|
||||
virtual_timer_t vt;
|
||||
os_timer_type type;
|
||||
os_ptimer ptimer;
|
||||
void *argument;
|
||||
uint32_t millisec;
|
||||
} *osTimerId;
|
||||
|
||||
/**
|
||||
* @brief Type of pointer to mutex control block.
|
||||
*/
|
||||
typedef binary_semaphore_t *osMutexId;
|
||||
|
||||
/**
|
||||
* @brief Type of pointer to semaphore control block.
|
||||
*/
|
||||
typedef semaphore_t *osSemaphoreId;
|
||||
|
||||
/**
|
||||
* @brief Type of pointer to memory pool control block.
|
||||
*/
|
||||
typedef memory_pool_t *osPoolId;
|
||||
|
||||
/**
|
||||
* @brief Type of pointer to message queue control block.
|
||||
*/
|
||||
typedef struct mailbox *osMessageQId;
|
||||
|
||||
/**
|
||||
* @brief Type of an event.
|
||||
*/
|
||||
typedef struct {
|
||||
osStatus status;
|
||||
union {
|
||||
uint32_t v;
|
||||
void *p;
|
||||
int32_t signals;
|
||||
} value;
|
||||
union {
|
||||
/* osMailQId mail_id;*/
|
||||
osMessageQId message_id;
|
||||
} def;
|
||||
} osEvent;
|
||||
|
||||
/**
|
||||
* @brief Type of a thread definition block.
|
||||
*/
|
||||
typedef struct os_thread_def {
|
||||
os_pthread pthread;
|
||||
osPriority tpriority;
|
||||
uint32_t stacksize;
|
||||
} osThreadDef_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a timer definition block.
|
||||
*/
|
||||
typedef struct os_timer_def {
|
||||
os_ptimer ptimer;
|
||||
} osTimerDef_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a mutex definition block.
|
||||
*/
|
||||
typedef struct os_mutex_def {
|
||||
uint32_t dummy;
|
||||
} osMutexDef_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a semaphore definition block.
|
||||
*/
|
||||
typedef struct os_semaphore_def {
|
||||
uint32_t dummy;
|
||||
} osSemaphoreDef_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a memory pool definition block.
|
||||
*/
|
||||
typedef struct os_pool_def {
|
||||
uint32_t pool_sz;
|
||||
uint32_t item_sz;
|
||||
memory_pool_t *pool;
|
||||
void *items;
|
||||
} osPoolDef_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a message queue definition block.
|
||||
*/
|
||||
typedef struct os_messageQ_def {
|
||||
uint32_t queue_sz;
|
||||
uint32_t item_sz;
|
||||
mailbox_t *mailbox;
|
||||
void *items;
|
||||
} osMessageQDef_t;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Convert a microseconds value to a RTOS kernel system timer value.
|
||||
*/
|
||||
#define osKernelSysTickMicroSec(microsec) (((uint64_t)microsec * \
|
||||
(osKernelSysTickFrequency)) / \
|
||||
1000000)
|
||||
|
||||
/**
|
||||
* @brief Create a Thread definition.
|
||||
*/
|
||||
#if defined(osObjectsExternal)
|
||||
#define osThreadDef(name, priority, instances, stacksz) \
|
||||
extern const osThreadDef_t os_thread_def_##name
|
||||
#else
|
||||
#define osThreadDef(name, priority, stacksz) \
|
||||
const osThreadDef_t os_thread_def_##name = { \
|
||||
(name), \
|
||||
(priority), \
|
||||
(stacksz) \
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Access a Thread definition.
|
||||
*/
|
||||
#define osThread(name) &os_thread_def_##name
|
||||
|
||||
/**
|
||||
* @brief Define a Timer object.
|
||||
*/
|
||||
#if defined(osObjectsExternal)
|
||||
#define osTimerDef(name, function) \
|
||||
extern const osTimerDef_t os_timer_def_##name
|
||||
#else
|
||||
#define osTimerDef(name, function) \
|
||||
const osTimerDef_t os_timer_def_##name = { \
|
||||
(function) \
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Access a Timer definition.
|
||||
*/
|
||||
#define osTimer(name) &os_timer_def_##name
|
||||
|
||||
/**
|
||||
* @brief Define a Mutex.
|
||||
*/
|
||||
#if defined(osObjectsExternal)
|
||||
#define osMutexDef(name) extern const osMutexDef_t os_mutex_def_##name
|
||||
#else
|
||||
#define osMutexDef(name) const osMutexDef_t os_mutex_def_##name = {0}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Access a Mutex definition.
|
||||
*/
|
||||
#define osMutex(name) &os_mutex_def_##name
|
||||
|
||||
/**
|
||||
* @brief Define a Semaphore.
|
||||
*/
|
||||
#if defined(osObjectsExternal)
|
||||
#define osSemaphoreDef(name) \
|
||||
extern const osSemaphoreDef_t os_semaphore_def_##name
|
||||
#else // define the object
|
||||
#define osSemaphoreDef(name) \
|
||||
const osSemaphoreDef_t os_semaphore_def_##name = {0}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Access a Semaphore definition.
|
||||
*/
|
||||
#define osSemaphore(name) &os_semaphore_def_##name
|
||||
|
||||
/**
|
||||
* @brief Define a Memory Pool.
|
||||
*/
|
||||
#if defined(osObjectsExternal)
|
||||
#define osPoolDef(name, no, type) \
|
||||
extern const osPoolDef_t os_pool_def_##name
|
||||
#else
|
||||
#define osPoolDef(name, no, type) \
|
||||
static const type os_pool_buf_##name[no]; \
|
||||
static memory_pool_t os_pool_obj_##name; \
|
||||
const osPoolDef_t os_pool_def_##name = { \
|
||||
(no), \
|
||||
sizeof (type), \
|
||||
(void *)&os_pool_obj_##name, \
|
||||
(void *)&os_pool_buf_##name[0] \
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Access a Memory Pool definition.
|
||||
*/
|
||||
#define osPool(name) &os_pool_def_##name
|
||||
|
||||
/**
|
||||
* @brief Define a Message Queue.
|
||||
*/
|
||||
#if defined(osObjectsExternal)
|
||||
#define osMessageQDef(name, queue_sz, type) \
|
||||
extern const osMessageQDef_t os_messageQ_def_##name
|
||||
#else
|
||||
#define osMessageQDef(name, queue_sz, type) \
|
||||
static const msg_t os_messageQ_buf_##name[queue_sz]; \
|
||||
static mailbox_t os_messageQ_obj_##name; \
|
||||
const osMessageQDef_t os_messageQ_def_##name = { \
|
||||
(queue_sz), \
|
||||
sizeof (type) \
|
||||
(void *)&os_messageQ_obj_##name, \
|
||||
(void *)&os_messageQ_buf_##name[0] \
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Access a Message Queue definition.
|
||||
*/
|
||||
#define osMessageQ(name) &os_messageQ_def_##name
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
extern int32_t cmsis_os_started;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
osStatus osKernelInitialize(void);
|
||||
osStatus osKernelStart(void);
|
||||
osThreadId osThreadCreate(const osThreadDef_t *thread_def, void *argument);
|
||||
osStatus osThreadTerminate(osThreadId thread_id);
|
||||
osStatus osThreadSetPriority(osThreadId thread_id, osPriority newprio);
|
||||
/*osEvent osWait(uint32_t millisec);*/
|
||||
osTimerId osTimerCreate(const osTimerDef_t *timer_def,
|
||||
os_timer_type type,
|
||||
void *argument);
|
||||
osStatus osTimerStart(osTimerId timer_id, uint32_t millisec);
|
||||
osStatus osTimerStop(osTimerId timer_id);
|
||||
osStatus osTimerDelete(osTimerId timer_id);
|
||||
int32_t osSignalSet(osThreadId thread_id, int32_t signals);
|
||||
int32_t osSignalClear(osThreadId thread_id, int32_t signals);
|
||||
osEvent osSignalWait(int32_t signals, uint32_t millisec);
|
||||
osSemaphoreId osSemaphoreCreate(const osSemaphoreDef_t *semaphore_def,
|
||||
int32_t count);
|
||||
int32_t osSemaphoreWait(osSemaphoreId semaphore_id, uint32_t millisec);
|
||||
osStatus osSemaphoreRelease(osSemaphoreId semaphore_id);
|
||||
osStatus osSemaphoreDelete(osSemaphoreId semaphore_id);
|
||||
osMutexId osMutexCreate(const osMutexDef_t *mutex_def);
|
||||
osStatus osMutexWait(osMutexId mutex_id, uint32_t millisec);
|
||||
osStatus osMutexRelease(osMutexId mutex_id);
|
||||
osStatus osMutexDelete(osMutexId mutex_id);
|
||||
osPoolId osPoolCreate(const osPoolDef_t *pool_def);
|
||||
void *osPoolAlloc(osPoolId pool_id);
|
||||
void *osPoolCAlloc(osPoolId pool_id);
|
||||
osStatus osPoolFree(osPoolId pool_id, void *block);
|
||||
osMessageQId osMessageCreate(const osMessageQDef_t *queue_def,
|
||||
osThreadId thread_id);
|
||||
osStatus osMessagePut(osMessageQId queue_id,
|
||||
uint32_t info,
|
||||
uint32_t millisec);
|
||||
osEvent osMessageGet(osMessageQId queue_id,
|
||||
uint32_t millisec);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief To be or not to be.
|
||||
*/
|
||||
static inline int32_t osKernelRunning(void) {
|
||||
|
||||
return cmsis_os_started;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief System ticks since start.
|
||||
*/
|
||||
static inline uint32_t osKernelSysTick(void) {
|
||||
|
||||
return (uint32_t)chVTGetSystemTimeX();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current thread.
|
||||
*/
|
||||
static inline osThreadId osThreadGetId(void) {
|
||||
|
||||
return (osThreadId)chThdGetSelfX();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Thread time slice yield.
|
||||
*/
|
||||
static inline osStatus osThreadYield(void) {
|
||||
|
||||
chThdYield();
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns priority of a thread.
|
||||
*/
|
||||
static inline osPriority osThreadGetPriority(osThreadId thread_id) {
|
||||
|
||||
return thread_id->p_prio;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Thread delay in milliseconds.
|
||||
*/
|
||||
static inline osStatus osDelay(uint32_t millisec) {
|
||||
|
||||
chThdSleepMilliseconds(millisec);
|
||||
|
||||
return osOK;
|
||||
}
|
||||
|
||||
#endif /* _CMSIS_OS_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,4 +0,0 @@
|
|||
# List of the ChibiOS/RT CMSIS RTOS wrapper.
|
||||
CMSISRTOSSRC = ${CHIBIOS}/os/rt/ports/ARMCMx/cmsis_os/cmsis_os.c
|
||||
|
||||
CMSISRTOSINC = ${CHIBIOS}/os/rt/ports/ARMCMx/cmsis_os
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file compilers/GCC/chcoreasm_v6m.s
|
||||
* @brief ARMv6-M architecture port low level code.
|
||||
*
|
||||
* @addtogroup ARMCMx_GCC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define _FROM_ASM_
|
||||
#include "chconf.h"
|
||||
#include "chcore.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
.set CONTEXT_OFFSET, 12
|
||||
.set SCB_ICSR, 0xE000ED04
|
||||
.set ICSR_PENDSVSET, 0x10000000
|
||||
.set ICSR_NMIPENDSET, 0x80000000
|
||||
|
||||
.cpu cortex-m0
|
||||
.fpu softvfp
|
||||
|
||||
.thumb
|
||||
.text
|
||||
|
||||
/*--------------------------------------------------------------------------*
|
||||
* Performs a context switch between two threads.
|
||||
*--------------------------------------------------------------------------*/
|
||||
.thumb_func
|
||||
.globl _port_switch
|
||||
_port_switch:
|
||||
push {r4, r5, r6, r7, lr}
|
||||
mov r4, r8
|
||||
mov r5, r9
|
||||
mov r6, r10
|
||||
mov r7, r11
|
||||
push {r4, r5, r6, r7}
|
||||
|
||||
mov r3, sp
|
||||
str r3, [r1, #CONTEXT_OFFSET]
|
||||
ldr r3, [r0, #CONTEXT_OFFSET]
|
||||
mov sp, r3
|
||||
|
||||
pop {r4, r5, r6, r7}
|
||||
mov r8, r4
|
||||
mov r9, r5
|
||||
mov r10, r6
|
||||
mov r11, r7
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
|
||||
/*--------------------------------------------------------------------------*
|
||||
* Start a thread by invoking its work function.
|
||||
*
|
||||
* Threads execution starts here, the code leaves the system critical zone
|
||||
* and then jumps into the thread function passed in register R4. The
|
||||
* register R5 contains the thread parameter. The function chThdExit() is
|
||||
* called on thread function return.
|
||||
*--------------------------------------------------------------------------*/
|
||||
.thumb_func
|
||||
.globl _port_thread_start
|
||||
_port_thread_start:
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
cpsie i
|
||||
mov r0, r5
|
||||
blx r4
|
||||
movs r0, #0 /* MSG_OK */
|
||||
bl chThdExit
|
||||
|
||||
/*--------------------------------------------------------------------------*
|
||||
* Post-IRQ switch code.
|
||||
*
|
||||
* Exception handlers return here for context switching.
|
||||
*--------------------------------------------------------------------------*/
|
||||
.thumb_func
|
||||
.globl _port_switch_from_isr
|
||||
_port_switch_from_isr:
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_start_measure_crit_thd
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_lock
|
||||
#endif
|
||||
bl chSchDoReschedule
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
.globl _port_exit_from_isr
|
||||
_port_exit_from_isr:
|
||||
ldr r2, .L2
|
||||
ldr r3, .L3
|
||||
str r3, [r2, #0]
|
||||
#if CORTEX_ALTERNATE_SWITCH
|
||||
cpsie i
|
||||
#endif
|
||||
.L1: b .L1
|
||||
|
||||
.align 2
|
||||
.L2: .word SCB_ICSR
|
||||
#if CORTEX_ALTERNATE_SWITCH
|
||||
.L3: .word ICSR_PENDSVSET
|
||||
#else
|
||||
.L3: .word ICSR_NMIPENDSET
|
||||
#endif
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/** @} */
|
|
@ -1,148 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file compilers/GCC/chcoreasm_v7m.s
|
||||
* @brief ARMv7-M architecture port low level code.
|
||||
*
|
||||
* @addtogroup ARMCMx_GCC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define _FROM_ASM_
|
||||
#include "chconf.h"
|
||||
#include "chcore.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
.set CONTEXT_OFFSET, 12
|
||||
.set SCB_ICSR, 0xE000ED04
|
||||
.set ICSR_PENDSVSET, 0x10000000
|
||||
|
||||
.syntax unified
|
||||
.cpu cortex-m4
|
||||
#if CORTEX_USE_FPU
|
||||
.fpu fpv4-sp-d16
|
||||
#else
|
||||
.fpu softvfp
|
||||
#endif
|
||||
|
||||
.thumb
|
||||
.text
|
||||
|
||||
/*--------------------------------------------------------------------------*
|
||||
* Performs a context switch between two threads.
|
||||
*--------------------------------------------------------------------------*/
|
||||
.thumb_func
|
||||
.globl _port_switch
|
||||
_port_switch:
|
||||
push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
|
||||
#if CORTEX_USE_FPU
|
||||
vpush {s16-s31}
|
||||
#endif
|
||||
|
||||
str sp, [r1, #CONTEXT_OFFSET]
|
||||
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) && \
|
||||
((CORTEX_MODEL == 3) || (CORTEX_MODEL == 4))
|
||||
/* Workaround for ARM errata 752419, only applied if
|
||||
condition exists for it to be triggered.*/
|
||||
ldr r3, [r0, #CONTEXT_OFFSET]
|
||||
mov sp, r3
|
||||
#else
|
||||
ldr sp, [r0, #CONTEXT_OFFSET]
|
||||
#endif
|
||||
|
||||
#if CORTEX_USE_FPU
|
||||
vpop {s16-s31}
|
||||
#endif
|
||||
pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||
|
||||
/*--------------------------------------------------------------------------*
|
||||
* Start a thread by invoking its work function.
|
||||
*
|
||||
* Threads execution starts here, the code leaves the system critical zone
|
||||
* and then jumps into the thread function passed in register R4. The
|
||||
* register R5 contains the thread parameter. The function chThdExit() is
|
||||
* called on thread function return.
|
||||
*--------------------------------------------------------------------------*/
|
||||
.thumb_func
|
||||
.globl _port_thread_start
|
||||
_port_thread_start:
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
#if CORTEX_SIMPLIFIED_PRIORITY
|
||||
cpsie i
|
||||
#else
|
||||
movs r3, #0 /* CORTEX_BASEPRI_DISABLED */
|
||||
msr BASEPRI, r3
|
||||
#endif
|
||||
mov r0, r5
|
||||
blx r4
|
||||
movs r0, #0 /* MSG_OK */
|
||||
bl chThdExit
|
||||
|
||||
/*--------------------------------------------------------------------------*
|
||||
* Post-IRQ switch code.
|
||||
*
|
||||
* Exception handlers return here for context switching.
|
||||
*--------------------------------------------------------------------------*/
|
||||
.thumb_func
|
||||
.globl _port_switch_from_isr
|
||||
_port_switch_from_isr:
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_start_measure_crit_thd
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_lock
|
||||
#endif
|
||||
bl chSchDoReschedule
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
.globl _port_exit_from_isr
|
||||
_port_exit_from_isr:
|
||||
#if CORTEX_SIMPLIFIED_PRIORITY
|
||||
movw r3, #:lower16:SCB_ICSR
|
||||
movt r3, #:upper16:SCB_ICSR
|
||||
mov r2, ICSR_PENDSVSET
|
||||
str r2, [r3, #0]
|
||||
cpsie i
|
||||
#else /* !CORTEX_SIMPLIFIED_PRIORITY */
|
||||
svc #0
|
||||
#endif /* !CORTEX_SIMPLIFIED_PRIORITY */
|
||||
.L1: b .L1
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/** @} */
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ARMCMx/compilers/GCC/chtypes.h
|
||||
* @brief ARM Cortex-Mx port system types.
|
||||
*
|
||||
* @addtogroup ARMCMx_GCC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHTYPES_H_
|
||||
#define _CHTYPES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @name Common constants
|
||||
*/
|
||||
/**
|
||||
* @brief Generic 'false' boolean constant.
|
||||
*/
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generic 'true' boolean constant.
|
||||
*/
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Kernel types
|
||||
* @{
|
||||
*/
|
||||
typedef uint32_t rtcnt_t; /**< Realtime counter. */
|
||||
typedef uint64_t rttime_t; /**< Realtime accumulator. */
|
||||
typedef uint32_t syssts_t; /**< System status word. */
|
||||
typedef uint8_t tmode_t; /**< Thread flags. */
|
||||
typedef uint8_t tstate_t; /**< Thread state. */
|
||||
typedef uint8_t trefs_t; /**< Thread references counter. */
|
||||
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
|
||||
typedef uint32_t tprio_t; /**< Thread priority. */
|
||||
typedef int32_t msg_t; /**< Inter-thread message. */
|
||||
typedef int32_t eventid_t; /**< Numeric event identifier. */
|
||||
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
|
||||
typedef uint32_t eventflags_t; /**< Mask of event flags. */
|
||||
typedef int32_t cnt_t; /**< Generic signed counter. */
|
||||
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief ROM constant modifier.
|
||||
* @note It is set to use the "const" keyword in this port.
|
||||
*/
|
||||
#define ROMCONST const
|
||||
|
||||
/**
|
||||
* @brief Makes functions not inlineable.
|
||||
* @note If the compiler does not support such attribute then the
|
||||
* realtime counter precision could be degraded.
|
||||
*/
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
|
||||
/**
|
||||
* @brief Optimized thread function declaration macro.
|
||||
*/
|
||||
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
|
||||
|
||||
/**
|
||||
* @brief Packed variable specifier.
|
||||
*/
|
||||
#define PACKED_VAR __attribute__((packed))
|
||||
|
||||
#endif /* _CHTYPES_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,8 +0,0 @@
|
|||
# List of the ChibiOS/RT Cortex-M0 STM32F0xx port files.
|
||||
PORTSRC = $(CHIBIOS)/os/rt/ports/ARMCMx/chcore.c \
|
||||
$(CHIBIOS)/os/rt/ports/ARMCMx/chcore_v6m.c
|
||||
|
||||
PORTASM = $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/chcoreasm_v6m.s
|
||||
|
||||
PORTINC = $(CHIBIOS)/os/rt/ports/ARMCMx \
|
||||
$(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC
|
|
@ -1,8 +0,0 @@
|
|||
# List of the ChibiOS/RT ARMv7M generic port files.
|
||||
PORTSRC = $(CHIBIOS)/os/rt/ports/ARMCMx/chcore.c \
|
||||
$(CHIBIOS)/os/rt/ports/ARMCMx/chcore_v7m.c
|
||||
|
||||
PORTASM = $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/chcoreasm_v7m.s
|
||||
|
||||
PORTINC = $(CHIBIOS)/os/rt/ports/ARMCMx \
|
||||
$(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file compilers/IAR/chcoreasm_v6m.s
|
||||
* @brief ARMv6-M architecture port low level code.
|
||||
*
|
||||
* @addtogroup ARMCMx_IAR_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define _FROM_ASM_
|
||||
#include "chconf.h"
|
||||
#include "chcore.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
MODULE ?chcoreasm_v6m
|
||||
|
||||
AAPCS INTERWORK, VFP_COMPATIBLE
|
||||
PRESERVE8
|
||||
|
||||
CONTEXT_OFFSET SET 12
|
||||
SCB_ICSR SET 0xE000ED04
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
|
||||
EXTERN chThdExit
|
||||
EXTERN chSchDoReschedule
|
||||
#if CH_DBG_STATISTICS
|
||||
EXTERN _stats_start_measure_crit_thd
|
||||
EXTERN _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
EXTERN _dbg_check_unlock
|
||||
EXTERN _dbg_check_lock
|
||||
#endif
|
||||
|
||||
THUMB
|
||||
|
||||
/*
|
||||
* Performs a context switch between two threads.
|
||||
*/
|
||||
PUBLIC _port_switch
|
||||
_port_switch:
|
||||
push {r4, r5, r6, r7, lr}
|
||||
mov r4, r8
|
||||
mov r5, r9
|
||||
mov r6, r10
|
||||
mov r7, r11
|
||||
push {r4, r5, r6, r7}
|
||||
mov r3, sp
|
||||
str r3, [r1, #CONTEXT_OFFSET]
|
||||
ldr r3, [r0, #CONTEXT_OFFSET]
|
||||
mov sp, r3
|
||||
pop {r4, r5, r6, r7}
|
||||
mov r8, r4
|
||||
mov r9, r5
|
||||
mov r10, r6
|
||||
mov r11, r7
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
|
||||
/*
|
||||
* Start a thread by invoking its work function.
|
||||
* If the work function returns @p chThdExit() is automatically invoked.
|
||||
*/
|
||||
PUBLIC _port_thread_start
|
||||
_port_thread_start:
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
cpsie i
|
||||
mov r0, r5
|
||||
blx r4
|
||||
bl chThdExit
|
||||
|
||||
/*
|
||||
* Post-IRQ switch code.
|
||||
* Exception handlers return here for context switching.
|
||||
*/
|
||||
PUBLIC _port_switch_from_isr
|
||||
PUBLIC _port_exit_from_isr
|
||||
_port_switch_from_isr:
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_start_measure_crit_thd
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_lock
|
||||
#endif
|
||||
bl chSchDoReschedule
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
_port_exit_from_isr:
|
||||
ldr r2, =SCB_ICSR
|
||||
movs r3, #128
|
||||
#if CORTEX_ALTERNATE_SWITCH
|
||||
lsls r3, r3, #21
|
||||
str r3, [r2, #0]
|
||||
cpsie i
|
||||
#else
|
||||
lsls r3, r3, #24
|
||||
str r3, [r2, #0]
|
||||
#endif
|
||||
waithere:
|
||||
b waithere
|
||||
|
||||
END
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/** @} */
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file compilers/IAR/chcoreasm_v7m.s
|
||||
* @brief ARMv7-M architecture port low level code.
|
||||
*
|
||||
* @addtogroup ARMCMx_IAR_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define _FROM_ASM_
|
||||
#include "chconf.h"
|
||||
#include "chcore.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
MODULE ?chcoreasm_v7m
|
||||
|
||||
AAPCS INTERWORK, VFP_COMPATIBLE
|
||||
PRESERVE8
|
||||
|
||||
CONTEXT_OFFSET SET 12
|
||||
SCB_ICSR SET 0xE000ED04
|
||||
ICSR_PENDSVSET SET 0x10000000
|
||||
|
||||
SECTION .text:CODE:NOROOT(2)
|
||||
|
||||
EXTERN chThdExit
|
||||
EXTERN chSchDoReschedule
|
||||
#if CH_DBG_STATISTICS
|
||||
EXTERN _stats_start_measure_crit_thd
|
||||
EXTERN _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
EXTERN _dbg_check_unlock
|
||||
EXTERN _dbg_check_lock
|
||||
#endif
|
||||
|
||||
THUMB
|
||||
|
||||
/*
|
||||
* Performs a context switch between two threads.
|
||||
*/
|
||||
PUBLIC _port_switch
|
||||
_port_switch:
|
||||
push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
|
||||
#if CORTEX_USE_FPU
|
||||
vpush {s16-s31}
|
||||
#endif
|
||||
|
||||
str sp, [r1, #CONTEXT_OFFSET]
|
||||
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) && \
|
||||
((CORTEX_MODEL == 3) || (CORTEX_MODEL == 4))
|
||||
/* Workaround for ARM errata 752419, only applied if
|
||||
condition exists for it to be triggered.*/
|
||||
ldr r3, [r0, #CONTEXT_OFFSET]
|
||||
mov sp, r3
|
||||
#else
|
||||
ldr sp, [r0, #CONTEXT_OFFSET]
|
||||
#endif
|
||||
|
||||
#if CORTEX_USE_FPU
|
||||
vpop {s16-s31}
|
||||
#endif
|
||||
pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||
|
||||
/*
|
||||
* Start a thread by invoking its work function.
|
||||
* If the work function returns @p chThdExit() is automatically invoked.
|
||||
*/
|
||||
PUBLIC _port_thread_start
|
||||
_port_thread_start:
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
#if CORTEX_SIMPLIFIED_PRIORITY
|
||||
cpsie i
|
||||
#else
|
||||
movs r3, #0 /* CORTEX_BASEPRI_DISABLED */
|
||||
msr BASEPRI, r3
|
||||
#endif
|
||||
mov r0, r5
|
||||
blx r4
|
||||
bl chThdExit
|
||||
|
||||
/*
|
||||
* Post-IRQ switch code.
|
||||
* Exception handlers return here for context switching.
|
||||
*/
|
||||
PUBLIC _port_switch_from_isr
|
||||
PUBLIC _port_exit_from_isr
|
||||
_port_switch_from_isr:
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_start_measure_crit_thd
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_lock
|
||||
#endif
|
||||
bl chSchDoReschedule
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
_port_exit_from_isr:
|
||||
#if CORTEX_SIMPLIFIED_PRIORITY
|
||||
mov r3, #LWRD SCB_ICSR
|
||||
movt r3, #HWRD SCB_ICSR
|
||||
mov r2, #ICSR_PENDSVSET
|
||||
str r2, [r3]
|
||||
cpsie i
|
||||
#else
|
||||
svc #0
|
||||
#endif
|
||||
.L3: b .L3
|
||||
|
||||
END
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/** @} */
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ARMCMx/compilers/IAR/chtypes.h
|
||||
* @brief ARM Cortex-Mx port system types.
|
||||
*
|
||||
* @addtogroup ARMCMx_IAR_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHTYPES_H_
|
||||
#define _CHTYPES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @name Common constants
|
||||
*/
|
||||
/**
|
||||
* @brief Generic 'false' boolean constant.
|
||||
*/
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generic 'true' boolean constant.
|
||||
*/
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Kernel types
|
||||
* @{
|
||||
*/
|
||||
typedef uint32_t rtcnt_t; /**< Realtime counter. */
|
||||
typedef uint64_t rttime_t; /**< Realtime accumulator. */
|
||||
typedef uint32_t syssts_t; /**< System status word. */
|
||||
typedef uint8_t tmode_t; /**< Thread flags. */
|
||||
typedef uint8_t tstate_t; /**< Thread state. */
|
||||
typedef uint8_t trefs_t; /**< Thread references counter. */
|
||||
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
|
||||
typedef uint32_t tprio_t; /**< Thread priority. */
|
||||
typedef int32_t msg_t; /**< Inter-thread message. */
|
||||
typedef int32_t eventid_t; /**< Numeric event identifier. */
|
||||
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
|
||||
typedef uint32_t eventflags_t; /**< Mask of event flags. */
|
||||
typedef int32_t cnt_t; /**< Generic signed counter. */
|
||||
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief ROM constant modifier.
|
||||
* @note It is set to use the "const" keyword in this port.
|
||||
*/
|
||||
#define ROMCONST const
|
||||
|
||||
/**
|
||||
* @brief Makes functions not inlineable.
|
||||
* @note If the compiler does not support such attribute then the
|
||||
* realtime counter precision could be degraded.
|
||||
*/
|
||||
#define NOINLINE
|
||||
|
||||
/**
|
||||
* @brief Optimized thread function declaration macro.
|
||||
*/
|
||||
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
|
||||
|
||||
/**
|
||||
* @brief Packed variable specifier.
|
||||
*/
|
||||
#define PACKED_VAR __packed
|
||||
|
||||
#endif /* _CHTYPES_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file compilers/RVCT/chcoreasm_v6m.s
|
||||
* @brief ARMv6-M architecture port low level code.
|
||||
*
|
||||
* @addtogroup ARMCMx_RVCT_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define _FROM_ASM_
|
||||
#include "chconf.h"
|
||||
#include "chcore.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
CONTEXT_OFFSET EQU 12
|
||||
SCB_ICSR EQU 0xE000ED04
|
||||
|
||||
PRESERVE8
|
||||
THUMB
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
IMPORT chThdExit
|
||||
IMPORT chSchDoReschedule
|
||||
#if CH_DBG_STATISTICS
|
||||
IMPORT _stats_start_measure_crit_thd
|
||||
IMPORT _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
IMPORT _dbg_check_unlock
|
||||
IMPORT _dbg_check_lock
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Performs a context switch between two threads.
|
||||
*/
|
||||
EXPORT _port_switch
|
||||
_port_switch PROC
|
||||
push {r4, r5, r6, r7, lr}
|
||||
mov r4, r8
|
||||
mov r5, r9
|
||||
mov r6, r10
|
||||
mov r7, r11
|
||||
push {r4, r5, r6, r7}
|
||||
mov r3, sp
|
||||
str r3, [r1, #CONTEXT_OFFSET]
|
||||
ldr r3, [r0, #CONTEXT_OFFSET]
|
||||
mov sp, r3
|
||||
pop {r4, r5, r6, r7}
|
||||
mov r8, r4
|
||||
mov r9, r5
|
||||
mov r10, r6
|
||||
mov r11, r7
|
||||
pop {r4, r5, r6, r7, pc}
|
||||
ENDP
|
||||
|
||||
/*
|
||||
* Start a thread by invoking its work function.
|
||||
* If the work function returns @p chThdExit() is automatically invoked.
|
||||
*/
|
||||
EXPORT _port_thread_start
|
||||
_port_thread_start PROC
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
cpsie i
|
||||
mov r0, r5
|
||||
blx r4
|
||||
bl chThdExit
|
||||
ENDP
|
||||
|
||||
/*
|
||||
* Post-IRQ switch code.
|
||||
* Exception handlers return here for context switching.
|
||||
*/
|
||||
EXPORT _port_switch_from_isr
|
||||
EXPORT _port_exit_from_isr
|
||||
_port_switch_from_isr PROC
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_start_measure_crit_thd
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_lock
|
||||
#endif
|
||||
bl chSchDoReschedule
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
_port_exit_from_isr
|
||||
ldr r2, =SCB_ICSR
|
||||
movs r3, #128
|
||||
#if CORTEX_ALTERNATE_SWITCH
|
||||
lsls r3, r3, #21
|
||||
str r3, [r2, #0]
|
||||
cpsie i
|
||||
#else
|
||||
lsls r3, r3, #24
|
||||
str r3, [r2, #0]
|
||||
#endif
|
||||
waithere b waithere
|
||||
ENDP
|
||||
|
||||
END
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/** @} */
|
|
@ -1,148 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file compilers/RVCT/chcoreasm_v7m.s
|
||||
* @brief ARMv7-M architecture port low level code.
|
||||
*
|
||||
* @addtogroup ARMCMx_RVCT_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define _FROM_ASM_
|
||||
#include "chconf.h"
|
||||
#include "chcore.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
CONTEXT_OFFSET EQU 12
|
||||
SCB_ICSR EQU 0xE000ED04
|
||||
ICSR_PENDSVSET EQU 0x10000000
|
||||
|
||||
PRESERVE8
|
||||
THUMB
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
IMPORT chThdExit
|
||||
IMPORT chSchDoReschedule
|
||||
#if CH_DBG_STATISTICS
|
||||
IMPORT _stats_start_measure_crit_thd
|
||||
IMPORT _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
IMPORT _dbg_check_unlock
|
||||
IMPORT _dbg_check_lock
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Performs a context switch between two threads.
|
||||
*/
|
||||
EXPORT _port_switch
|
||||
_port_switch PROC
|
||||
push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
|
||||
#if CORTEX_USE_FPU
|
||||
vpush {s16-s31}
|
||||
#endif
|
||||
|
||||
str sp, [r1, #CONTEXT_OFFSET]
|
||||
#if (CORTEX_SIMPLIFIED_PRIORITY == FALSE) && \
|
||||
((CORTEX_MODEL == 3) || (CORTEX_MODEL == 4))
|
||||
/* Workaround for ARM errata 752419, only applied if
|
||||
condition exists for it to be triggered.*/
|
||||
ldr r3, [r0, #CONTEXT_OFFSET]
|
||||
mov sp, r3
|
||||
#else
|
||||
ldr sp, [r0, #CONTEXT_OFFSET]
|
||||
#endif
|
||||
|
||||
#if CORTEX_USE_FPU
|
||||
vpop {s16-s31}
|
||||
#endif
|
||||
pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||
ENDP
|
||||
|
||||
/*
|
||||
* Start a thread by invoking its work function.
|
||||
* If the work function returns @p chThdExit() is automatically invoked.
|
||||
*/
|
||||
EXPORT _port_thread_start
|
||||
_port_thread_start PROC
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
#if CORTEX_SIMPLIFIED_PRIORITY
|
||||
cpsie i
|
||||
#else
|
||||
movs r3, #0 /* CORTEX_BASEPRI_DISABLED */
|
||||
msr BASEPRI, r3
|
||||
#endif
|
||||
mov r0, r5
|
||||
blx r4
|
||||
bl chThdExit
|
||||
ENDP
|
||||
|
||||
/*
|
||||
* Post-IRQ switch code.
|
||||
* Exception handlers return here for context switching.
|
||||
*/
|
||||
EXPORT _port_switch_from_isr
|
||||
EXPORT _port_exit_from_isr
|
||||
_port_switch_from_isr PROC
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_start_measure_crit_thd
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_lock
|
||||
#endif
|
||||
bl chSchDoReschedule
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
_port_exit_from_isr
|
||||
#if CORTEX_SIMPLIFIED_PRIORITY
|
||||
mov r3, #SCB_ICSR :AND: 0xFFFF
|
||||
movt r3, #SCB_ICSR :SHR: 16
|
||||
mov r2, #ICSR_PENDSVSET
|
||||
str r2, [r3, #0]
|
||||
cpsie i
|
||||
#else
|
||||
svc #0
|
||||
#endif
|
||||
waithere b waithere
|
||||
ENDP
|
||||
|
||||
END
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/** @} */
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ARMCMx/compilers/RVCT/chtypes.h
|
||||
* @brief ARM Cortex-Mx port system types.
|
||||
*
|
||||
* @addtogroup ARMCMx_RVCT_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHTYPES_H_
|
||||
#define _CHTYPES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @name Common constants
|
||||
*/
|
||||
/**
|
||||
* @brief Generic 'false' boolean constant.
|
||||
*/
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generic 'true' boolean constant.
|
||||
*/
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Kernel types
|
||||
* @{
|
||||
*/
|
||||
typedef uint32_t rtcnt_t; /**< Realtime counter. */
|
||||
typedef uint64_t rttime_t; /**< Realtime accumulator. */
|
||||
typedef uint32_t syssts_t; /**< System status word. */
|
||||
typedef uint8_t tmode_t; /**< Thread flags. */
|
||||
typedef uint8_t tstate_t; /**< Thread state. */
|
||||
typedef uint8_t trefs_t; /**< Thread references counter. */
|
||||
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
|
||||
typedef uint32_t tprio_t; /**< Thread priority. */
|
||||
typedef int32_t msg_t; /**< Inter-thread message. */
|
||||
typedef int32_t eventid_t; /**< Numeric event identifier. */
|
||||
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
|
||||
typedef uint32_t eventflags_t; /**< Mask of event flags. */
|
||||
typedef int32_t cnt_t; /**< Generic signed counter. */
|
||||
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief ROM constant modifier.
|
||||
* @note It is set to use the "const" keyword in this port.
|
||||
*/
|
||||
#define ROMCONST const
|
||||
|
||||
/**
|
||||
* @brief Makes functions not inlineable.
|
||||
* @note If the compiler does not support such attribute then the
|
||||
* realtime counter precision could be degraded.
|
||||
*/
|
||||
#define NOINLINE
|
||||
|
||||
/**
|
||||
* @brief Optimized thread function declaration macro.
|
||||
*/
|
||||
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
|
||||
|
||||
/**
|
||||
* @brief Packed variable specifier.
|
||||
*/
|
||||
#define PACKED_VAR __packed
|
||||
|
||||
#endif /* _CHTYPES_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,132 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AVR/chcore.c
|
||||
* @brief AVR architecture port code.
|
||||
*
|
||||
* @addtogroup AVR_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
/**
|
||||
* @brief Performs a context switch between two threads.
|
||||
* @details This is the most critical code in any port, this function
|
||||
* is responsible for the context switch between 2 threads.
|
||||
* @note The implementation of this code affects <b>directly</b> the context
|
||||
* switch performance so optimize here as much as you can.
|
||||
* @note The function is declared as a weak symbol, it is possible to
|
||||
* redefine it in your application code.
|
||||
*
|
||||
* @param[in] ntp the thread to be switched in
|
||||
* @param[in] otp the thread to be switched out
|
||||
*/
|
||||
#if !defined(__DOXYGEN__)
|
||||
__attribute__((naked, weak))
|
||||
#endif
|
||||
void port_switch(thread_t *ntp, thread_t *otp) {
|
||||
|
||||
asm volatile ("push r2");
|
||||
asm volatile ("push r3");
|
||||
asm volatile ("push r4");
|
||||
asm volatile ("push r5");
|
||||
asm volatile ("push r6");
|
||||
asm volatile ("push r7");
|
||||
asm volatile ("push r8");
|
||||
asm volatile ("push r9");
|
||||
asm volatile ("push r10");
|
||||
asm volatile ("push r11");
|
||||
asm volatile ("push r12");
|
||||
asm volatile ("push r13");
|
||||
asm volatile ("push r14");
|
||||
asm volatile ("push r15");
|
||||
asm volatile ("push r16");
|
||||
asm volatile ("push r17");
|
||||
asm volatile ("push r28");
|
||||
asm volatile ("push r29");
|
||||
|
||||
asm volatile ("movw r30, r22");
|
||||
asm volatile ("in r0, 0x3d");
|
||||
asm volatile ("std Z+5, r0");
|
||||
asm volatile ("in r0, 0x3e");
|
||||
asm volatile ("std Z+6, r0");
|
||||
|
||||
asm volatile ("movw r30, r24");
|
||||
asm volatile ("ldd r0, Z+5");
|
||||
asm volatile ("out 0x3d, r0");
|
||||
asm volatile ("ldd r0, Z+6");
|
||||
asm volatile ("out 0x3e, r0");
|
||||
|
||||
asm volatile ("pop r29");
|
||||
asm volatile ("pop r28");
|
||||
asm volatile ("pop r17");
|
||||
asm volatile ("pop r16");
|
||||
asm volatile ("pop r15");
|
||||
asm volatile ("pop r14");
|
||||
asm volatile ("pop r13");
|
||||
asm volatile ("pop r12");
|
||||
asm volatile ("pop r11");
|
||||
asm volatile ("pop r10");
|
||||
asm volatile ("pop r9");
|
||||
asm volatile ("pop r8");
|
||||
asm volatile ("pop r7");
|
||||
asm volatile ("pop r6");
|
||||
asm volatile ("pop r5");
|
||||
asm volatile ("pop r4");
|
||||
asm volatile ("pop r3");
|
||||
asm volatile ("pop r2");
|
||||
asm volatile ("ret");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Halts the system.
|
||||
* @details This function is invoked by the operating system when an
|
||||
* unrecoverable error is detected (for example because a programming
|
||||
* error in the application code that triggers an assertion while in
|
||||
* debug mode).
|
||||
* @note The function is declared as a weak symbol, it is possible to
|
||||
* redefine it in your application code.
|
||||
*/
|
||||
#if !defined(__DOXYGEN__)
|
||||
__attribute__((weak))
|
||||
#endif
|
||||
void port_halt(void) {
|
||||
|
||||
port_disable();
|
||||
while (TRUE) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start a thread by invoking its work function.
|
||||
* @details If the work function returns @p chThdExit() is automatically
|
||||
* invoked.
|
||||
*/
|
||||
void _port_thread_start(void) {
|
||||
|
||||
chSysUnlock();
|
||||
asm volatile ("movw r24, r4");
|
||||
asm volatile ("movw r30, r2");
|
||||
asm volatile ("icall");
|
||||
asm volatile ("call chThdExit");
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,390 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AVR/chcore.h
|
||||
* @brief AVR architecture port macros and structures.
|
||||
*
|
||||
* @addtogroup AVR_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHCORE_H_
|
||||
#define _CHCORE_H_
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#if CH_DBG_ENABLE_STACK_CHECK
|
||||
#error "option CH_DBG_ENABLE_STACK_CHECK not supported by this port"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief If enabled allows the idle thread to enter a low power mode.
|
||||
*/
|
||||
#ifndef ENABLE_WFI_IDLE
|
||||
#define ENABLE_WFI_IDLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Macro defining the AVR architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_AVR
|
||||
|
||||
/**
|
||||
* @brief Name of the implemented architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_NAME "AVR"
|
||||
|
||||
/**
|
||||
* @brief Name of the architecture variant (optional).
|
||||
*/
|
||||
#define PORT_CORE_VARIANT_NAME "MegaAVR"
|
||||
|
||||
/**
|
||||
* @brief Name of the compiler supported by this port.
|
||||
*/
|
||||
#define PORT_COMPILER_NAME "GCC " __VERSION__
|
||||
|
||||
/**
|
||||
* @brief Port-specific information string.
|
||||
*/
|
||||
#define PORT_INFO "None"
|
||||
|
||||
/**
|
||||
* @brief This port supports a realtime counter.
|
||||
*/
|
||||
#define PORT_SUPPORTS_RT FALSE
|
||||
|
||||
/**
|
||||
* @brief 8 bits stack and memory alignment enforcement.
|
||||
*/
|
||||
typedef uint8_t stkalign_t;
|
||||
|
||||
/**
|
||||
* @brief Interrupt saved context.
|
||||
* @details This structure represents the stack frame saved during a
|
||||
* preemption-capable interrupt handler.
|
||||
* @note The field @p _next is not part of the context, it represents the
|
||||
* offset of the structure relative to the stack pointer.
|
||||
*/
|
||||
struct port_extctx {
|
||||
uint8_t _next;
|
||||
uint8_t r31;
|
||||
uint8_t r30;
|
||||
uint8_t r27;
|
||||
uint8_t r26;
|
||||
uint8_t r25;
|
||||
uint8_t r24;
|
||||
uint8_t r23;
|
||||
uint8_t r22;
|
||||
uint8_t r21;
|
||||
uint8_t r20;
|
||||
uint8_t r19;
|
||||
uint8_t r18;
|
||||
uint8_t sr;
|
||||
uint8_t r1;
|
||||
uint8_t r0;
|
||||
#ifdef __AVR_3_BYTE_PC__
|
||||
uint8_t pcx;
|
||||
#endif
|
||||
uint16_t pc;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief System saved context.
|
||||
* @details This structure represents the inner stack frame during a context
|
||||
* switching.
|
||||
* @note The field @p _next is not part of the context, it represents the
|
||||
* offset of the structure relative to the stack pointer.
|
||||
*/
|
||||
struct port_intctx {
|
||||
uint8_t _next;
|
||||
uint8_t r29;
|
||||
uint8_t r28;
|
||||
uint8_t r17;
|
||||
uint8_t r16;
|
||||
uint8_t r15;
|
||||
uint8_t r14;
|
||||
uint8_t r13;
|
||||
uint8_t r12;
|
||||
uint8_t r11;
|
||||
uint8_t r10;
|
||||
uint8_t r9;
|
||||
uint8_t r8;
|
||||
uint8_t r7;
|
||||
uint8_t r6;
|
||||
uint8_t r5;
|
||||
uint8_t r4;
|
||||
uint8_t r3;
|
||||
uint8_t r2;
|
||||
#ifdef __AVR_3_BYTE_PC__
|
||||
uint8_t pcx;
|
||||
#endif
|
||||
uint8_t pcl;
|
||||
uint8_t pch;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p thread_t structure.
|
||||
* @details In the AVR port this structure just holds a pointer to the
|
||||
* @p port_intctx structure representing the stack pointer at the time
|
||||
* of the context switch.
|
||||
*/
|
||||
struct context {
|
||||
struct port_intctx *sp;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p chThdCreateI() API.
|
||||
* @details This code usually setup the context switching frame represented
|
||||
* by an @p port_intctx structure.
|
||||
*/
|
||||
#ifdef __AVR_3_BYTE_PC__
|
||||
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
|
||||
tp->p_ctx.sp = (struct port_intctx*)((uint8_t *)workspace + wsize - \
|
||||
sizeof(struct port_intctx)); \
|
||||
tp->p_ctx.sp->r2 = (int)pf; \
|
||||
tp->p_ctx.sp->r3 = (int)pf >> 8; \
|
||||
tp->p_ctx.sp->r4 = (int)arg; \
|
||||
tp->p_ctx.sp->r5 = (int)arg >> 8; \
|
||||
tp->p_ctx.sp->pcx = (int)0; \
|
||||
tp->p_ctx.sp->pcl = (int)_port_thread_start >> 8; \
|
||||
tp->p_ctx.sp->pch = (int)_port_thread_start; \
|
||||
}
|
||||
#else /* __AVR_3_BYTE_PC__ */
|
||||
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
|
||||
tp->p_ctx.sp = (struct port_intctx*)((uint8_t *)workspace + wsize - \
|
||||
sizeof(struct port_intctx)); \
|
||||
tp->p_ctx.sp->r2 = (int)pf; \
|
||||
tp->p_ctx.sp->r3 = (int)pf >> 8; \
|
||||
tp->p_ctx.sp->r4 = (int)arg; \
|
||||
tp->p_ctx.sp->r5 = (int)arg >> 8; \
|
||||
tp->p_ctx.sp->pcl = (int)_port_thread_start >> 8; \
|
||||
tp->p_ctx.sp->pch = (int)_port_thread_start; \
|
||||
}
|
||||
#endif /* __AVR_3_BYTE_PC__ */
|
||||
|
||||
/**
|
||||
* @brief Stack size for the system idle thread.
|
||||
* @details This size depends on the idle thread implementation, usually
|
||||
* the idle thread should take no more space than those reserved
|
||||
* by @p PORT_INT_REQUIRED_STACK.
|
||||
* @note In this port it is set to 8.
|
||||
*/
|
||||
#if !defined(PORT_IDLE_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
|
||||
#define PORT_IDLE_THREAD_STACK_SIZE 8
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Per-thread stack overhead for interrupts servicing.
|
||||
* @details This constant is used in the calculation of the correct working
|
||||
* area size.
|
||||
* This value can be zero on those architecture where there is a
|
||||
* separate interrupt stack and the stack space between @p port_intctx
|
||||
* and @p port_extctx is known to be zero.
|
||||
* @note In this port the default is 32 bytes per thread.
|
||||
*/
|
||||
#if !defined(PORT_INT_REQUIRED_STACK) || defined(__DOXYGEN__)
|
||||
#define PORT_INT_REQUIRED_STACK 32
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enforces a correct alignment for a stack area size value.
|
||||
*/
|
||||
#define STACK_ALIGN(n) ((((n) - 1) | (sizeof(stkalign_t) - 1)) + 1)
|
||||
|
||||
/**
|
||||
* @brief Computes the thread working area global size.
|
||||
*/
|
||||
#define PORT_WA_SIZE(n) STACK_ALIGN(sizeof(thread_t) + \
|
||||
(sizeof(struct port_intctx) - 1) + \
|
||||
(sizeof(struct port_extctx) - 1) + \
|
||||
(n) + (PORT_INT_REQUIRED_STACK))
|
||||
|
||||
/**
|
||||
* @brief Static working area allocation.
|
||||
* @details This macro is used to allocate a static thread working area
|
||||
* aligned as both position and size.
|
||||
*/
|
||||
#define WORKING_AREA(s, n) stkalign_t s[PORT_WA_SIZE(n) / sizeof(stkalign_t)]
|
||||
|
||||
/**
|
||||
* @brief IRQ prologue code.
|
||||
* @details This macro must be inserted at the start of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
* @note This code tricks the compiler to save all the specified registers
|
||||
* by "touching" them.
|
||||
*/
|
||||
#define PORT_IRQ_PROLOGUE() { \
|
||||
asm ("" : : : "r18", "r19", "r20", "r21", "r22", "r23", "r24", \
|
||||
"r25", "r26", "r27", "r30", "r31"); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief IRQ epilogue code.
|
||||
* @details This macro must be inserted at the end of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#define PORT_IRQ_EPILOGUE() { \
|
||||
_dbg_check_lock(); \
|
||||
if (chSchIsPreemptionRequired()) \
|
||||
chSchDoReschedule(); \
|
||||
_dbg_check_unlock(); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_IRQ_HANDLER(id) ISR(id)
|
||||
|
||||
/**
|
||||
* @brief Port-related initialization code.
|
||||
* @note This function is empty in this port.
|
||||
*/
|
||||
#define port_init()
|
||||
|
||||
/**
|
||||
* @brief Returns a word encoding the current interrupts status.
|
||||
*
|
||||
* @return The interrupts status.
|
||||
*/
|
||||
static inline syssts_t port_get_irq_status(void) {
|
||||
|
||||
return SREG;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the interrupt status.
|
||||
*
|
||||
* @param[in] sts the interrupt status word
|
||||
*
|
||||
* @return The interrupt status.
|
||||
* @retvel false the word specified a disabled interrupts status.
|
||||
* @retvel true the word specified an enabled interrupts status.
|
||||
*/
|
||||
static inline bool port_irq_enabled(syssts_t sts) {
|
||||
|
||||
return (bool)((sts & 0x80) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines the current execution context.
|
||||
*
|
||||
* @return The execution context.
|
||||
* @retval false not running in ISR mode.
|
||||
* @retval true running in ISR mode.
|
||||
*/
|
||||
static inline bool port_is_isr_context(void) {
|
||||
|
||||
//TODO: is there any way to determine this?
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action.
|
||||
* @details Usually this function just disables interrupts but may perform more
|
||||
* actions.
|
||||
* @note Implemented as global interrupt disable.
|
||||
*/
|
||||
#define port_lock() asm volatile ("cli" : : : "memory")
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action.
|
||||
* @details Usually this function just enables interrupts but may perform more
|
||||
* actions.
|
||||
* @note Implemented as global interrupt enable.
|
||||
*/
|
||||
#define port_unlock() asm volatile ("sei" : : : "memory")
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action from an interrupt handler.
|
||||
* @details This function is invoked before invoking I-class APIs from
|
||||
* interrupt handlers. The implementation is architecture dependent,
|
||||
* in its simplest form it is void.
|
||||
* @note This function is empty in this port.
|
||||
*/
|
||||
#define port_lock_from_isr()
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action from an interrupt handler.
|
||||
* @details This function is invoked after invoking I-class APIs from interrupt
|
||||
* handlers. The implementation is architecture dependent, in its
|
||||
* simplest form it is void.
|
||||
* @note This function is empty in this port.
|
||||
*/
|
||||
#define port_unlock_from_isr()
|
||||
|
||||
/**
|
||||
* @brief Disables all the interrupt sources.
|
||||
* @note Of course non-maskable interrupt sources are not included.
|
||||
* @note Implemented as global interrupt disable.
|
||||
*/
|
||||
#define port_disable() asm volatile ("cli" : : : "memory")
|
||||
|
||||
/**
|
||||
* @brief Disables the interrupt sources below kernel-level priority.
|
||||
* @note Interrupt sources above kernel level remains enabled.
|
||||
* @note Same as @p port_disable() in this port, there is no difference
|
||||
* between the two states.
|
||||
*/
|
||||
#define port_suspend() asm volatile ("cli" : : : "memory")
|
||||
|
||||
/**
|
||||
* @brief Enables all the interrupt sources.
|
||||
* @note Implemented as global interrupt enable.
|
||||
*/
|
||||
#define port_enable() asm volatile ("sei" : : : "memory")
|
||||
|
||||
/**
|
||||
* @brief Enters an architecture-dependent IRQ-waiting mode.
|
||||
* @details The function is meant to return when an interrupt becomes pending.
|
||||
* The simplest implementation is an empty function or macro but this
|
||||
* would not take advantage of architecture-specific power saving
|
||||
* modes.
|
||||
* @note This port function is implemented as inlined code for performance
|
||||
* reasons.
|
||||
*/
|
||||
#if ENABLE_WFI_IDLE != 0
|
||||
#define port_wait_for_interrupt() { \
|
||||
asm volatile ("sleep" : : : "memory"); \
|
||||
}
|
||||
#else
|
||||
#define port_wait_for_interrupt()
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void port_switch(thread_t *ntp, thread_t *otp);
|
||||
void port_halt(void);
|
||||
void _port_thread_start(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CH_CFG_ST_TIMEDELTA > 0
|
||||
#include "chcore_timer.h"
|
||||
#endif
|
||||
|
||||
#endif /* _CHCORE_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AVR/chcore_timer.h
|
||||
* @brief System timer header file.
|
||||
*
|
||||
* @addtogroup AVR_TIMER
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHCORE_TIMER_H_
|
||||
#define _CHCORE_TIMER_H_
|
||||
|
||||
/* This is the only header in the HAL designed to be include-able alone.*/
|
||||
#include "st.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Starts the alarm.
|
||||
* @note Makes sure that no spurious alarms are triggered after
|
||||
* this call.
|
||||
*
|
||||
* @param[in] time the time to be set for the first alarm
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void port_timer_start_alarm(systime_t time) {
|
||||
|
||||
stStartAlarm(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the alarm interrupt.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void port_timer_stop_alarm(void) {
|
||||
|
||||
stStopAlarm();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the alarm time.
|
||||
*
|
||||
* @param[in] time the time to be set for the next alarm
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline void port_timer_set_alarm(systime_t time) {
|
||||
|
||||
stSetAlarm(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the system time.
|
||||
*
|
||||
* @return The system time.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline systime_t port_timer_get_time(void) {
|
||||
|
||||
return stGetCounter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current alarm time.
|
||||
*
|
||||
* @return The currently set alarm time.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static inline systime_t port_timer_get_alarm(void) {
|
||||
|
||||
return stGetAlarm();
|
||||
}
|
||||
|
||||
#endif /* _CHCORE_TIMER_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file AVR/compilers/GCC/chtypes.h
|
||||
* @brief AVR architecture port system types.
|
||||
*
|
||||
* @addtogroup AVR_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHTYPES_H_
|
||||
#define _CHTYPES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @name Common constants
|
||||
*/
|
||||
/**
|
||||
* @brief Generic 'false' boolean constant.
|
||||
*/
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generic 'true' boolean constant.
|
||||
*/
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
typedef bool bool_t; /**< Fast boolean type. */
|
||||
typedef uint8_t syssts_t; /**< System status word. */
|
||||
typedef uint8_t tmode_t; /**< Thread flags. */
|
||||
typedef uint8_t tstate_t; /**< Thread state. */
|
||||
typedef uint8_t trefs_t; /**< Thread references counter. */
|
||||
typedef uint8_t tslices_t; /**< Thread time slices counter. */
|
||||
typedef uint8_t tprio_t; /**< Thread priority. */
|
||||
typedef int16_t msg_t; /**< Inter-thread message. */
|
||||
typedef uint8_t eventid_t; /**< Event Id. */
|
||||
typedef uint8_t eventmask_t; /**< Event mask. */
|
||||
typedef uint8_t eventflags_t; /**< Event flags. */
|
||||
typedef int8_t cnt_t; /**< Resources counter. */
|
||||
|
||||
/**
|
||||
* @brief ROM constant modifier.
|
||||
* @note It is set to use the "const" keyword in this port.
|
||||
*/
|
||||
#define ROMCONST const
|
||||
|
||||
/**
|
||||
* @brief Makes functions not inlineable.
|
||||
* @note If the compiler does not support such attribute then the
|
||||
* realtime counter precision could be degraded.
|
||||
*/
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
|
||||
/**
|
||||
* @brief Optimized thread function declaration macro.
|
||||
*/
|
||||
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
|
||||
|
||||
/**
|
||||
* @brief Packed variable specifier.
|
||||
*/
|
||||
#define PACKED_VAR __attribute__((packed))
|
||||
|
||||
#endif /* _CHTYPES_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,7 +0,0 @@
|
|||
# List of the ChibiOS/RT AVR port files.
|
||||
PORTSRC = ${CHIBIOS}/os/rt/ports/AVR/chcore.c
|
||||
|
||||
PORTASM =
|
||||
|
||||
PORTINC = ${CHIBIOS}/os/rt/ports/AVR \
|
||||
${CHIBIOS}/os/rt/ports/AVR/compilers/GCC
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SIMIA32/chcore.c
|
||||
* @brief Simulator on IA32 port code.
|
||||
*
|
||||
* @addtogroup SIMIA32_GCC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
bool port_isr_context_flag;
|
||||
syssts_t port_irq_sts;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* Performs a context switch between two threads.
|
||||
* @param otp the thread to be switched out
|
||||
* @param ntp the thread to be switched in
|
||||
*/
|
||||
__attribute__((used))
|
||||
static void __dummy(thread_t *ntp, thread_t *otp) {
|
||||
(void)ntp; (void)otp;
|
||||
|
||||
asm volatile (
|
||||
#if defined(WIN32)
|
||||
".globl @port_switch@8 \n\t"
|
||||
"@port_switch@8:"
|
||||
#elif defined(__APPLE__)
|
||||
".globl _port_switch \n\t"
|
||||
"_port_switch:"
|
||||
#else
|
||||
".globl port_switch \n\t"
|
||||
"port_switch:"
|
||||
#endif
|
||||
"push %ebp \n\t"
|
||||
"push %esi \n\t"
|
||||
"push %edi \n\t"
|
||||
"push %ebx \n\t"
|
||||
"movl %esp, 12(%edx) \n\t"
|
||||
"movl 12(%ecx), %esp \n\t"
|
||||
"pop %ebx \n\t"
|
||||
"pop %edi \n\t"
|
||||
"pop %esi \n\t"
|
||||
"pop %ebp \n\t"
|
||||
"ret");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start a thread by invoking its work function.
|
||||
* @details If the work function returns @p chThdExit() is automatically
|
||||
* invoked.
|
||||
*/
|
||||
__attribute__((cdecl, noreturn))
|
||||
void _port_thread_start(msg_t (*pf)(void *), void *p) {
|
||||
|
||||
chSysUnlock();
|
||||
pf(p);
|
||||
chThdExit(0);
|
||||
while(1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns the current value of the realtime counter.
|
||||
*
|
||||
* @return The realtime counter value.
|
||||
*/
|
||||
rtcnt_t port_rt_get_counter_value(void) {
|
||||
LARGE_INTEGER n;
|
||||
|
||||
QueryPerformanceCounter(&n);
|
||||
|
||||
return (rtcnt_t)(n.QuadPart / 1000LL);
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,382 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SIMIA32/chcore.h
|
||||
* @brief Simulator on IA32 port macros and structures.
|
||||
*
|
||||
* @addtogroup SIMIA32_GCC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHCORE_H_
|
||||
#define _CHCORE_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* Macro defining the a simulated architecture into x86.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_SIMIA32
|
||||
|
||||
/**
|
||||
* Name of the implemented architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_NAME "Simulator"
|
||||
|
||||
/**
|
||||
* @brief Name of the architecture variant (optional).
|
||||
*/
|
||||
#define PORT_CORE_VARIANT_NAME "x86 (integer only)"
|
||||
|
||||
/**
|
||||
* @brief Name of the compiler supported by this port.
|
||||
*/
|
||||
#define PORT_COMPILER_NAME "GCC " __VERSION__
|
||||
|
||||
/**
|
||||
* @brief Port-specific information string.
|
||||
*/
|
||||
#define PORT_INFO "No preemption"
|
||||
|
||||
/**
|
||||
* @brief This port supports a realtime counter.
|
||||
*/
|
||||
#define PORT_SUPPORTS_RT TRUE
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Stack size for the system idle thread.
|
||||
* @details This size depends on the idle thread implementation, usually
|
||||
* the idle thread should take no more space than those reserved
|
||||
* by @p PORT_INT_REQUIRED_STACK.
|
||||
*/
|
||||
#ifndef PORT_IDLE_THREAD_STACK_SIZE
|
||||
#define PORT_IDLE_THREAD_STACK_SIZE 256
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Per-thread stack overhead for interrupts servicing.
|
||||
* @details This constant is used in the calculation of the correct working
|
||||
* area size.
|
||||
*/
|
||||
#ifndef PORT_INT_REQUIRED_STACK
|
||||
#define PORT_INT_REQUIRED_STACK 16384
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enables an alternative timer implementation.
|
||||
* @details Usually the port uses a timer interface defined in the file
|
||||
* @p chcore_timer.h, if this option is enabled then the file
|
||||
* @p chcore_timer_alt.h is included instead.
|
||||
*/
|
||||
#if !defined(PORT_USE_ALT_TIMER)
|
||||
#define PORT_USE_ALT_TIMER FALSE
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if CH_DBG_ENABLE_STACK_CHECK
|
||||
#error "option CH_DBG_ENABLE_STACK_CHECK not supported by this port"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief 16 bytes stack and memory alignment enforcement.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t a[16];
|
||||
} stkalign_t __attribute__((aligned(16)));
|
||||
|
||||
/**
|
||||
* @brief Type of a generic x86 register.
|
||||
*/
|
||||
typedef void *regx86;
|
||||
|
||||
/**
|
||||
* @brief Interrupt saved context.
|
||||
* @details This structure represents the stack frame saved during a
|
||||
* preemption-capable interrupt handler.
|
||||
*/
|
||||
struct port_extctx {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief System saved context.
|
||||
* @details This structure represents the inner stack frame during a context
|
||||
* switch.
|
||||
*/
|
||||
struct port_intctx {
|
||||
regx86 ebx;
|
||||
regx86 edi;
|
||||
regx86 esi;
|
||||
regx86 ebp;
|
||||
regx86 eip;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p thread_t structure.
|
||||
* @details In this port the structure just holds a pointer to the
|
||||
* @p port_intctx structure representing the stack pointer
|
||||
* at context switch time.
|
||||
*/
|
||||
struct context {
|
||||
struct port_intctx *esp;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define APUSH(p, a) do { \
|
||||
(p) -= sizeof(void *); \
|
||||
*(void **)(p) = (void*)(a); \
|
||||
} while (false)
|
||||
|
||||
/* Darwin requires the stack to be aligned to a 16-byte boundary at
|
||||
* the time of a call instruction (in case the called function needs
|
||||
* to save MMX registers). This aligns to 'mod' module 16, so that we'll end
|
||||
* up with the right alignment after pushing the args. */
|
||||
#define AALIGN(p, mask, mod) \
|
||||
p = (void *)((((uint32_t)(p) - (uint32_t)(mod)) & ~(uint32_t)(mask)) + (uint32_t)(mod)) \
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p chThdCreateI() API.
|
||||
* @details This code usually setup the context switching frame represented
|
||||
* by an @p port_intctx structure.
|
||||
*/
|
||||
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
|
||||
/*lint -save -e611 -e9033 -e9074 -e9087 [10.8, 11.1, 11.3] Valid casts.*/ \
|
||||
uint8_t *esp = (uint8_t *)workspace + wsize; \
|
||||
APUSH(esp, 0); \
|
||||
uint8_t *savebp = esp; \
|
||||
AALIGN(esp, 15, 8); \
|
||||
APUSH(esp, arg); \
|
||||
APUSH(esp, pf); \
|
||||
APUSH(esp, 0); \
|
||||
esp -= sizeof(struct port_intctx); \
|
||||
((struct port_intctx *)esp)->eip = (void *)_port_thread_start; \
|
||||
((struct port_intctx *)esp)->ebx = NULL; \
|
||||
((struct port_intctx *)esp)->edi = NULL; \
|
||||
((struct port_intctx *)esp)->esi = NULL; \
|
||||
((struct port_intctx *)esp)->ebp = (void *)savebp; \
|
||||
(tp)->p_ctx.esp = (struct port_intctx *)esp; \
|
||||
/*lint -restore*/ \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the thread working area global size.
|
||||
* @note There is no need to perform alignments in this macro.
|
||||
*/
|
||||
#define PORT_WA_SIZE(n) ((sizeof(void *) * 4U) + \
|
||||
sizeof(struct port_intctx) + \
|
||||
((size_t)(n)) + \
|
||||
((size_t)(PORT_INT_REQUIRED_STACK)))
|
||||
|
||||
/**
|
||||
* @brief IRQ prologue code.
|
||||
* @details This macro must be inserted at the start of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#define PORT_IRQ_PROLOGUE() { \
|
||||
port_isr_context_flag = true; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief IRQ epilogue code.
|
||||
* @details This macro must be inserted at the end of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#define PORT_IRQ_EPILOGUE() { \
|
||||
port_isr_context_flag = false; \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_IRQ_HANDLER(id) void id(void)
|
||||
|
||||
/**
|
||||
* @brief Fast IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_FAST_IRQ_HANDLER(id) void id(void)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
extern bool port_isr_context_flag;
|
||||
extern syssts_t port_irq_sts;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*lint -save -e950 [Dir-2.1] Non-ANSI keywords are fine in the port layer.*/
|
||||
__attribute__((fastcall)) void port_switch(thread_t *ntp, thread_t *otp);
|
||||
__attribute__((cdecl, noreturn)) void _port_thread_start(msg_t (*pf)(void *p),
|
||||
void *p);
|
||||
/*lint -restore*/
|
||||
rtcnt_t port_rt_get_counter_value(void);
|
||||
void _sim_check_for_interrupts(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Port-related initialization code.
|
||||
*/
|
||||
static inline void port_init(void) {
|
||||
|
||||
port_irq_sts = (syssts_t)0;
|
||||
port_isr_context_flag = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a word encoding the current interrupts status.
|
||||
*
|
||||
* @return The interrupts status.
|
||||
*/
|
||||
static inline syssts_t port_get_irq_status(void) {
|
||||
|
||||
return port_irq_sts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the interrupt status.
|
||||
*
|
||||
* @param[in] sts the interrupt status word
|
||||
*
|
||||
* @return The interrupt status.
|
||||
* @retvel false the word specified a disabled interrupts status.
|
||||
* @retvel true the word specified an enabled interrupts status.
|
||||
*/
|
||||
static inline bool port_irq_enabled(syssts_t sts) {
|
||||
|
||||
return sts == (syssts_t)0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines the current execution context.
|
||||
*
|
||||
* @return The execution context.
|
||||
* @retval false not running in ISR mode.
|
||||
* @retval true running in ISR mode.
|
||||
*/
|
||||
static inline bool port_is_isr_context(void) {
|
||||
|
||||
return port_isr_context_flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action.
|
||||
* @details In this port this function disables interrupts globally.
|
||||
*/
|
||||
static inline void port_lock(void) {
|
||||
|
||||
port_irq_sts = (syssts_t)1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action.
|
||||
* @details In this port this function enables interrupts globally.
|
||||
*/
|
||||
static inline void port_unlock(void) {
|
||||
|
||||
port_irq_sts = (syssts_t)0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action from an interrupt handler.
|
||||
* @details In this port this function disables interrupts globally.
|
||||
* @note Same as @p port_lock() in this port.
|
||||
*/
|
||||
static inline void port_lock_from_isr(void) {
|
||||
|
||||
port_irq_sts = (syssts_t)1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action from an interrupt handler.
|
||||
* @details In this port this function enables interrupts globally.
|
||||
* @note Same as @p port_lock() in this port.
|
||||
*/
|
||||
static inline void port_unlock_from_isr(void) {
|
||||
|
||||
port_irq_sts = (syssts_t)0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables all the interrupt sources.
|
||||
*/
|
||||
static inline void port_disable(void) {
|
||||
|
||||
port_irq_sts = (syssts_t)1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables the interrupt sources below kernel-level priority.
|
||||
*/
|
||||
static inline void port_suspend(void) {
|
||||
|
||||
port_irq_sts = (syssts_t)1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables all the interrupt sources.
|
||||
*/
|
||||
static inline void port_enable(void) {
|
||||
|
||||
port_irq_sts = (syssts_t)0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enters an architecture-dependent IRQ-waiting mode.
|
||||
* @details The function is meant to return when an interrupt becomes pending.
|
||||
* The simplest implementation is an empty function or macro but this
|
||||
* would not take advantage of architecture-specific power saving
|
||||
* modes.
|
||||
* @note Implemented as an inlined @p WFI instruction.
|
||||
*/
|
||||
static inline void port_wait_for_interrupt(void) {
|
||||
|
||||
_sim_check_for_interrupts();
|
||||
}
|
||||
|
||||
#endif /* _CHCORE_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SIMIA32/compilers/GCC/chtypes.h
|
||||
* @brief Simulator on IA32 port system types.
|
||||
*
|
||||
* @addtogroup SIMIA32_GCC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHTYPES_H_
|
||||
#define _CHTYPES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @name Common constants
|
||||
*/
|
||||
/**
|
||||
* @brief Generic 'false' boolean constant.
|
||||
*/
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generic 'true' boolean constant.
|
||||
*/
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Derived generic types
|
||||
* @{
|
||||
*/
|
||||
typedef volatile int8_t vint8_t; /**< Volatile signed 8 bits. */
|
||||
typedef volatile uint8_t vuint8_t; /**< Volatile unsigned 8 bits. */
|
||||
typedef volatile int16_t vint16_t; /**< Volatile signed 16 bits. */
|
||||
typedef volatile uint16_t vuint16_t; /**< Volatile unsigned 16 bits. */
|
||||
typedef volatile int32_t vint32_t; /**< Volatile signed 32 bits. */
|
||||
typedef volatile uint32_t vuint32_t; /**< Volatile unsigned 32 bits. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Kernel types
|
||||
* @{
|
||||
*/
|
||||
typedef uint32_t rtcnt_t; /**< Realtime counter. */
|
||||
typedef uint64_t rttime_t; /**< Realtime accumulator. */
|
||||
typedef uint32_t syssts_t; /**< System status word. */
|
||||
typedef uint8_t tmode_t; /**< Thread flags. */
|
||||
typedef uint8_t tstate_t; /**< Thread state. */
|
||||
typedef uint8_t trefs_t; /**< Thread references counter. */
|
||||
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
|
||||
typedef uint32_t tprio_t; /**< Thread priority. */
|
||||
typedef int32_t msg_t; /**< Inter-thread message. */
|
||||
typedef int32_t eventid_t; /**< Numeric event identifier. */
|
||||
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
|
||||
typedef uint32_t eventflags_t; /**< Mask of event flags. */
|
||||
typedef int32_t cnt_t; /**< Generic signed counter. */
|
||||
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief ROM constant modifier.
|
||||
* @note It is set to use the "const" keyword in this port.
|
||||
*/
|
||||
#define ROMCONST const
|
||||
|
||||
/**
|
||||
* @brief Makes functions not inlineable.
|
||||
* @note If the compiler does not support such attribute then the
|
||||
* realtime counter precision could be degraded.
|
||||
*/
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
|
||||
/**
|
||||
* @brief Optimized thread function declaration macro.
|
||||
*/
|
||||
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
|
||||
|
||||
/**
|
||||
* @brief Packed variable specifier.
|
||||
*/
|
||||
#define PACKED_VAR __attribute__((packed))
|
||||
|
||||
#endif /* _CHTYPES_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,7 +0,0 @@
|
|||
# List of the ChibiOS/RT SIMIA32 port files.
|
||||
PORTSRC = ${CHIBIOS}/os/rt/ports/SIMIA32/chcore.c
|
||||
|
||||
PORTASM =
|
||||
|
||||
PORTINC = ${CHIBIOS}/os/rt/ports/SIMIA32/compilers/GCC \
|
||||
${CHIBIOS}/os/rt/ports/SIMIA32
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file e200/chcore.c
|
||||
* @brief Power e200 port code.
|
||||
*
|
||||
* @addtogroup PPC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/** @} */
|
|
@ -1,599 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file PPC/chcore.h
|
||||
* @brief Power e200 port macros and structures.
|
||||
*
|
||||
* @addtogroup PPC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHCORE_H_
|
||||
#define _CHCORE_H_
|
||||
|
||||
#include "intc.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Architecture and Compiler
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Macro defining an PPC architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_PPC
|
||||
|
||||
/**
|
||||
* @brief Macro defining the specific PPC architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_PPC_E200
|
||||
|
||||
/**
|
||||
* @brief Name of the implemented architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_NAME "Power Architecture"
|
||||
|
||||
/**
|
||||
* @brief Compiler name and version.
|
||||
*/
|
||||
#if defined(__GNUC__) || defined(__DOXYGEN__)
|
||||
#define PORT_COMPILER_NAME "GCC " __VERSION__
|
||||
|
||||
#elif defined(__MWERKS__)
|
||||
#define PORT_COMPILER_NAME "CW"
|
||||
|
||||
#else
|
||||
#error "unsupported compiler"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief This port supports a realtime counter.
|
||||
*/
|
||||
#define PORT_SUPPORTS_RT FALSE
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name E200 core variants
|
||||
* @{
|
||||
*/
|
||||
#define PPC_VARIANT_e200z0 200
|
||||
#define PPC_VARIANT_e200z2 202
|
||||
#define PPC_VARIANT_e200z3 203
|
||||
#define PPC_VARIANT_e200z4 204
|
||||
/** @} */
|
||||
|
||||
/* Inclusion of the PPC implementation specific parameters.*/
|
||||
#include "ppcparams.h"
|
||||
#include "vectors.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Stack size for the system idle thread.
|
||||
* @details This size depends on the idle thread implementation, usually
|
||||
* the idle thread should take no more space than those reserved
|
||||
* by @p PORT_INT_REQUIRED_STACK.
|
||||
* @note In this port it is set to 32 because the idle thread does have
|
||||
* a stack frame when compiling without optimizations. You may
|
||||
* reduce this value to zero when compiling with optimizations.
|
||||
*/
|
||||
#if !defined(PORT_IDLE_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
|
||||
#define PORT_IDLE_THREAD_STACK_SIZE 32
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Per-thread stack overhead for interrupts servicing.
|
||||
* @details This constant is used in the calculation of the correct working
|
||||
* area size.
|
||||
* @note In this port this value is conservatively is set to 256 because
|
||||
* there is no separate interrupts stack (yet).
|
||||
*/
|
||||
#if !defined(PORT_INT_REQUIRED_STACK) || defined(__DOXYGEN__)
|
||||
#define PORT_INT_REQUIRED_STACK 256
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enables an alternative timer implementation.
|
||||
* @details Usually the port uses a timer interface defined in the file
|
||||
* @p chcore_timer.h, if this option is enabled then the file
|
||||
* @p chcore_timer_alt.h is included instead.
|
||||
*/
|
||||
#if !defined(PORT_USE_ALT_TIMER) || defined(__DOXYGEN__)
|
||||
#define PORT_USE_ALT_TIMER FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Use VLE instruction set.
|
||||
* @note This parameter is usually set in the Makefile.
|
||||
*/
|
||||
#if !defined(PPC_USE_VLE) || defined(__DOXYGEN__)
|
||||
#define PPC_USE_VLE TRUE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enables the use of the @p WFI instruction.
|
||||
*/
|
||||
#if !defined(PPC_ENABLE_WFI_IDLE) || defined(__DOXYGEN__)
|
||||
#define PPC_ENABLE_WFI_IDLE FALSE
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if PPC_USE_VLE && !PPC_SUPPORTS_VLE
|
||||
#error "the selected MCU does not support VLE instructions set"
|
||||
#endif
|
||||
|
||||
#if !PPC_USE_VLE && !PPC_SUPPORTS_BOOKE
|
||||
#error "the selected MCU does not support BookE instructions set"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Name of the architecture variant.
|
||||
*/
|
||||
#if (PPC_VARIANT == PPC_VARIANT_e200z0) || defined(__DOXYGEN__)
|
||||
#define PORT_CORE_VARIANT_NAME "e200z0"
|
||||
#elif PPC_VARIANT == PPC_VARIANT_e200z2
|
||||
#define PORT_CORE_VARIANT_NAME "e200z2"
|
||||
#elif PPC_VARIANT == PPC_VARIANT_e200z3
|
||||
#define PORT_CORE_VARIANT_NAME "e200z3"
|
||||
#elif PPC_VARIANT == PPC_VARIANT_e200z4
|
||||
#define PORT_CORE_VARIANT_NAME "e200z4"
|
||||
#else
|
||||
#error "unknown or unsupported PowerPC variant specified"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Port-specific information string.
|
||||
*/
|
||||
#if PPC_USE_VLE
|
||||
#define PORT_INFO "VLE mode"
|
||||
#else
|
||||
#define PORT_INFO "Book-E mode"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
/**
|
||||
* @brief Type of stack and memory alignment enforcement.
|
||||
* @note In this architecture the stack alignment is enforced to 64 bits.
|
||||
*/
|
||||
typedef uint64_t stkalign_t;
|
||||
|
||||
/**
|
||||
* @brief Generic PPC register.
|
||||
*/
|
||||
typedef void *regppc_t;
|
||||
|
||||
/**
|
||||
* @brief Mandatory part of a stack frame.
|
||||
*/
|
||||
struct port_eabi_frame {
|
||||
uint32_t slink; /**< Stack back link. */
|
||||
uint32_t shole; /**< Stack hole for LR storage. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Interrupt saved context.
|
||||
* @details This structure represents the stack frame saved during a
|
||||
* preemption-capable interrupt handler.
|
||||
* @note R2 and R13 are not saved because those are assumed to be immutable
|
||||
* during the system life cycle.
|
||||
*/
|
||||
struct port_extctx {
|
||||
struct port_eabi_frame frame;
|
||||
/* Start of the e_stmvsrrw frame (offset 8).*/
|
||||
regppc_t pc;
|
||||
regppc_t msr;
|
||||
/* Start of the e_stmvsprw frame (offset 16).*/
|
||||
regppc_t cr;
|
||||
regppc_t lr;
|
||||
regppc_t ctr;
|
||||
regppc_t xer;
|
||||
/* Start of the e_stmvgprw frame (offset 32).*/
|
||||
regppc_t r0;
|
||||
regppc_t r3;
|
||||
regppc_t r4;
|
||||
regppc_t r5;
|
||||
regppc_t r6;
|
||||
regppc_t r7;
|
||||
regppc_t r8;
|
||||
regppc_t r9;
|
||||
regppc_t r10;
|
||||
regppc_t r11;
|
||||
regppc_t r12;
|
||||
regppc_t padding;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief System saved context.
|
||||
* @details This structure represents the inner stack frame during a context
|
||||
* switching.
|
||||
* @note R2 and R13 are not saved because those are assumed to be immutable
|
||||
* during the system life cycle.
|
||||
* @note LR is stored in the caller context so it is not present in this
|
||||
* structure.
|
||||
*/
|
||||
struct port_intctx {
|
||||
regppc_t cr; /* Part of it is not volatile... */
|
||||
regppc_t r14;
|
||||
regppc_t r15;
|
||||
regppc_t r16;
|
||||
regppc_t r17;
|
||||
regppc_t r18;
|
||||
regppc_t r19;
|
||||
regppc_t r20;
|
||||
regppc_t r21;
|
||||
regppc_t r22;
|
||||
regppc_t r23;
|
||||
regppc_t r24;
|
||||
regppc_t r25;
|
||||
regppc_t r26;
|
||||
regppc_t r27;
|
||||
regppc_t r28;
|
||||
regppc_t r29;
|
||||
regppc_t r30;
|
||||
regppc_t r31;
|
||||
regppc_t padding;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p thread_t structure.
|
||||
* @details This structure usually contains just the saved stack pointer
|
||||
* defined as a pointer to a @p port_intctx structure.
|
||||
*/
|
||||
struct context {
|
||||
struct port_intctx *sp;
|
||||
};
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p chThdCreateI() API.
|
||||
* @details This code usually setup the context switching frame represented
|
||||
* by an @p port_intctx structure.
|
||||
*/
|
||||
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
|
||||
uint8_t *sp = (uint8_t *)(workspace) + \
|
||||
(wsize) - \
|
||||
sizeof(struct port_eabi_frame); \
|
||||
((struct port_eabi_frame *)sp)->slink = 0; \
|
||||
((struct port_eabi_frame *)sp)->shole = (uint32_t)_port_thread_start; \
|
||||
(tp)->p_ctx.sp = (struct port_intctx *)(sp - sizeof(struct port_intctx)); \
|
||||
(tp)->p_ctx.sp->r31 = (regppc_t)(arg); \
|
||||
(tp)->p_ctx.sp->r30 = (regppc_t)(pf); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the thread working area global size.
|
||||
* @note There is no need to perform alignments in this macro.
|
||||
*/
|
||||
#define PORT_WA_SIZE(n) (sizeof(struct port_intctx) + \
|
||||
sizeof(struct port_extctx) + \
|
||||
((size_t)(n)) + ((size_t)(PORT_INT_REQUIRED_STACK)))
|
||||
|
||||
/**
|
||||
* @brief IRQ prologue code.
|
||||
* @details This macro must be inserted at the start of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#define PORT_IRQ_PROLOGUE()
|
||||
|
||||
/**
|
||||
* @brief IRQ epilogue code.
|
||||
* @details This macro must be inserted at the end of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#define PORT_IRQ_EPILOGUE()
|
||||
|
||||
/**
|
||||
* @brief IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_IRQ_HANDLER(id) void id(void)
|
||||
|
||||
/**
|
||||
* @brief Fast IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_FAST_IRQ_HANDLER(id) void id(void)
|
||||
|
||||
/**
|
||||
* @brief Priority level verification macro.
|
||||
*/
|
||||
#define PORT_IRQ_IS_VALID_PRIORITY(n) \
|
||||
(((n) >= 0U) && ((n) < INTC_PRIORITY_LEVELS))
|
||||
|
||||
/**
|
||||
* @brief Priority level verification macro.
|
||||
*/
|
||||
#define PORT_IRQ_IS_VALID_KERNEL_PRIORITY(n) \
|
||||
(((n) >= 0U) && ((n) < INTC_PRIORITY_LEVELS))
|
||||
|
||||
/**
|
||||
* @brief Performs a context switch between two threads.
|
||||
* @details This is the most critical code in any port, this function
|
||||
* is responsible for the context switch between 2 threads.
|
||||
* @note The implementation of this code affects <b>directly</b> the context
|
||||
* switch performance so optimize here as much as you can.
|
||||
*
|
||||
* @param[in] ntp the thread to be switched in
|
||||
* @param[in] otp the thread to be switched out
|
||||
*/
|
||||
#if !CH_DBG_ENABLE_STACK_CHECK || defined(__DOXYGEN__)
|
||||
#define port_switch(ntp, otp) _port_switch(ntp, otp)
|
||||
#else
|
||||
#define port_switch(ntp, otp) { \
|
||||
register struct port_intctx *sp asm ("%r1"); \
|
||||
if ((stkalign_t *)(sp - 1) < otp->p_stklimit) \
|
||||
chSysHalt("stack overflow"); \
|
||||
_port_switch(ntp, otp); \
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Writes to a special register.
|
||||
*
|
||||
* @param[in] spr special register number
|
||||
* @param[in] val value to be written, must be an automatic variable
|
||||
*/
|
||||
#define port_write_spr(spr, val) \
|
||||
asm volatile ("mtspr %[p0], %[p1]" : : [p0] "n" (spr), [p1] "r" (val))
|
||||
|
||||
/**
|
||||
* @brief Writes to a special register.
|
||||
*
|
||||
* @param[in] spr special register number
|
||||
* @param[in] val returned value, must be an automatic variable
|
||||
*/
|
||||
#define port_read_spr(spr, val) \
|
||||
asm volatile ("mfspr %[p0], %[p1]" : [p0] "=r" (val) : [p1] "n" (spr))
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void _port_switch(thread_t *ntp, thread_t *otp);
|
||||
void _port_thread_start(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
/**
|
||||
* @brief Kernel port layer initialization.
|
||||
* @details IVOR4 and IVOR10 initialization.
|
||||
*/
|
||||
static inline void port_init(void) {
|
||||
uint32_t n;
|
||||
unsigned i;
|
||||
|
||||
/* Initializing the SPRG0 register to zero, it is required for interrupts
|
||||
handling.*/
|
||||
n = 0;
|
||||
port_write_spr(272, n);
|
||||
|
||||
#if PPC_SUPPORTS_IVORS
|
||||
{
|
||||
/* The CPU supports IVOR registers, the kernel requires IVOR4 and IVOR10
|
||||
and the initialization is performed here.*/
|
||||
extern void _IVOR4(void);
|
||||
port_write_spr(404, _IVOR4);
|
||||
|
||||
#if PPC_SUPPORTS_DECREMENTER
|
||||
extern void _IVOR10(void);
|
||||
port_write_spr(410, _IVOR10);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* INTC initialization, software vector mode, 4 bytes vectors, starting
|
||||
at priority 0.*/
|
||||
INTC_BCR = 0;
|
||||
for (i = 0; i < PPC_CORE_NUMBER; i++) {
|
||||
INTC_CPR(i) = 0;
|
||||
INTC_IACKR(i) = (uint32_t)_vectors;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a word encoding the current interrupts status.
|
||||
*
|
||||
* @return The interrupts status.
|
||||
*/
|
||||
static inline syssts_t port_get_irq_status(void) {
|
||||
uint32_t sts;
|
||||
|
||||
asm volatile ("mfmsr %[p0]" : [p0] "=r" (sts) :);
|
||||
return sts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the interrupt status.
|
||||
*
|
||||
* @param[in] sts the interrupt status word
|
||||
*
|
||||
* @return The interrupt status.
|
||||
* @retvel false the word specified a disabled interrupts status.
|
||||
* @retvel true the word specified an enabled interrupts status.
|
||||
*/
|
||||
static inline bool port_irq_enabled(syssts_t sts) {
|
||||
|
||||
return (bool)((sts & (1 << 15)) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines the current execution context.
|
||||
*
|
||||
* @return The execution context.
|
||||
* @retval false not running in ISR mode.
|
||||
* @retval true running in ISR mode.
|
||||
*/
|
||||
static inline bool port_is_isr_context(void) {
|
||||
uint32_t sprg0;
|
||||
|
||||
/* The SPRG0 register is increased before entering interrupt handlers and
|
||||
decreased at the end.*/
|
||||
port_read_spr(272, sprg0);
|
||||
return (bool)(sprg0 > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action.
|
||||
* @note Implemented as global interrupt disable.
|
||||
*/
|
||||
static inline void port_lock(void) {
|
||||
|
||||
asm volatile ("wrteei 0" : : : "memory");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action.
|
||||
* @note Implemented as global interrupt enable.
|
||||
*/
|
||||
static inline void port_unlock(void) {
|
||||
|
||||
asm volatile("wrteei 1" : : : "memory");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action from an interrupt handler.
|
||||
* @note Implementation not needed.
|
||||
*/
|
||||
static inline void port_lock_from_isr(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action from an interrupt handler.
|
||||
* @note Implementation not needed.
|
||||
*/
|
||||
static inline void port_unlock_from_isr(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables all the interrupt sources.
|
||||
* @note Implemented as global interrupt disable.
|
||||
*/
|
||||
static inline void port_disable(void) {
|
||||
|
||||
asm volatile ("wrteei 0" : : : "memory");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables the interrupt sources below kernel-level priority.
|
||||
* @note Same as @p port_disable() in this port, there is no difference
|
||||
* between the two states.
|
||||
*/
|
||||
static inline void port_suspend(void) {
|
||||
|
||||
asm volatile ("wrteei 0" : : : "memory");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables all the interrupt sources.
|
||||
* @note Implemented as global interrupt enable.
|
||||
*/
|
||||
static inline void port_enable(void) {
|
||||
|
||||
asm volatile ("wrteei 1" : : : "memory");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enters an architecture-dependent IRQ-waiting mode.
|
||||
* @details The function is meant to return when an interrupt becomes pending.
|
||||
* The simplest implementation is an empty function or macro but this
|
||||
* would not take advantage of architecture-specific power saving
|
||||
* modes.
|
||||
* @note Implemented as an inlined @p wait instruction.
|
||||
*/
|
||||
static inline void port_wait_for_interrupt(void) {
|
||||
|
||||
#if PPC_ENABLE_WFI_IDLE
|
||||
asm volatile ("wait" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current value of the realtime counter.
|
||||
*
|
||||
* @return The realtime counter value.
|
||||
*/
|
||||
static inline rtcnt_t port_rt_get_counter_value(void) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module late inclusions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
#if CH_CFG_ST_TIMEDELTA > 0
|
||||
#if !PORT_USE_ALT_TIMER
|
||||
#include "chcore_timer.h"
|
||||
#else /* PORT_USE_ALT_TIMER */
|
||||
#include "chcore_timer_alt.h"
|
||||
#endif /* PORT_USE_ALT_TIMER */
|
||||
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
#endif /* _CHCORE_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file e200/compilers/GCC/chcoreasm.s
|
||||
* @brief Power Architecture port low level code.
|
||||
*
|
||||
* @addtogroup PPC_GCC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Code section. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*
|
||||
* Imports the PPC configuration headers.
|
||||
*/
|
||||
#define _FROM_ASM_
|
||||
#include "chconf.h"
|
||||
#include "chcore.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
.extern chThdExit
|
||||
|
||||
#if PPC_USE_VLE == TRUE
|
||||
.section .text_vle, 16
|
||||
|
||||
.align 2
|
||||
.globl _port_switch
|
||||
.type _port_switch, @function
|
||||
_port_switch:
|
||||
e_subi r1, r1, 80
|
||||
se_mflr r0
|
||||
e_stw r0, 84(r1)
|
||||
mfcr r0
|
||||
se_stw r0, 0(r1)
|
||||
e_stmw r14, 4(r1)
|
||||
|
||||
se_stw r1, 12(r4)
|
||||
se_lwz r1, 12(r3)
|
||||
|
||||
e_lmw r14, 4(r1)
|
||||
se_lwz r0, 0(r1)
|
||||
mtcr r0
|
||||
e_lwz r0, 84(r1)
|
||||
se_mtlr r0
|
||||
e_addi r1, r1, 80
|
||||
se_blr
|
||||
|
||||
.align 2
|
||||
.globl _port_thread_start
|
||||
.type _port_thread_start, @function
|
||||
_port_thread_start:
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
wrteei 1
|
||||
mr r3, r31
|
||||
mtctr r30
|
||||
se_bctrl
|
||||
se_li r0, 0
|
||||
e_bl chThdExit
|
||||
|
||||
#else /* PPC_USE_VLE == FALSE */
|
||||
|
||||
#error "non-VLE mode not yet implemented"
|
||||
|
||||
#endif /* PPC_USE_VLE == FALSE */
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/** @} */
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file e200/compilers/CW/chtypes.h
|
||||
* @brief Power e200 port system types.
|
||||
*
|
||||
* @addtogroup PPC_CW_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHTYPES_H_
|
||||
#define _CHTYPES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @name Common constants
|
||||
*/
|
||||
/**
|
||||
* @brief Generic 'false' boolean constant.
|
||||
*/
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generic 'true' boolean constant.
|
||||
*/
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Kernel types
|
||||
* @{
|
||||
*/
|
||||
typedef uint32_t rtcnt_t; /**< Realtime counter. */
|
||||
typedef uint64_t rttime_t; /**< Realtime accumulator. */
|
||||
typedef uint32_t syssts_t; /**< System status word. */
|
||||
typedef uint8_t tmode_t; /**< Thread flags. */
|
||||
typedef uint8_t tstate_t; /**< Thread state. */
|
||||
typedef uint8_t trefs_t; /**< Thread references counter. */
|
||||
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
|
||||
typedef uint32_t tprio_t; /**< Thread priority. */
|
||||
typedef int32_t msg_t; /**< Inter-thread message. */
|
||||
typedef int32_t eventid_t; /**< Numeric event identifier. */
|
||||
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
|
||||
typedef uint32_t eventflags_t; /**< Mask of event flags. */
|
||||
typedef int32_t cnt_t; /**< Generic signed counter. */
|
||||
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief ROM constant modifier.
|
||||
* @note It is set to use the "const" keyword in this port.
|
||||
*/
|
||||
#define ROMCONST const
|
||||
|
||||
/**
|
||||
* @brief Makes functions not inlineable.
|
||||
* @note If the compiler does not support such attribute then the
|
||||
* realtime counter precision could be degraded.
|
||||
*/
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
|
||||
/**
|
||||
* @brief Optimized thread function declaration macro.
|
||||
*/
|
||||
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
|
||||
|
||||
#endif /* _CHTYPES_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,204 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ivor.s
|
||||
* @brief Kernel ISRs.
|
||||
*
|
||||
* @addtogroup PPC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Code section. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*
|
||||
* Imports the PPC configuration headers.
|
||||
*/
|
||||
#define _FROM_ASM_
|
||||
#include "chconf.h"
|
||||
#include "chcore.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
.extern _stats_start_measure_crit_thd
|
||||
.extern _stats_stop_measure_crit_thd
|
||||
.extern _dbg_check_lock
|
||||
.extern _dbg_check_unlock
|
||||
.extern chSchIsPreemptionRequired
|
||||
.extern chSchDoReschedule
|
||||
.extern chSysTimerHandlerI
|
||||
|
||||
.section .handlers, text_vle
|
||||
|
||||
#if PPC_USE_VLE == TRUE
|
||||
|
||||
#if PPC_SUPPORTS_DECREMENTER
|
||||
/*
|
||||
* _IVOR10 handler (Book-E decrementer).
|
||||
*/
|
||||
.align 16
|
||||
.globl _IVOR10
|
||||
.type _IVOR10, @function
|
||||
_IVOR10:
|
||||
/* Saving the external context (port_extctx structure).*/
|
||||
e_stwu r1, -80(r1)
|
||||
e_stmvsrrw 8(r1) /* Saves PC, MSR. */
|
||||
e_stmvsprw 16(r1) /* Saves CR, LR, CTR, XER. */
|
||||
e_stmvgprw 32(r1) /* Saves GPR0, GPR3...GPR12. */
|
||||
|
||||
/* Increasing the SPGR0 register.*/
|
||||
mfspr r0, 272
|
||||
se_addi r0, 1
|
||||
mtspr 272, r0
|
||||
|
||||
/* Reset DIE bit in TSR register.*/
|
||||
e_lis r3, 0x0800 /* DIS bit mask. */
|
||||
mtspr 336, r3 /* TSR register. */
|
||||
|
||||
/* Restoring pre-IRQ MSR register value.*/
|
||||
mfSRR1 r0
|
||||
#if !PPC_USE_IRQ_PREEMPTION
|
||||
/* No preemption, keeping EE disabled.*/
|
||||
se_bclri r0, 16 /* EE = bit 16. */
|
||||
#endif
|
||||
mtMSR r0
|
||||
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_enter_isr
|
||||
bl _dbg_check_lock_from_isr
|
||||
#endif
|
||||
/* System tick handler invocation.*/
|
||||
e_bl chSysTimerHandlerI
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock_from_isr
|
||||
bl _dbg_check_leave_isr
|
||||
#endif
|
||||
|
||||
#if PPC_USE_IRQ_PREEMPTION
|
||||
/* Prevents preemption again.*/
|
||||
wrteei 0
|
||||
#endif
|
||||
|
||||
/* Jumps to the common IVOR epilogue code.*/
|
||||
se_b _ivor_exit
|
||||
#endif /* PPC_SUPPORTS_DECREMENTER */
|
||||
|
||||
/*
|
||||
* _IVOR4 handler (Book-E external interrupt).
|
||||
*/
|
||||
.align 16
|
||||
.globl _IVOR4
|
||||
.type _IVOR4, @function
|
||||
_IVOR4:
|
||||
/* Saving the external context (port_extctx structure).*/
|
||||
e_stwu r1, -80(r1)
|
||||
e_stmvsrrw 8(r1) /* Saves PC, MSR. */
|
||||
e_stmvsprw 16(r1) /* Saves CR, LR, CTR, XER. */
|
||||
e_stmvgprw 32(r1) /* Saves GPR0, GPR3...GPR12. */
|
||||
|
||||
/* Increasing the SPGR0 register.*/
|
||||
mfspr r0, 272
|
||||
se_addi r0, 1
|
||||
mtspr 272, r0
|
||||
|
||||
/* Software vector address from the INTC register.*/
|
||||
e_lis r3, INTC_IACKR_ADDR@h
|
||||
e_or2i r3, INTC_IACKR_ADDR@l /* IACKR register address. */
|
||||
se_lwz r3, 0(r3) /* IACKR register value. */
|
||||
se_lwz r3, 0(r3)
|
||||
mtCTR r3 /* Software handler address. */
|
||||
|
||||
/* Restoring pre-IRQ MSR register value.*/
|
||||
mfSRR1 r0
|
||||
#if !PPC_USE_IRQ_PREEMPTION
|
||||
/* No preemption, keeping EE disabled.*/
|
||||
se_bclri r0, 16 /* EE = bit 16. */
|
||||
#endif
|
||||
mtMSR r0
|
||||
|
||||
/* Exectes the software handler.*/
|
||||
se_bctrl
|
||||
|
||||
#if PPC_USE_IRQ_PREEMPTION
|
||||
/* Prevents preemption again.*/
|
||||
wrteei 0
|
||||
#endif
|
||||
|
||||
/* Informs the INTC that the interrupt has been served.*/
|
||||
mbar 0
|
||||
e_lis r3, INTC_EOIR_ADDR@h
|
||||
e_or2i r3, INTC_EOIR_ADDR@l
|
||||
se_stw r3, 0(r3) /* Writing any value should do. */
|
||||
|
||||
/* Common IVOR epilogue code, context restore.*/
|
||||
.globl _ivor_exit
|
||||
_ivor_exit:
|
||||
/* Decreasing the SPGR0 register.*/
|
||||
mfspr r0, 272
|
||||
se_subi r0, 1
|
||||
mtspr 272, r0
|
||||
|
||||
#if CH_DBG_STATISTICS
|
||||
e_bl _stats_start_measure_crit_thd
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
e_bl _dbg_check_lock
|
||||
#endif
|
||||
e_bl chSchIsPreemptionRequired
|
||||
e_cmpli cr0, r3, 0
|
||||
se_beq .noresch
|
||||
e_bl chSchDoReschedule
|
||||
.noresch:
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
e_bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
e_bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
|
||||
/* Restoring the external context.*/
|
||||
e_lmvgprw 32(r1) /* Restores GPR0, GPR3...GPR12. */
|
||||
e_lmvsprw 16(r1) /* Restores CR, LR, CTR, XER. */
|
||||
e_lmvsrrw 8(r1) /* Restores PC, MSR. */
|
||||
e_addi r1, r1, 80 /* Back to the previous frame. */
|
||||
se_rfi
|
||||
|
||||
#else /* PPC_USE_VLE == FALSE */
|
||||
|
||||
#error "non-VLE mode not yet implemented"
|
||||
|
||||
#endif /* PPC_USE_VLE == FALSE */
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/** @} */
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file e200/compilers/GCC/chcoreasm.s
|
||||
* @brief Power Architecture port low level code.
|
||||
*
|
||||
* @addtogroup PPC_GCC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Code section. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#define _FROM_ASM_
|
||||
#include "chconf.h"
|
||||
#include "chcore.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
#if PPC_USE_VLE == TRUE
|
||||
.section .text_vle, "ax"
|
||||
#else
|
||||
.section .text, "ax"
|
||||
#endif
|
||||
|
||||
.align 2
|
||||
.globl _port_switch
|
||||
.type _port_switch, @function
|
||||
_port_switch:
|
||||
subi %sp, %sp, 80
|
||||
mflr %r0
|
||||
stw %r0, 84(%sp)
|
||||
mfcr %r0
|
||||
stw %r0, 0(%sp)
|
||||
stmw %r14, 4(%sp)
|
||||
|
||||
stw %sp, 12(%r4)
|
||||
lwz %sp, 12(%r3)
|
||||
|
||||
lmw %r14, 4(%sp)
|
||||
lwz %r0, 0(%sp)
|
||||
mtcr %r0
|
||||
lwz %r0, 84(%sp)
|
||||
mtlr %r0
|
||||
addi %sp, %sp, 80
|
||||
blr
|
||||
|
||||
.align 2
|
||||
.globl _port_thread_start
|
||||
.type _port_thread_start, @function
|
||||
_port_thread_start:
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
wrteei 1
|
||||
mr %r3, %r31
|
||||
mtctr %r30
|
||||
bctrl
|
||||
li %r0, 0
|
||||
bl chThdExit
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/** @} */
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file e200/compilers/GCC/chtypes.h
|
||||
* @brief Power e200 port system types.
|
||||
*
|
||||
* @addtogroup PPC_GCC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHTYPES_H_
|
||||
#define _CHTYPES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @name Common constants
|
||||
*/
|
||||
/**
|
||||
* @brief Generic 'false' boolean constant.
|
||||
*/
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generic 'true' boolean constant.
|
||||
*/
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Kernel types
|
||||
* @{
|
||||
*/
|
||||
typedef uint32_t rtcnt_t; /**< Realtime counter. */
|
||||
typedef uint64_t rttime_t; /**< Realtime accumulator. */
|
||||
typedef uint32_t syssts_t; /**< System status word. */
|
||||
typedef uint8_t tmode_t; /**< Thread flags. */
|
||||
typedef uint8_t tstate_t; /**< Thread state. */
|
||||
typedef uint8_t trefs_t; /**< Thread references counter. */
|
||||
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
|
||||
typedef uint32_t tprio_t; /**< Thread priority. */
|
||||
typedef int32_t msg_t; /**< Inter-thread message. */
|
||||
typedef int32_t eventid_t; /**< Numeric event identifier. */
|
||||
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
|
||||
typedef uint32_t eventflags_t; /**< Mask of event flags. */
|
||||
typedef int32_t cnt_t; /**< Generic signed counter. */
|
||||
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief ROM constant modifier.
|
||||
* @note It is set to use the "const" keyword in this port.
|
||||
*/
|
||||
#define ROMCONST const
|
||||
|
||||
/**
|
||||
* @brief Makes functions not inlineable.
|
||||
* @note If the compiler does not support such attribute then the
|
||||
* realtime counter precision could be degraded.
|
||||
*/
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
|
||||
/**
|
||||
* @brief Optimized thread function declaration macro.
|
||||
*/
|
||||
#define PORT_THD_FUNCTION(tname, arg) void tname(void *arg)
|
||||
|
||||
#endif /* _CHTYPES_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,258 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ivor.s
|
||||
* @brief Kernel ISRs.
|
||||
*
|
||||
* @addtogroup PPC_CORE
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Imports the PPC configuration headers.
|
||||
*/
|
||||
#define _FROM_ASM_
|
||||
#include "chconf.h"
|
||||
#include "chcore.h"
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
|
||||
.section .handlers, "ax"
|
||||
|
||||
#if PPC_SUPPORTS_DECREMENTER
|
||||
/*
|
||||
* _IVOR10 handler (Book-E decrementer).
|
||||
*/
|
||||
.align 4
|
||||
.globl _IVOR10
|
||||
.type _IVOR10, @function
|
||||
_IVOR10:
|
||||
/* Saving the external context (port_extctx structure).*/
|
||||
stwu %sp, -80(%sp)
|
||||
#if PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI
|
||||
e_stmvsrrw 8(%sp) /* Saves PC, MSR. */
|
||||
e_stmvsprw 16(%sp) /* Saves CR, LR, CTR, XER. */
|
||||
e_stmvgprw 32(%sp) /* Saves GPR0, GPR3...GPR12. */
|
||||
#else /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
|
||||
stw %r0, 32(%sp) /* Saves GPR0. */
|
||||
mfSRR0 %r0
|
||||
stw %r0, 8(%sp) /* Saves PC. */
|
||||
mfSRR1 %r0
|
||||
stw %r0, 12(%sp) /* Saves MSR. */
|
||||
mfCR %r0
|
||||
stw %r0, 16(%sp) /* Saves CR. */
|
||||
mfLR %r0
|
||||
stw %r0, 20(%sp) /* Saves LR. */
|
||||
mfCTR %r0
|
||||
stw %r0, 24(%sp) /* Saves CTR. */
|
||||
mfXER %r0
|
||||
stw %r0, 28(%sp) /* Saves XER. */
|
||||
stw %r3, 36(%sp) /* Saves GPR3...GPR12. */
|
||||
stw %r4, 40(%sp)
|
||||
stw %r5, 44(%sp)
|
||||
stw %r6, 48(%sp)
|
||||
stw %r7, 52(%sp)
|
||||
stw %r8, 56(%sp)
|
||||
stw %r9, 60(%sp)
|
||||
stw %r10, 64(%sp)
|
||||
stw %r11, 68(%sp)
|
||||
stw %r12, 72(%sp)
|
||||
#endif /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
|
||||
|
||||
/* Increasing the SPGR0 register.*/
|
||||
mfspr %r0, 272
|
||||
eaddi %r0, %r0, 1
|
||||
mtspr 272, %r0
|
||||
|
||||
/* Reset DIE bit in TSR register.*/
|
||||
lis %r3, 0x0800 /* DIS bit mask. */
|
||||
mtspr 336, %r3 /* TSR register. */
|
||||
|
||||
/* Restoring pre-IRQ MSR register value.*/
|
||||
mfSRR1 %r0
|
||||
#if !PPC_USE_IRQ_PREEMPTION
|
||||
/* No preemption, keeping EE disabled.*/
|
||||
se_bclri %r0, 16 /* EE = bit 16. */
|
||||
#endif
|
||||
mtMSR %r0
|
||||
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_enter_isr
|
||||
bl _dbg_check_lock_from_isr
|
||||
#endif
|
||||
/* System tick handler invocation.*/
|
||||
bl chSysTimerHandlerI
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock_from_isr
|
||||
bl _dbg_check_leave_isr
|
||||
#endif
|
||||
|
||||
#if PPC_USE_IRQ_PREEMPTION
|
||||
/* Prevents preemption again.*/
|
||||
wrteei 0
|
||||
#endif
|
||||
|
||||
/* Jumps to the common IVOR epilogue code.*/
|
||||
b _ivor_exit
|
||||
#endif /* PPC_SUPPORTS_DECREMENTER */
|
||||
|
||||
/*
|
||||
* _IVOR4 handler (Book-E external interrupt).
|
||||
*/
|
||||
.align 4
|
||||
.globl _IVOR4
|
||||
.type _IVOR4, @function
|
||||
_IVOR4:
|
||||
/* Saving the external context (port_extctx structure).*/
|
||||
stwu %sp, -80(%sp)
|
||||
#if PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI
|
||||
e_stmvsrrw 8(%sp) /* Saves PC, MSR. */
|
||||
e_stmvsprw 16(%sp) /* Saves CR, LR, CTR, XER. */
|
||||
e_stmvgprw 32(%sp) /* Saves GPR0, GPR3...GPR12. */
|
||||
#else /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
|
||||
stw %r0, 32(%sp) /* Saves GPR0. */
|
||||
mfSRR0 %r0
|
||||
stw %r0, 8(%sp) /* Saves PC. */
|
||||
mfSRR1 %r0
|
||||
stw %r0, 12(%sp) /* Saves MSR. */
|
||||
mfCR %r0
|
||||
stw %r0, 16(%sp) /* Saves CR. */
|
||||
mfLR %r0
|
||||
stw %r0, 20(%sp) /* Saves LR. */
|
||||
mfCTR %r0
|
||||
stw %r0, 24(%sp) /* Saves CTR. */
|
||||
mfXER %r0
|
||||
stw %r0, 28(%sp) /* Saves XER. */
|
||||
stw %r3, 36(%sp) /* Saves GPR3...GPR12. */
|
||||
stw %r4, 40(%sp)
|
||||
stw %r5, 44(%sp)
|
||||
stw %r6, 48(%sp)
|
||||
stw %r7, 52(%sp)
|
||||
stw %r8, 56(%sp)
|
||||
stw %r9, 60(%sp)
|
||||
stw %r10, 64(%sp)
|
||||
stw %r11, 68(%sp)
|
||||
stw %r12, 72(%sp)
|
||||
#endif /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
|
||||
|
||||
/* Increasing the SPGR0 register.*/
|
||||
mfspr %r0, 272
|
||||
eaddi %r0, %r0, 1
|
||||
mtspr 272, %r0
|
||||
|
||||
/* Software vector address from the INTC register.*/
|
||||
lis %r3, INTC_IACKR_ADDR@h
|
||||
ori %r3, %r3, INTC_IACKR_ADDR@l /* IACKR register address. */
|
||||
lwz %r3, 0(%r3) /* IACKR register value. */
|
||||
lwz %r3, 0(%r3)
|
||||
mtCTR %r3 /* Software handler address. */
|
||||
|
||||
/* Restoring pre-IRQ MSR register value.*/
|
||||
mfSRR1 %r0
|
||||
#if !PPC_USE_IRQ_PREEMPTION
|
||||
/* No preemption, keeping EE disabled.*/
|
||||
se_bclri %r0, 16 /* EE = bit 16. */
|
||||
#endif
|
||||
mtMSR %r0
|
||||
|
||||
/* Exectes the software handler.*/
|
||||
bctrl
|
||||
|
||||
#if PPC_USE_IRQ_PREEMPTION
|
||||
/* Prevents preemption again.*/
|
||||
wrteei 0
|
||||
#endif
|
||||
|
||||
/* Informs the INTC that the interrupt has been served.*/
|
||||
mbar 0
|
||||
lis %r3, INTC_EOIR_ADDR@h
|
||||
ori %r3, %r3, INTC_EOIR_ADDR@l
|
||||
stw %r3, 0(%r3) /* Writing any value should do. */
|
||||
|
||||
/* Common IVOR epilogue code, context restore.*/
|
||||
.globl _ivor_exit
|
||||
_ivor_exit:
|
||||
/* Decreasing the SPGR0 register.*/
|
||||
mfspr %r0, 272
|
||||
eaddi %r0, %r0, -1
|
||||
mtspr 272, %r0
|
||||
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_start_measure_crit_thd
|
||||
#endif
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_lock
|
||||
#endif
|
||||
bl chSchIsPreemptionRequired
|
||||
cmpli cr0, %r3, 0
|
||||
beq cr0, .noresch
|
||||
bl chSchDoReschedule
|
||||
.noresch:
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK
|
||||
bl _dbg_check_unlock
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS
|
||||
bl _stats_stop_measure_crit_thd
|
||||
#endif
|
||||
|
||||
/* Restoring the external context.*/
|
||||
#if PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI
|
||||
e_lmvgprw 32(%sp) /* Restores GPR0, GPR3...GPR12. */
|
||||
e_lmvsprw 16(%sp) /* Restores CR, LR, CTR, XER. */
|
||||
e_lmvsrrw 8(%sp) /* Restores PC, MSR. */
|
||||
#else /*!(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
|
||||
lwz %r3, 36(%sp) /* Restores GPR3...GPR12. */
|
||||
lwz %r4, 40(%sp)
|
||||
lwz %r5, 44(%sp)
|
||||
lwz %r6, 48(%sp)
|
||||
lwz %r7, 52(%sp)
|
||||
lwz %r8, 56(%sp)
|
||||
lwz %r9, 60(%sp)
|
||||
lwz %r10, 64(%sp)
|
||||
lwz %r11, 68(%sp)
|
||||
lwz %r12, 72(%sp)
|
||||
lwz %r0, 8(%sp)
|
||||
mtSRR0 %r0 /* Restores PC. */
|
||||
lwz %r0, 12(%sp)
|
||||
mtSRR1 %r0 /* Restores MSR. */
|
||||
lwz %r0, 16(%sp)
|
||||
mtCR %r0 /* Restores CR. */
|
||||
lwz %r0, 20(%sp)
|
||||
mtLR %r0 /* Restores LR. */
|
||||
lwz %r0, 24(%sp)
|
||||
mtCTR %r0 /* Restores CTR. */
|
||||
lwz %r0, 28(%sp)
|
||||
mtXER %r0 /* Restores XER. */
|
||||
lwz %r0, 32(%sp) /* Restores GPR0. */
|
||||
#endif /* !(PPC_USE_VLE && PPC_SUPPORTS_VLE_MULTI) */
|
||||
addi %sp, %sp, 80 /* Back to the previous frame. */
|
||||
rfi
|
||||
|
||||
#endif /* !defined(__DOXYGEN__) */
|
||||
|
||||
/** @} */
|
|
@ -1,8 +0,0 @@
|
|||
# List of the ChibiOS/RT e200 generic port files.
|
||||
PORTSRC = $(CHIBIOS)/os/rt/ports/e200/chcore.c
|
||||
|
||||
PORTASM = $(CHIBIOS)/os/rt/ports/e200/compilers/GCC/ivor.s \
|
||||
$(CHIBIOS)/os/rt/ports/e200/compilers/GCC/chcoreasm.s
|
||||
|
||||
PORTINC = $(CHIBIOS)/os/rt/ports/e200 \
|
||||
$(CHIBIOS)/os/rt/ports/e200/compilers/GCC
|
33
os/rt/rt.mk
33
os/rt/rt.mk
|
@ -14,9 +14,6 @@ endif
|
|||
ifneq ($(findstring CH_DBG_STATISTICS TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/rt/src/chstats.c
|
||||
endif
|
||||
ifneq ($(findstring CH_CFG_USE_DYNAMIC TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/rt/src/chdynamic.c
|
||||
endif
|
||||
ifneq ($(findstring CH_CFG_USE_REGISTRY TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/rt/src/chregistry.c
|
||||
endif
|
||||
|
@ -35,42 +32,46 @@ endif
|
|||
ifneq ($(findstring CH_CFG_USE_MESSAGES TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/rt/src/chmsg.c
|
||||
endif
|
||||
ifneq ($(findstring CH_CFG_USE_MAILBOXES TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/rt/src/chmboxes.c
|
||||
endif
|
||||
ifneq ($(findstring CH_CFG_USE_QUEUES TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/rt/src/chqueues.c
|
||||
endif
|
||||
ifneq ($(findstring CH_CFG_USE_MAILBOXES TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/common/oslib/src/chmboxes.c
|
||||
endif
|
||||
ifneq ($(findstring CH_CFG_USE_MEMCORE TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/rt/src/chmemcore.c
|
||||
KERNSRC += $(CHIBIOS)/os/common/oslib/src/chmemcore.c
|
||||
endif
|
||||
ifneq ($(findstring CH_CFG_USE_HEAP TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/rt/src/chheap.c
|
||||
KERNSRC += $(CHIBIOS)/os/common/oslib/src/chheap.c
|
||||
endif
|
||||
ifneq ($(findstring CH_CFG_USE_MEMPOOLS TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/rt/src/chmempools.c
|
||||
KERNSRC += $(CHIBIOS)/os/common/oslib/src/chmempools.c
|
||||
endif
|
||||
ifneq ($(findstring CH_CFG_USE_DYNAMIC TRUE,$(CHCONF)),)
|
||||
KERNSRC += $(CHIBIOS)/os/common/oslib/src/chdynamic.c
|
||||
endif
|
||||
else
|
||||
KERNSRC = $(CHIBIOS)/os/rt/src/chsys.c \
|
||||
KERNSRC := $(CHIBIOS)/os/rt/src/chsys.c \
|
||||
$(CHIBIOS)/os/rt/src/chdebug.c \
|
||||
$(CHIBIOS)/os/rt/src/chvt.c \
|
||||
$(CHIBIOS)/os/rt/src/chschd.c \
|
||||
$(CHIBIOS)/os/rt/src/chthreads.c \
|
||||
$(CHIBIOS)/os/rt/src/chtm.c \
|
||||
$(CHIBIOS)/os/rt/src/chstats.c \
|
||||
$(CHIBIOS)/os/rt/src/chdynamic.c \
|
||||
$(CHIBIOS)/os/rt/src/chregistry.c \
|
||||
$(CHIBIOS)/os/rt/src/chsem.c \
|
||||
$(CHIBIOS)/os/rt/src/chmtx.c \
|
||||
$(CHIBIOS)/os/rt/src/chcond.c \
|
||||
$(CHIBIOS)/os/rt/src/chevents.c \
|
||||
$(CHIBIOS)/os/rt/src/chmsg.c \
|
||||
$(CHIBIOS)/os/rt/src/chmboxes.c \
|
||||
$(CHIBIOS)/os/rt/src/chqueues.c \
|
||||
$(CHIBIOS)/os/rt/src/chmemcore.c \
|
||||
$(CHIBIOS)/os/rt/src/chheap.c \
|
||||
$(CHIBIOS)/os/rt/src/chmempools.c
|
||||
$(CHIBIOS)/os/common/oslib/src/chmboxes.c \
|
||||
$(CHIBIOS)/os/common/oslib/src/chmemcore.c \
|
||||
$(CHIBIOS)/os/common/oslib/src/chheap.c \
|
||||
$(CHIBIOS)/os/common/oslib/src/chmempools.c \
|
||||
$(CHIBIOS)/os/common/oslib/src/chdynamic.c
|
||||
endif
|
||||
|
||||
# Required include directories
|
||||
KERNINC = $(CHIBIOS)/os/rt/include
|
||||
KERNINC := $(CHIBIOS)/os/rt/include \
|
||||
$(CHIBIOS)/os/common/oslib/include
|
||||
|
|
|
@ -76,7 +76,7 @@ void chCondObjectInit(condition_variable_t *cp) {
|
|||
|
||||
chDbgCheck(cp != NULL);
|
||||
|
||||
queue_init(&cp->c_queue);
|
||||
queue_init(&cp->queue);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,8 +91,8 @@ void chCondSignal(condition_variable_t *cp) {
|
|||
chDbgCheck(cp != NULL);
|
||||
|
||||
chSysLock();
|
||||
if (queue_notempty(&cp->c_queue)) {
|
||||
chSchWakeupS(queue_fifo_remove(&cp->c_queue), MSG_OK);
|
||||
if (queue_notempty(&cp->queue)) {
|
||||
chSchWakeupS(queue_fifo_remove(&cp->queue), MSG_OK);
|
||||
}
|
||||
chSysUnlock();
|
||||
}
|
||||
|
@ -113,9 +113,9 @@ void chCondSignalI(condition_variable_t *cp) {
|
|||
chDbgCheckClassI();
|
||||
chDbgCheck(cp != NULL);
|
||||
|
||||
if (queue_notempty(&cp->c_queue)) {
|
||||
thread_t *tp = queue_fifo_remove(&cp->c_queue);
|
||||
tp->p_u.rdymsg = MSG_OK;
|
||||
if (queue_notempty(&cp->queue)) {
|
||||
thread_t *tp = queue_fifo_remove(&cp->queue);
|
||||
tp->u.rdymsg = MSG_OK;
|
||||
(void) chSchReadyI(tp);
|
||||
}
|
||||
}
|
||||
|
@ -154,8 +154,8 @@ void chCondBroadcastI(condition_variable_t *cp) {
|
|||
/* Empties the condition variable queue and inserts all the threads into the
|
||||
ready list in FIFO order. The wakeup message is set to @p MSG_RESET in
|
||||
order to make a chCondBroadcast() detectable from a chCondSignal().*/
|
||||
while (queue_notempty(&cp->c_queue)) {
|
||||
chSchReadyI(queue_fifo_remove(&cp->c_queue))->p_u.rdymsg = MSG_RESET;
|
||||
while (queue_notempty(&cp->queue)) {
|
||||
chSchReadyI(queue_fifo_remove(&cp->queue))->u.rdymsg = MSG_RESET;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,7 +209,7 @@ msg_t chCondWaitS(condition_variable_t *cp) {
|
|||
|
||||
chDbgCheckClassS();
|
||||
chDbgCheck(cp != NULL);
|
||||
chDbgAssert(ctp->p_mtxlist != NULL, "not owning a mutex");
|
||||
chDbgAssert(ctp->mtxlist != NULL, "not owning a mutex");
|
||||
|
||||
/* Getting "current" mutex and releasing it.*/
|
||||
mp = chMtxGetNextMutexS();
|
||||
|
@ -217,10 +217,10 @@ msg_t chCondWaitS(condition_variable_t *cp) {
|
|||
|
||||
/* Start waiting on the condition variable, on exit the mutex is taken
|
||||
again.*/
|
||||
ctp->p_u.wtobjp = cp;
|
||||
queue_prio_insert(ctp, &cp->c_queue);
|
||||
ctp->u.wtobjp = cp;
|
||||
queue_prio_insert(ctp, &cp->queue);
|
||||
chSchGoSleepS(CH_STATE_WTCOND);
|
||||
msg = ctp->p_u.rdymsg;
|
||||
msg = ctp->u.rdymsg;
|
||||
chMtxLockS(mp);
|
||||
|
||||
return msg;
|
||||
|
@ -299,7 +299,7 @@ msg_t chCondWaitTimeoutS(condition_variable_t *cp, systime_t time) {
|
|||
|
||||
chDbgCheckClassS();
|
||||
chDbgCheck((cp != NULL) && (time != TIME_IMMEDIATE));
|
||||
chDbgAssert(currp->p_mtxlist != NULL, "not owning a mutex");
|
||||
chDbgAssert(currp->mtxlist != NULL, "not owning a mutex");
|
||||
|
||||
/* Getting "current" mutex and releasing it.*/
|
||||
mp = chMtxGetNextMutexS();
|
||||
|
@ -307,8 +307,8 @@ msg_t chCondWaitTimeoutS(condition_variable_t *cp, systime_t time) {
|
|||
|
||||
/* Start waiting on the condition variable, on exit the mutex is taken
|
||||
again.*/
|
||||
currp->p_u.wtobjp = cp;
|
||||
queue_prio_insert(currp, &cp->c_queue);
|
||||
currp->u.wtobjp = cp;
|
||||
queue_prio_insert(currp, &cp->queue);
|
||||
msg = chSchGoSleepTimeoutS(CH_STATE_WTCOND, time);
|
||||
if (msg != MSG_TIMEOUT) {
|
||||
chMtxLockS(mp);
|
||||
|
|
|
@ -101,6 +101,31 @@
|
|||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Writes a time stamp and increases the trace buffer pointer.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
NOINLINE static void trace_next(void) {
|
||||
|
||||
ch.dbg.trace_buffer.ptr->time = chVTGetSystemTimeX();
|
||||
#if PORT_SUPPORTS_RT == TRUE
|
||||
ch.dbg.trace_buffer.ptr->rtstamp = chSysGetRealtimeCounterX();
|
||||
#else
|
||||
ch.dbg.trace_buffer.ptr->rtstamp = (rtcnt_t)0;
|
||||
#endif
|
||||
|
||||
/* Trace hook, useful in order to interface debug tools.*/
|
||||
CH_CFG_TRACE_HOOK(ch.dbg.trace_buffer.ptr);
|
||||
|
||||
if (++ch.dbg.trace_buffer.ptr >=
|
||||
&ch.dbg.trace_buffer.buffer[CH_DBG_TRACE_BUFFER_SIZE]) {
|
||||
ch.dbg.trace_buffer.ptr = &ch.dbg.trace_buffer.buffer[0];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
@ -256,17 +281,24 @@ void chDbgCheckClassS(void) {
|
|||
|
||||
#endif /* CH_DBG_SYSTEM_STATE_CHECK == TRUE */
|
||||
|
||||
#if (CH_DBG_ENABLE_TRACE == TRUE) || defined(__DOXYGEN__)
|
||||
#if (CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Trace circular buffer subsystem initialization.
|
||||
* @note Internal use only.
|
||||
*/
|
||||
void _dbg_trace_init(void) {
|
||||
unsigned i;
|
||||
|
||||
ch.dbg.trace_buffer.tb_size = CH_DBG_TRACE_BUFFER_SIZE;
|
||||
ch.dbg.trace_buffer.tb_ptr = &ch.dbg.trace_buffer.tb_buffer[0];
|
||||
ch.dbg.trace_buffer.suspended = 0U;
|
||||
ch.dbg.trace_buffer.size = CH_DBG_TRACE_BUFFER_SIZE;
|
||||
ch.dbg.trace_buffer.ptr = &ch.dbg.trace_buffer.buffer[0];
|
||||
for (i = 0U; i < CH_DBG_TRACE_BUFFER_SIZE; i++) {
|
||||
ch.dbg.trace_buffer.buffer[i].type = CH_TRACE_TYPE_UNUSED;
|
||||
}
|
||||
}
|
||||
|
||||
#if ((CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_SWITCH) != 0) || \
|
||||
defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Inserts in the circular debug trace buffer a context switch record.
|
||||
*
|
||||
|
@ -274,17 +306,173 @@ void _dbg_trace_init(void) {
|
|||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_trace(thread_t *otp) {
|
||||
void _dbg_trace_switch(thread_t *otp) {
|
||||
|
||||
ch.dbg.trace_buffer.tb_ptr->se_time = chVTGetSystemTimeX();
|
||||
ch.dbg.trace_buffer.tb_ptr->se_tp = currp;
|
||||
ch.dbg.trace_buffer.tb_ptr->se_wtobjp = otp->p_u.wtobjp;
|
||||
ch.dbg.trace_buffer.tb_ptr->se_state = (uint8_t)otp->p_state;
|
||||
if (++ch.dbg.trace_buffer.tb_ptr >=
|
||||
&ch.dbg.trace_buffer.tb_buffer[CH_DBG_TRACE_BUFFER_SIZE]) {
|
||||
ch.dbg.trace_buffer.tb_ptr = &ch.dbg.trace_buffer.tb_buffer[0];
|
||||
if ((ch.dbg.trace_buffer.suspended & CH_TRACE_SUSPEND_SWITCH) == 0U) {
|
||||
ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_SWITCH;
|
||||
ch.dbg.trace_buffer.ptr->state = (uint8_t)otp->state;
|
||||
ch.dbg.trace_buffer.ptr->u.sw.ntp = currp;
|
||||
ch.dbg.trace_buffer.ptr->u.sw.wtobjp = otp->u.wtobjp;
|
||||
trace_next();
|
||||
}
|
||||
}
|
||||
#endif /* CH_DBG_ENABLE_TRACE */
|
||||
#endif /* (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_SWITCH) != 0 */
|
||||
|
||||
#if ((CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_ISR) != 0) || \
|
||||
defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Inserts in the circular debug trace buffer an ISR-enter record.
|
||||
*
|
||||
* @param[in] isr name of the isr
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_trace_isr_enter(const char *isr) {
|
||||
|
||||
if ((ch.dbg.trace_buffer.suspended & CH_TRACE_SUSPEND_ISR_ENTER) == 0U) {
|
||||
port_lock_from_isr();
|
||||
ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_ISR_ENTER;
|
||||
ch.dbg.trace_buffer.ptr->state = 0U;
|
||||
ch.dbg.trace_buffer.ptr->u.isr.name = isr;
|
||||
trace_next();
|
||||
port_unlock_from_isr();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts in the circular debug trace buffer an ISR-leave record.
|
||||
*
|
||||
* @param[in] isr name of the isr
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_trace_isr_leave(const char *isr) {
|
||||
|
||||
if ((ch.dbg.trace_buffer.suspended & CH_TRACE_SUSPEND_ISR_LEAVE) == 0U) {
|
||||
port_lock_from_isr();
|
||||
ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_ISR_LEAVE;
|
||||
ch.dbg.trace_buffer.ptr->state = 0U;
|
||||
ch.dbg.trace_buffer.ptr->u.isr.name = isr;
|
||||
trace_next();
|
||||
port_unlock_from_isr();
|
||||
}
|
||||
}
|
||||
#endif /* (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_ISR) != 0 */
|
||||
|
||||
#if ((CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_HALT) != 0) || \
|
||||
defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Inserts in the circular debug trace buffer an halt record.
|
||||
*
|
||||
* @param[in] reason the halt error string
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _dbg_trace_halt(const char *reason) {
|
||||
|
||||
if ((ch.dbg.trace_buffer.suspended & CH_TRACE_SUSPEND_HALT) == 0U) {
|
||||
ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_HALT;
|
||||
ch.dbg.trace_buffer.ptr->state = 0;
|
||||
ch.dbg.trace_buffer.ptr->u.halt.reason = reason;
|
||||
trace_next();
|
||||
}
|
||||
}
|
||||
#endif /* (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_HALT) != 0 */
|
||||
|
||||
#if ((CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_USER) != 0) || \
|
||||
defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Adds an user trace record to the trace buffer.
|
||||
*
|
||||
* @param[in] up1 user parameter 1
|
||||
* @param[in] up2 user parameter 2
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
void chDbgWriteTraceI(void *up1, void *up2) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
|
||||
if ((ch.dbg.trace_buffer.suspended & CH_TRACE_SUSPEND_SWITCH) == 0U) {
|
||||
ch.dbg.trace_buffer.ptr->type = CH_TRACE_TYPE_USER;
|
||||
ch.dbg.trace_buffer.ptr->state = 0;
|
||||
ch.dbg.trace_buffer.ptr->u.user.up1 = up1;
|
||||
ch.dbg.trace_buffer.ptr->u.user.up2 = up2;
|
||||
trace_next();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an user trace record to the trace buffer.
|
||||
*
|
||||
* @param[in] up1 user parameter 1
|
||||
* @param[in] up2 user parameter 2
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void chDbgWriteTrace(void *up1, void *up2) {
|
||||
|
||||
chSysLock();
|
||||
chDbgWriteTraceI(up1, up2);
|
||||
chSysUnlock();
|
||||
}
|
||||
#endif /* (CH_DBG_TRACE_MASK & CH_DBG_TRACE_MASK_USER) != 0 */
|
||||
|
||||
/**
|
||||
* @brief Suspends one or more trace events.
|
||||
*
|
||||
* @paramin mask mask of the trace events to be suspended
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
void chDbgSuspendTraceI(uint16_t mask) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
|
||||
ch.dbg.trace_buffer.suspended |= mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Suspends one or more trace events.
|
||||
*
|
||||
* @paramin mask mask of the trace events to be suspended
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void chDbgSuspendTrace(uint16_t mask) {
|
||||
|
||||
chSysLock();
|
||||
chDbgSuspendTraceI(mask);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resumes one or more trace events.
|
||||
*
|
||||
* @paramin mask mask of the trace events to be resumed
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
void chDbgResumeTraceI(uint16_t mask) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
|
||||
ch.dbg.trace_buffer.suspended &= ~mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resumes one or more trace events.
|
||||
*
|
||||
* @paramin mask mask of the trace events to be resumed
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void chDbgResumeTrace(uint16_t mask) {
|
||||
|
||||
chSysLock();
|
||||
chDbgResumeTraceI(mask);
|
||||
chSysUnlock();
|
||||
}
|
||||
#endif /* CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE */
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -1,238 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chdynamic.c
|
||||
* @brief Dynamic threads code.
|
||||
*
|
||||
* @addtogroup dynamic_threads
|
||||
* @details Dynamic threads related APIs and services.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
#if (CH_CFG_USE_DYNAMIC == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Adds a reference to a thread object.
|
||||
* @pre The configuration option @p CH_CFG_USE_DYNAMIC must be enabled in
|
||||
* order to use this function.
|
||||
*
|
||||
* @param[in] tp pointer to the thread
|
||||
* @return The same thread pointer passed as parameter
|
||||
* representing the new reference.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
thread_t *chThdAddRef(thread_t *tp) {
|
||||
|
||||
chSysLock();
|
||||
chDbgAssert(tp->p_refs < (trefs_t)255, "too many references");
|
||||
tp->p_refs++;
|
||||
chSysUnlock();
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases a reference to a thread object.
|
||||
* @details If the references counter reaches zero <b>and</b> the thread
|
||||
* is in the @p CH_STATE_FINAL state then the thread's memory is
|
||||
* returned to the proper allocator.
|
||||
* @pre The configuration option @p CH_CFG_USE_DYNAMIC must be enabled in
|
||||
* order to use this function.
|
||||
* @note Static threads are not affected.
|
||||
*
|
||||
* @param[in] tp pointer to the thread
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void chThdRelease(thread_t *tp) {
|
||||
trefs_t refs;
|
||||
|
||||
chSysLock();
|
||||
chDbgAssert(tp->p_refs > (trefs_t)0, "not referenced");
|
||||
tp->p_refs--;
|
||||
refs = tp->p_refs;
|
||||
chSysUnlock();
|
||||
|
||||
/* If the references counter reaches zero and the thread is in its
|
||||
terminated state then the memory can be returned to the proper
|
||||
allocator. Of course static threads are not affected.*/
|
||||
if ((refs == (trefs_t)0) && (tp->p_state == CH_STATE_FINAL)) {
|
||||
switch (tp->p_flags & CH_FLAG_MODE_MASK) {
|
||||
#if CH_CFG_USE_HEAP == TRUE
|
||||
case CH_FLAG_MODE_HEAP:
|
||||
#if CH_CFG_USE_REGISTRY == TRUE
|
||||
REG_REMOVE(tp);
|
||||
#endif
|
||||
chHeapFree(tp);
|
||||
break;
|
||||
#endif
|
||||
#if CH_CFG_USE_MEMPOOLS == TRUE
|
||||
case CH_FLAG_MODE_MPOOL:
|
||||
#if CH_CFG_USE_REGISTRY == TRUE
|
||||
REG_REMOVE(tp);
|
||||
#endif
|
||||
chPoolFree(tp->p_mpool, tp);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Nothing to do for static threads, those are removed from the
|
||||
registry on exit.*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if (CH_CFG_USE_HEAP == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Creates a new thread allocating the memory from the heap.
|
||||
* @pre The configuration options @p CH_CFG_USE_DYNAMIC and
|
||||
* @p CH_CFG_USE_HEAP must be enabled in order to use this function.
|
||||
* @note A thread can terminate by calling @p chThdExit() or by simply
|
||||
* returning from its main function.
|
||||
* @note The memory allocated for the thread is not released when the thread
|
||||
* terminates but when a @p chThdWait() is performed.
|
||||
*
|
||||
* @param[in] heapp heap from which allocate the memory or @p NULL for the
|
||||
* default heap
|
||||
* @param[in] size size of the working area to be allocated
|
||||
* @param[in] prio the priority level for the new thread
|
||||
* @param[in] pf the thread function
|
||||
* @param[in] arg an argument passed to the thread function. It can be
|
||||
* @p NULL.
|
||||
* @return The pointer to the @p thread_t structure allocated for
|
||||
* the thread into the working space area.
|
||||
* @retval NULL if the memory cannot be allocated.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
thread_t *chThdCreateFromHeap(memory_heap_t *heapp, size_t size,
|
||||
tprio_t prio, tfunc_t pf, void *arg) {
|
||||
void *wsp;
|
||||
thread_t *tp;
|
||||
|
||||
wsp = chHeapAlloc(heapp, size);
|
||||
if (wsp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if CH_DBG_FILL_THREADS == TRUE
|
||||
_thread_memfill((uint8_t *)wsp,
|
||||
(uint8_t *)wsp + sizeof(thread_t),
|
||||
CH_DBG_THREAD_FILL_VALUE);
|
||||
_thread_memfill((uint8_t *)wsp + sizeof(thread_t),
|
||||
(uint8_t *)wsp + size,
|
||||
CH_DBG_STACK_FILL_VALUE);
|
||||
#endif
|
||||
|
||||
chSysLock();
|
||||
tp = chThdCreateI(wsp, size, prio, pf, arg);
|
||||
tp->p_flags = CH_FLAG_MODE_HEAP;
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSysUnlock();
|
||||
|
||||
return tp;
|
||||
}
|
||||
#endif /* CH_CFG_USE_HEAP == TRUE */
|
||||
|
||||
#if (CH_CFG_USE_MEMPOOLS == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Creates a new thread allocating the memory from the specified
|
||||
* memory pool.
|
||||
* @pre The configuration options @p CH_CFG_USE_DYNAMIC and
|
||||
* @p CH_CFG_USE_MEMPOOLS must be enabled in order to use this
|
||||
* function.
|
||||
* @note A thread can terminate by calling @p chThdExit() or by simply
|
||||
* returning from its main function.
|
||||
* @note The memory allocated for the thread is not released when the thread
|
||||
* terminates but when a @p chThdWait() is performed.
|
||||
*
|
||||
* @param[in] mp pointer to the memory pool object
|
||||
* @param[in] prio the priority level for the new thread
|
||||
* @param[in] pf the thread function
|
||||
* @param[in] arg an argument passed to the thread function. It can be
|
||||
* @p NULL.
|
||||
* @return The pointer to the @p thread_t structure allocated for
|
||||
* the thread into the working space area.
|
||||
* @retval NULL if the memory pool is empty.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
thread_t *chThdCreateFromMemoryPool(memory_pool_t *mp, tprio_t prio,
|
||||
tfunc_t pf, void *arg) {
|
||||
void *wsp;
|
||||
thread_t *tp;
|
||||
|
||||
chDbgCheck(mp != NULL);
|
||||
|
||||
wsp = chPoolAlloc(mp);
|
||||
if (wsp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if CH_DBG_FILL_THREADS == TRUE
|
||||
_thread_memfill((uint8_t *)wsp,
|
||||
(uint8_t *)wsp + sizeof(thread_t),
|
||||
CH_DBG_THREAD_FILL_VALUE);
|
||||
_thread_memfill((uint8_t *)wsp + sizeof(thread_t),
|
||||
(uint8_t *)wsp + mp->mp_object_size,
|
||||
CH_DBG_STACK_FILL_VALUE);
|
||||
#endif
|
||||
|
||||
chSysLock();
|
||||
tp = chThdCreateI(wsp, mp->mp_object_size, prio, pf, arg);
|
||||
tp->p_flags = CH_FLAG_MODE_MPOOL;
|
||||
tp->p_mpool = mp;
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSysUnlock();
|
||||
|
||||
return tp;
|
||||
}
|
||||
#endif /* CH_CFG_USE_MEMPOOLS == TRUE */
|
||||
|
||||
#endif /* CH_CFG_USE_DYNAMIC == TRUE */
|
||||
|
||||
/** @} */
|
|
@ -108,12 +108,12 @@ void chEvtRegisterMaskWithFlags(event_source_t *esp,
|
|||
chDbgCheck((esp != NULL) && (elp != NULL));
|
||||
|
||||
chSysLock();
|
||||
elp->el_next = esp->es_next;
|
||||
esp->es_next = elp;
|
||||
elp->el_listener = currp;
|
||||
elp->el_events = events;
|
||||
elp->el_flags = (eventflags_t)0;
|
||||
elp->el_wflags = wflags;
|
||||
elp->next = esp->next;
|
||||
esp->next = elp;
|
||||
elp->listener = currp;
|
||||
elp->events = events;
|
||||
elp->flags = (eventflags_t)0;
|
||||
elp->wflags = wflags;
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
|
@ -140,13 +140,13 @@ void chEvtUnregister(event_source_t *esp, event_listener_t *elp) {
|
|||
/*lint -restore*/
|
||||
chSysLock();
|
||||
/*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/
|
||||
while (p->el_next != (event_listener_t *)esp) {
|
||||
while (p->next != (event_listener_t *)esp) {
|
||||
/*lint -restore*/
|
||||
if (p->el_next == elp) {
|
||||
p->el_next = elp->el_next;
|
||||
if (p->next == elp) {
|
||||
p->next = elp->next;
|
||||
break;
|
||||
}
|
||||
p = p->el_next;
|
||||
p = p->next;
|
||||
}
|
||||
chSysUnlock();
|
||||
}
|
||||
|
@ -163,8 +163,8 @@ eventmask_t chEvtGetAndClearEvents(eventmask_t events) {
|
|||
eventmask_t m;
|
||||
|
||||
chSysLock();
|
||||
m = currp->p_epending & events;
|
||||
currp->p_epending &= ~events;
|
||||
m = currp->epending & events;
|
||||
currp->epending &= ~events;
|
||||
chSysUnlock();
|
||||
|
||||
return m;
|
||||
|
@ -182,8 +182,8 @@ eventmask_t chEvtGetAndClearEvents(eventmask_t events) {
|
|||
eventmask_t chEvtAddEvents(eventmask_t events) {
|
||||
|
||||
chSysLock();
|
||||
currp->p_epending |= events;
|
||||
events = currp->p_epending;
|
||||
currp->epending |= events;
|
||||
events = currp->epending;
|
||||
chSysUnlock();
|
||||
|
||||
return events;
|
||||
|
@ -212,18 +212,18 @@ void chEvtBroadcastFlagsI(event_source_t *esp, eventflags_t flags) {
|
|||
chDbgCheckClassI();
|
||||
chDbgCheck(esp != NULL);
|
||||
|
||||
elp = esp->es_next;
|
||||
elp = esp->next;
|
||||
/*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/
|
||||
while (elp != (event_listener_t *)esp) {
|
||||
/*lint -restore*/
|
||||
elp->el_flags |= flags;
|
||||
elp->flags |= flags;
|
||||
/* When flags == 0 the thread will always be signaled because the
|
||||
source does not emit any flag.*/
|
||||
if ((flags == (eventflags_t)0) ||
|
||||
((elp->el_flags & elp->el_wflags) != (eventflags_t)0)) {
|
||||
chEvtSignalI(elp->el_listener, elp->el_events);
|
||||
((elp->flags & elp->wflags) != (eventflags_t)0)) {
|
||||
chEvtSignalI(elp->listener, elp->events);
|
||||
}
|
||||
elp = elp->el_next;
|
||||
elp = elp->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,8 +242,8 @@ eventflags_t chEvtGetAndClearFlags(event_listener_t *elp) {
|
|||
eventflags_t flags;
|
||||
|
||||
chSysLock();
|
||||
flags = elp->el_flags;
|
||||
elp->el_flags = (eventflags_t)0;
|
||||
flags = elp->flags;
|
||||
elp->flags = (eventflags_t)0;
|
||||
chSysUnlock();
|
||||
|
||||
return flags;
|
||||
|
@ -284,13 +284,13 @@ void chEvtSignalI(thread_t *tp, eventmask_t events) {
|
|||
chDbgCheckClassI();
|
||||
chDbgCheck(tp != NULL);
|
||||
|
||||
tp->p_epending |= events;
|
||||
tp->epending |= events;
|
||||
/* Test on the AND/OR conditions wait states.*/
|
||||
if (((tp->p_state == CH_STATE_WTOREVT) &&
|
||||
((tp->p_epending & tp->p_u.ewmask) != (eventmask_t)0)) ||
|
||||
((tp->p_state == CH_STATE_WTANDEVT) &&
|
||||
((tp->p_epending & tp->p_u.ewmask) == tp->p_u.ewmask))) {
|
||||
tp->p_u.rdymsg = MSG_OK;
|
||||
if (((tp->state == CH_STATE_WTOREVT) &&
|
||||
((tp->epending & tp->u.ewmask) != (eventmask_t)0)) ||
|
||||
((tp->state == CH_STATE_WTANDEVT) &&
|
||||
((tp->epending & tp->u.ewmask) == tp->u.ewmask))) {
|
||||
tp->u.rdymsg = MSG_OK;
|
||||
(void) chSchReadyI(tp);
|
||||
}
|
||||
}
|
||||
|
@ -330,8 +330,8 @@ void chEvtBroadcastFlags(event_source_t *esp, eventflags_t flags) {
|
|||
eventflags_t chEvtGetAndClearFlagsI(event_listener_t *elp) {
|
||||
eventflags_t flags;
|
||||
|
||||
flags = elp->el_flags;
|
||||
elp->el_flags = (eventflags_t)0;
|
||||
flags = elp->flags;
|
||||
elp->flags = (eventflags_t)0;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
@ -385,14 +385,14 @@ eventmask_t chEvtWaitOne(eventmask_t events) {
|
|||
eventmask_t m;
|
||||
|
||||
chSysLock();
|
||||
m = ctp->p_epending & events;
|
||||
m = ctp->epending & events;
|
||||
if (m == (eventmask_t)0) {
|
||||
ctp->p_u.ewmask = events;
|
||||
ctp->u.ewmask = events;
|
||||
chSchGoSleepS(CH_STATE_WTOREVT);
|
||||
m = ctp->p_epending & events;
|
||||
m = ctp->epending & events;
|
||||
}
|
||||
m ^= m & (m - (eventmask_t)1);
|
||||
ctp->p_epending &= ~m;
|
||||
ctp->epending &= ~m;
|
||||
chSysUnlock();
|
||||
|
||||
return m;
|
||||
|
@ -415,13 +415,13 @@ eventmask_t chEvtWaitAny(eventmask_t events) {
|
|||
eventmask_t m;
|
||||
|
||||
chSysLock();
|
||||
m = ctp->p_epending & events;
|
||||
m = ctp->epending & events;
|
||||
if (m == (eventmask_t)0) {
|
||||
ctp->p_u.ewmask = events;
|
||||
ctp->u.ewmask = events;
|
||||
chSchGoSleepS(CH_STATE_WTOREVT);
|
||||
m = ctp->p_epending & events;
|
||||
m = ctp->epending & events;
|
||||
}
|
||||
ctp->p_epending &= ~m;
|
||||
ctp->epending &= ~m;
|
||||
chSysUnlock();
|
||||
|
||||
return m;
|
||||
|
@ -442,11 +442,11 @@ eventmask_t chEvtWaitAll(eventmask_t events) {
|
|||
thread_t *ctp = currp;
|
||||
|
||||
chSysLock();
|
||||
if ((ctp->p_epending & events) != events) {
|
||||
ctp->p_u.ewmask = events;
|
||||
if ((ctp->epending & events) != events) {
|
||||
ctp->u.ewmask = events;
|
||||
chSchGoSleepS(CH_STATE_WTANDEVT);
|
||||
}
|
||||
ctp->p_epending &= ~events;
|
||||
ctp->epending &= ~events;
|
||||
chSysUnlock();
|
||||
|
||||
return events;
|
||||
|
@ -481,21 +481,21 @@ eventmask_t chEvtWaitOneTimeout(eventmask_t events, systime_t time) {
|
|||
eventmask_t m;
|
||||
|
||||
chSysLock();
|
||||
m = ctp->p_epending & events;
|
||||
m = ctp->epending & events;
|
||||
if (m == (eventmask_t)0) {
|
||||
if (TIME_IMMEDIATE == time) {
|
||||
chSysUnlock();
|
||||
return (eventmask_t)0;
|
||||
}
|
||||
ctp->p_u.ewmask = events;
|
||||
ctp->u.ewmask = events;
|
||||
if (chSchGoSleepTimeoutS(CH_STATE_WTOREVT, time) < MSG_OK) {
|
||||
chSysUnlock();
|
||||
return (eventmask_t)0;
|
||||
}
|
||||
m = ctp->p_epending & events;
|
||||
m = ctp->epending & events;
|
||||
}
|
||||
m ^= m & (m - (eventmask_t)1);
|
||||
ctp->p_epending &= ~m;
|
||||
ctp->epending &= ~m;
|
||||
chSysUnlock();
|
||||
|
||||
return m;
|
||||
|
@ -524,20 +524,20 @@ eventmask_t chEvtWaitAnyTimeout(eventmask_t events, systime_t time) {
|
|||
eventmask_t m;
|
||||
|
||||
chSysLock();
|
||||
m = ctp->p_epending & events;
|
||||
m = ctp->epending & events;
|
||||
if (m == (eventmask_t)0) {
|
||||
if (TIME_IMMEDIATE == time) {
|
||||
chSysUnlock();
|
||||
return (eventmask_t)0;
|
||||
}
|
||||
ctp->p_u.ewmask = events;
|
||||
ctp->u.ewmask = events;
|
||||
if (chSchGoSleepTimeoutS(CH_STATE_WTOREVT, time) < MSG_OK) {
|
||||
chSysUnlock();
|
||||
return (eventmask_t)0;
|
||||
}
|
||||
m = ctp->p_epending & events;
|
||||
m = ctp->epending & events;
|
||||
}
|
||||
ctp->p_epending &= ~m;
|
||||
ctp->epending &= ~m;
|
||||
chSysUnlock();
|
||||
|
||||
return m;
|
||||
|
@ -564,18 +564,18 @@ eventmask_t chEvtWaitAllTimeout(eventmask_t events, systime_t time) {
|
|||
thread_t *ctp = currp;
|
||||
|
||||
chSysLock();
|
||||
if ((ctp->p_epending & events) != events) {
|
||||
if ((ctp->epending & events) != events) {
|
||||
if (TIME_IMMEDIATE == time) {
|
||||
chSysUnlock();
|
||||
return (eventmask_t)0;
|
||||
}
|
||||
ctp->p_u.ewmask = events;
|
||||
ctp->u.ewmask = events;
|
||||
if (chSchGoSleepTimeoutS(CH_STATE_WTANDEVT, time) < MSG_OK) {
|
||||
chSysUnlock();
|
||||
return (eventmask_t)0;
|
||||
}
|
||||
}
|
||||
ctp->p_epending &= ~events;
|
||||
ctp->epending &= ~events;
|
||||
chSysUnlock();
|
||||
|
||||
return events;
|
||||
|
|
|
@ -1,294 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chheap.c
|
||||
* @brief Heaps code.
|
||||
*
|
||||
* @addtogroup heaps
|
||||
* @details Heap Allocator related APIs.
|
||||
* <h2>Operation mode</h2>
|
||||
* The heap allocator implements a first-fit strategy and its APIs
|
||||
* are functionally equivalent to the usual @p malloc() and @p free()
|
||||
* library functions. The main difference is that the OS heap APIs
|
||||
* are guaranteed to be thread safe.<br>
|
||||
* @pre In order to use the heap APIs the @p CH_CFG_USE_HEAP option must
|
||||
* be enabled in @p chconf.h.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
#if (CH_CFG_USE_HEAP == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*
|
||||
* Defaults on the best synchronization mechanism available.
|
||||
*/
|
||||
#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
|
||||
#define H_LOCK(h) chMtxLock(&(h)->h_mtx)
|
||||
#define H_UNLOCK(h) chMtxUnlock(&(h)->h_mtx)
|
||||
#else
|
||||
#define H_LOCK(h) (void) chSemWait(&(h)->h_sem)
|
||||
#define H_UNLOCK(h) chSemSignal(&(h)->h_sem)
|
||||
#endif
|
||||
|
||||
#define LIMIT(p) \
|
||||
/*lint -save -e9087 [11.3] Safe cast.*/ \
|
||||
(union heap_header *)((uint8_t *)(p) + \
|
||||
sizeof(union heap_header) + (p)->h.size) \
|
||||
/*lint -restore*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Default heap descriptor.
|
||||
*/
|
||||
static memory_heap_t default_heap;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initializes the default heap.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _heap_init(void) {
|
||||
|
||||
default_heap.h_provider = chCoreAlloc;
|
||||
default_heap.h_free.h.u.next = NULL;
|
||||
default_heap.h_free.h.size = 0;
|
||||
#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
|
||||
chMtxObjectInit(&default_heap.h_mtx);
|
||||
#else
|
||||
chSemObjectInit(&default_heap.h_sem, (cnt_t)1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes a memory heap from a static memory area.
|
||||
* @pre Both the heap buffer base and the heap size must be aligned to
|
||||
* the @p stkalign_t type size.
|
||||
*
|
||||
* @param[out] heapp pointer to the memory heap descriptor to be initialized
|
||||
* @param[in] buf heap buffer base
|
||||
* @param[in] size heap size
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void chHeapObjectInit(memory_heap_t *heapp, void *buf, size_t size) {
|
||||
union heap_header *hp = buf;
|
||||
|
||||
chDbgCheck(MEM_IS_ALIGNED(buf) && MEM_IS_ALIGNED(size));
|
||||
|
||||
heapp->h_provider = NULL;
|
||||
heapp->h_free.h.u.next = hp;
|
||||
heapp->h_free.h.size = 0;
|
||||
hp->h.u.next = NULL;
|
||||
hp->h.size = size - sizeof(union heap_header);
|
||||
#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
|
||||
chMtxObjectInit(&heapp->h_mtx);
|
||||
#else
|
||||
chSemObjectInit(&heapp->h_sem, (cnt_t)1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocates a block of memory from the heap by using the first-fit
|
||||
* algorithm.
|
||||
* @details The allocated block is guaranteed to be properly aligned for a
|
||||
* pointer data type (@p stkalign_t).
|
||||
*
|
||||
* @param[in] heapp pointer to a heap descriptor or @p NULL in order to
|
||||
* access the default heap.
|
||||
* @param[in] size the size of the block to be allocated. Note that the
|
||||
* allocated block may be a bit bigger than the requested
|
||||
* size for alignment and fragmentation reasons.
|
||||
* @return A pointer to the allocated block.
|
||||
* @retval NULL if the block cannot be allocated.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void *chHeapAlloc(memory_heap_t *heapp, size_t size) {
|
||||
union heap_header *qp, *hp, *fp;
|
||||
|
||||
if (heapp == NULL) {
|
||||
heapp = &default_heap;
|
||||
}
|
||||
|
||||
size = MEM_ALIGN_NEXT(size);
|
||||
qp = &heapp->h_free;
|
||||
|
||||
H_LOCK(heapp);
|
||||
while (qp->h.u.next != NULL) {
|
||||
hp = qp->h.u.next;
|
||||
if (hp->h.size >= size) {
|
||||
if (hp->h.size < (size + sizeof(union heap_header))) {
|
||||
/* Gets the whole block even if it is slightly bigger than the
|
||||
requested size because the fragment would be too small to be
|
||||
useful.*/
|
||||
qp->h.u.next = hp->h.u.next;
|
||||
}
|
||||
else {
|
||||
/* Block bigger enough, must split it.*/
|
||||
/*lint -save -e9087 [11.3] Safe cast.*/
|
||||
fp = (void *)((uint8_t *)(hp) + sizeof(union heap_header) + size);
|
||||
/*lint -restore*/
|
||||
fp->h.u.next = hp->h.u.next;
|
||||
fp->h.size = (hp->h.size - sizeof(union heap_header)) - size;
|
||||
qp->h.u.next = fp;
|
||||
hp->h.size = size;
|
||||
}
|
||||
hp->h.u.heap = heapp;
|
||||
H_UNLOCK(heapp);
|
||||
|
||||
/*lint -save -e9087 [11.3] Safe cast.*/
|
||||
return (void *)(hp + 1);
|
||||
/*lint -restore*/
|
||||
}
|
||||
qp = hp;
|
||||
}
|
||||
H_UNLOCK(heapp);
|
||||
|
||||
/* More memory is required, tries to get it from the associated provider
|
||||
else fails.*/
|
||||
if (heapp->h_provider != NULL) {
|
||||
hp = heapp->h_provider(size + sizeof(union heap_header));
|
||||
if (hp != NULL) {
|
||||
hp->h.u.heap = heapp;
|
||||
hp->h.size = size;
|
||||
hp++;
|
||||
|
||||
/*lint -save -e9087 [11.3] Safe cast.*/
|
||||
return (void *)hp;
|
||||
/*lint -restore*/
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Frees a previously allocated memory block.
|
||||
*
|
||||
* @param[in] p pointer to the memory block to be freed
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void chHeapFree(void *p) {
|
||||
union heap_header *qp, *hp;
|
||||
memory_heap_t *heapp;
|
||||
|
||||
chDbgCheck(p != NULL);
|
||||
|
||||
/*lint -save -e9087 [11.3] Safe cast.*/
|
||||
hp = (union heap_header *)p - 1;
|
||||
/*lint -restore*/
|
||||
heapp = hp->h.u.heap;
|
||||
qp = &heapp->h_free;
|
||||
|
||||
H_LOCK(heapp);
|
||||
while (true) {
|
||||
chDbgAssert((hp < qp) || (hp >= LIMIT(qp)), "within free block");
|
||||
|
||||
if (((qp == &heapp->h_free) || (hp > qp)) &&
|
||||
((qp->h.u.next == NULL) || (hp < qp->h.u.next))) {
|
||||
/* Insertion after qp.*/
|
||||
hp->h.u.next = qp->h.u.next;
|
||||
qp->h.u.next = hp;
|
||||
/* Verifies if the newly inserted block should be merged.*/
|
||||
if (LIMIT(hp) == hp->h.u.next) {
|
||||
/* Merge with the next block.*/
|
||||
hp->h.size += hp->h.u.next->h.size + sizeof(union heap_header);
|
||||
hp->h.u.next = hp->h.u.next->h.u.next;
|
||||
}
|
||||
if ((LIMIT(qp) == hp)) {
|
||||
/* Merge with the previous block.*/
|
||||
qp->h.size += hp->h.size + sizeof(union heap_header);
|
||||
qp->h.u.next = hp->h.u.next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
qp = qp->h.u.next;
|
||||
}
|
||||
H_UNLOCK(heapp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reports the heap status.
|
||||
* @note This function is meant to be used in the test suite, it should
|
||||
* not be really useful for the application code.
|
||||
*
|
||||
* @param[in] heapp pointer to a heap descriptor or @p NULL in order to
|
||||
* access the default heap.
|
||||
* @param[in] sizep pointer to a variable that will receive the total
|
||||
* fragmented free space
|
||||
* @return The number of fragments in the heap.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
size_t chHeapStatus(memory_heap_t *heapp, size_t *sizep) {
|
||||
union heap_header *qp;
|
||||
size_t n, sz;
|
||||
|
||||
if (heapp == NULL) {
|
||||
heapp = &default_heap;
|
||||
}
|
||||
|
||||
H_LOCK(heapp);
|
||||
sz = 0;
|
||||
n = 0;
|
||||
qp = &heapp->h_free;
|
||||
while (qp->h.u.next != NULL) {
|
||||
sz += qp->h.u.next->h.size;
|
||||
n++;
|
||||
qp = qp->h.u.next;
|
||||
}
|
||||
if (sizep != NULL) {
|
||||
*sizep = sz;
|
||||
}
|
||||
H_UNLOCK(heapp);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif /* CH_CFG_USE_HEAP == TRUE */
|
||||
|
||||
/** @} */
|
|
@ -1,434 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chmboxes.c
|
||||
* @brief Mailboxes code.
|
||||
*
|
||||
* @addtogroup mailboxes
|
||||
* @details Asynchronous messages.
|
||||
* <h2>Operation mode</h2>
|
||||
* A mailbox is an asynchronous communication mechanism.<br>
|
||||
* Operations defined for mailboxes:
|
||||
* - <b>Post</b>: Posts a message on the mailbox in FIFO order.
|
||||
* - <b>Post Ahead</b>: Posts a message on the mailbox with urgent
|
||||
* priority.
|
||||
* - <b>Fetch</b>: A message is fetched from the mailbox and removed
|
||||
* from the queue.
|
||||
* - <b>Reset</b>: The mailbox is emptied and all the stored messages
|
||||
* are lost.
|
||||
* .
|
||||
* A message is a variable of type msg_t that is guaranteed to have
|
||||
* the same size of and be compatible with (data) pointers (anyway an
|
||||
* explicit cast is needed).
|
||||
* If larger messages need to be exchanged then a pointer to a
|
||||
* structure can be posted in the mailbox but the posting side has
|
||||
* no predefined way to know when the message has been processed. A
|
||||
* possible approach is to allocate memory (from a memory pool for
|
||||
* example) from the posting side and free it on the fetching side.
|
||||
* Another approach is to set a "done" flag into the structure pointed
|
||||
* by the message.
|
||||
* @pre In order to use the mailboxes APIs the @p CH_CFG_USE_MAILBOXES option
|
||||
* must be enabled in @p chconf.h.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
#if (CH_CFG_USE_MAILBOXES == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initializes a @p mailbox_t object.
|
||||
*
|
||||
* @param[out] mbp the pointer to the @p mailbox_t structure to be
|
||||
* initialized
|
||||
* @param[in] buf pointer to the messages buffer as an array of @p msg_t
|
||||
* @param[in] n number of elements in the buffer array
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void chMBObjectInit(mailbox_t *mbp, msg_t *buf, cnt_t n) {
|
||||
|
||||
chDbgCheck((mbp != NULL) && (buf != NULL) && (n > (cnt_t)0));
|
||||
|
||||
mbp->mb_buffer = buf;
|
||||
mbp->mb_rdptr = buf;
|
||||
mbp->mb_wrptr = buf;
|
||||
mbp->mb_top = &buf[n];
|
||||
chSemObjectInit(&mbp->mb_emptysem, n);
|
||||
chSemObjectInit(&mbp->mb_fullsem, (cnt_t)0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets a @p mailbox_t object.
|
||||
* @details All the waiting threads are resumed with status @p MSG_RESET and
|
||||
* the queued messages are lost.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized @p mailbox_t object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void chMBReset(mailbox_t *mbp) {
|
||||
|
||||
chSysLock();
|
||||
chMBResetI(mbp);
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets a @p mailbox_t object.
|
||||
* @details All the waiting threads are resumed with status @p MSG_RESET and
|
||||
* the queued messages are lost.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized @p mailbox_t object
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void chMBResetI(mailbox_t *mbp) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck(mbp != NULL);
|
||||
|
||||
mbp->mb_wrptr = mbp->mb_buffer;
|
||||
mbp->mb_rdptr = mbp->mb_buffer;
|
||||
chSemResetI(&mbp->mb_emptysem, (cnt_t)(mbp->mb_top - mbp->mb_buffer));
|
||||
chSemResetI(&mbp->mb_fullsem, (cnt_t)0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Posts a message into a mailbox.
|
||||
* @details The invoking thread waits until a empty slot in the mailbox becomes
|
||||
* available or the specified time runs out.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized @p mailbox_t object
|
||||
* @param[in] msg the message to be posted on the mailbox
|
||||
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||
* the following special values are allowed:
|
||||
* - @a TIME_IMMEDIATE immediate timeout.
|
||||
* - @a TIME_INFINITE no timeout.
|
||||
* .
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK if a message has been correctly posted.
|
||||
* @retval MSG_RESET if the mailbox has been reset while waiting.
|
||||
* @retval MSG_TIMEOUT if the operation has timed out.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t chMBPost(mailbox_t *mbp, msg_t msg, systime_t timeout) {
|
||||
msg_t rdymsg;
|
||||
|
||||
chSysLock();
|
||||
rdymsg = chMBPostS(mbp, msg, timeout);
|
||||
chSysUnlock();
|
||||
|
||||
return rdymsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Posts a message into a mailbox.
|
||||
* @details The invoking thread waits until a empty slot in the mailbox becomes
|
||||
* available or the specified time runs out.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized @p mailbox_t object
|
||||
* @param[in] msg the message to be posted on the mailbox
|
||||
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||
* the following special values are allowed:
|
||||
* - @a TIME_IMMEDIATE immediate timeout.
|
||||
* - @a TIME_INFINITE no timeout.
|
||||
* .
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK if a message has been correctly posted.
|
||||
* @retval MSG_RESET if the mailbox has been reset while waiting.
|
||||
* @retval MSG_TIMEOUT if the operation has timed out.
|
||||
*
|
||||
* @sclass
|
||||
*/
|
||||
msg_t chMBPostS(mailbox_t *mbp, msg_t msg, systime_t timeout) {
|
||||
msg_t rdymsg;
|
||||
|
||||
chDbgCheckClassS();
|
||||
chDbgCheck(mbp != NULL);
|
||||
|
||||
rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, timeout);
|
||||
if (rdymsg == MSG_OK) {
|
||||
*mbp->mb_wrptr++ = msg;
|
||||
if (mbp->mb_wrptr >= mbp->mb_top) {
|
||||
mbp->mb_wrptr = mbp->mb_buffer;
|
||||
}
|
||||
chSemSignalI(&mbp->mb_fullsem);
|
||||
chSchRescheduleS();
|
||||
}
|
||||
|
||||
return rdymsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Posts a message into a mailbox.
|
||||
* @details This variant is non-blocking, the function returns a timeout
|
||||
* condition if the queue is full.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized @p mailbox_t object
|
||||
* @param[in] msg the message to be posted on the mailbox
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK if a message has been correctly posted.
|
||||
* @retval MSG_TIMEOUT if the mailbox is full and the message cannot be
|
||||
* posted.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
msg_t chMBPostI(mailbox_t *mbp, msg_t msg) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck(mbp != NULL);
|
||||
|
||||
if (chSemGetCounterI(&mbp->mb_emptysem) <= (cnt_t)0) {
|
||||
return MSG_TIMEOUT;
|
||||
}
|
||||
|
||||
chSemFastWaitI(&mbp->mb_emptysem);
|
||||
*mbp->mb_wrptr++ = msg;
|
||||
if (mbp->mb_wrptr >= mbp->mb_top) {
|
||||
mbp->mb_wrptr = mbp->mb_buffer;
|
||||
}
|
||||
chSemSignalI(&mbp->mb_fullsem);
|
||||
|
||||
return MSG_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Posts an high priority message into a mailbox.
|
||||
* @details The invoking thread waits until a empty slot in the mailbox becomes
|
||||
* available or the specified time runs out.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized @p mailbox_t object
|
||||
* @param[in] msg the message to be posted on the mailbox
|
||||
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||
* the following special values are allowed:
|
||||
* - @a TIME_IMMEDIATE immediate timeout.
|
||||
* - @a TIME_INFINITE no timeout.
|
||||
* .
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK if a message has been correctly posted.
|
||||
* @retval MSG_RESET if the mailbox has been reset while waiting.
|
||||
* @retval MSG_TIMEOUT if the operation has timed out.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t chMBPostAhead(mailbox_t *mbp, msg_t msg, systime_t timeout) {
|
||||
msg_t rdymsg;
|
||||
|
||||
chSysLock();
|
||||
rdymsg = chMBPostAheadS(mbp, msg, timeout);
|
||||
chSysUnlock();
|
||||
|
||||
return rdymsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Posts an high priority message into a mailbox.
|
||||
* @details The invoking thread waits until a empty slot in the mailbox becomes
|
||||
* available or the specified time runs out.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized @p mailbox_t object
|
||||
* @param[in] msg the message to be posted on the mailbox
|
||||
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||
* the following special values are allowed:
|
||||
* - @a TIME_IMMEDIATE immediate timeout.
|
||||
* - @a TIME_INFINITE no timeout.
|
||||
* .
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK if a message has been correctly posted.
|
||||
* @retval MSG_RESET if the mailbox has been reset while waiting.
|
||||
* @retval MSG_TIMEOUT if the operation has timed out.
|
||||
*
|
||||
* @sclass
|
||||
*/
|
||||
msg_t chMBPostAheadS(mailbox_t *mbp, msg_t msg, systime_t timeout) {
|
||||
msg_t rdymsg;
|
||||
|
||||
chDbgCheckClassS();
|
||||
chDbgCheck(mbp != NULL);
|
||||
|
||||
rdymsg = chSemWaitTimeoutS(&mbp->mb_emptysem, timeout);
|
||||
if (rdymsg == MSG_OK) {
|
||||
if (--mbp->mb_rdptr < mbp->mb_buffer) {
|
||||
mbp->mb_rdptr = mbp->mb_top - 1;
|
||||
}
|
||||
*mbp->mb_rdptr = msg;
|
||||
chSemSignalI(&mbp->mb_fullsem);
|
||||
chSchRescheduleS();
|
||||
}
|
||||
|
||||
return rdymsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Posts an high priority message into a mailbox.
|
||||
* @details This variant is non-blocking, the function returns a timeout
|
||||
* condition if the queue is full.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized @p mailbox_t object
|
||||
* @param[in] msg the message to be posted on the mailbox
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK if a message has been correctly posted.
|
||||
* @retval MSG_TIMEOUT if the mailbox is full and the message cannot be
|
||||
* posted.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
msg_t chMBPostAheadI(mailbox_t *mbp, msg_t msg) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck(mbp != NULL);
|
||||
|
||||
if (chSemGetCounterI(&mbp->mb_emptysem) <= (cnt_t)0) {
|
||||
return MSG_TIMEOUT;
|
||||
}
|
||||
chSemFastWaitI(&mbp->mb_emptysem);
|
||||
if (--mbp->mb_rdptr < mbp->mb_buffer) {
|
||||
mbp->mb_rdptr = mbp->mb_top - 1;
|
||||
}
|
||||
*mbp->mb_rdptr = msg;
|
||||
chSemSignalI(&mbp->mb_fullsem);
|
||||
|
||||
return MSG_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves a message from a mailbox.
|
||||
* @details The invoking thread waits until a message is posted in the mailbox
|
||||
* or the specified time runs out.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized @p mailbox_t object
|
||||
* @param[out] msgp pointer to a message variable for the received message
|
||||
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||
* the following special values are allowed:
|
||||
* - @a TIME_IMMEDIATE immediate timeout.
|
||||
* - @a TIME_INFINITE no timeout.
|
||||
* .
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK if a message has been correctly fetched.
|
||||
* @retval MSG_RESET if the mailbox has been reset while waiting.
|
||||
* @retval MSG_TIMEOUT if the operation has timed out.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
msg_t chMBFetch(mailbox_t *mbp, msg_t *msgp, systime_t timeout) {
|
||||
msg_t rdymsg;
|
||||
|
||||
chSysLock();
|
||||
rdymsg = chMBFetchS(mbp, msgp, timeout);
|
||||
chSysUnlock();
|
||||
|
||||
return rdymsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves a message from a mailbox.
|
||||
* @details The invoking thread waits until a message is posted in the mailbox
|
||||
* or the specified time runs out.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized @p mailbox_t object
|
||||
* @param[out] msgp pointer to a message variable for the received message
|
||||
* @param[in] timeout the number of ticks before the operation timeouts,
|
||||
* the following special values are allowed:
|
||||
* - @a TIME_IMMEDIATE immediate timeout.
|
||||
* - @a TIME_INFINITE no timeout.
|
||||
* .
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK if a message has been correctly fetched.
|
||||
* @retval MSG_RESET if the mailbox has been reset while waiting.
|
||||
* @retval MSG_TIMEOUT if the operation has timed out.
|
||||
*
|
||||
* @sclass
|
||||
*/
|
||||
msg_t chMBFetchS(mailbox_t *mbp, msg_t *msgp, systime_t timeout) {
|
||||
msg_t rdymsg;
|
||||
|
||||
chDbgCheckClassS();
|
||||
chDbgCheck((mbp != NULL) && (msgp != NULL));
|
||||
|
||||
rdymsg = chSemWaitTimeoutS(&mbp->mb_fullsem, timeout);
|
||||
if (rdymsg == MSG_OK) {
|
||||
*msgp = *mbp->mb_rdptr++;
|
||||
if (mbp->mb_rdptr >= mbp->mb_top) {
|
||||
mbp->mb_rdptr = mbp->mb_buffer;
|
||||
}
|
||||
chSemSignalI(&mbp->mb_emptysem);
|
||||
chSchRescheduleS();
|
||||
}
|
||||
|
||||
return rdymsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves a message from a mailbox.
|
||||
* @details This variant is non-blocking, the function returns a timeout
|
||||
* condition if the queue is empty.
|
||||
*
|
||||
* @param[in] mbp the pointer to an initialized @p mailbox_t object
|
||||
* @param[out] msgp pointer to a message variable for the received message
|
||||
* @return The operation status.
|
||||
* @retval MSG_OK if a message has been correctly fetched.
|
||||
* @retval MSG_TIMEOUT if the mailbox is empty and a message cannot be
|
||||
* fetched.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
msg_t chMBFetchI(mailbox_t *mbp, msg_t *msgp) {
|
||||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck((mbp != NULL) && (msgp != NULL));
|
||||
|
||||
if (chSemGetCounterI(&mbp->mb_fullsem) <= (cnt_t)0) {
|
||||
return MSG_TIMEOUT;
|
||||
}
|
||||
chSemFastWaitI(&mbp->mb_fullsem);
|
||||
*msgp = *mbp->mb_rdptr++;
|
||||
if (mbp->mb_rdptr >= mbp->mb_top) {
|
||||
mbp->mb_rdptr = mbp->mb_buffer;
|
||||
}
|
||||
chSemSignalI(&mbp->mb_emptysem);
|
||||
|
||||
return MSG_OK;
|
||||
}
|
||||
#endif /* CH_CFG_USE_MAILBOXES == TRUE */
|
||||
|
||||
/** @} */
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chmemcore.c
|
||||
* @brief Core memory manager code.
|
||||
*
|
||||
* @addtogroup memcore
|
||||
* @details Core Memory Manager related APIs and services.
|
||||
* <h2>Operation mode</h2>
|
||||
* The core memory manager is a simplified allocator that only
|
||||
* allows to allocate memory blocks without the possibility to
|
||||
* free them.<br>
|
||||
* This allocator is meant as a memory blocks provider for the
|
||||
* other allocators such as:
|
||||
* - C-Runtime allocator (through a compiler specific adapter module).
|
||||
* - Heap allocator (see @ref heaps).
|
||||
* - Memory pools allocator (see @ref pools).
|
||||
* .
|
||||
* By having a centralized memory provider the various allocators
|
||||
* can coexist and share the main memory.<br>
|
||||
* This allocator, alone, is also useful for very simple
|
||||
* applications that just require a simple way to get memory
|
||||
* blocks.
|
||||
* @pre In order to use the core memory manager APIs the @p CH_CFG_USE_MEMCORE
|
||||
* option must be enabled in @p chconf.h.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
#if (CH_CFG_USE_MEMCORE == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
static uint8_t *nextmem;
|
||||
static uint8_t *endmem;
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level memory manager initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _core_init(void) {
|
||||
#if CH_CFG_MEMCORE_SIZE == 0
|
||||
extern uint8_t __heap_base__[];
|
||||
extern uint8_t __heap_end__[];
|
||||
|
||||
/*lint -save -e9033 [10.8] Required cast operations.*/
|
||||
nextmem = (uint8_t *)MEM_ALIGN_NEXT(__heap_base__);
|
||||
endmem = (uint8_t *)MEM_ALIGN_PREV(__heap_end__);
|
||||
/*lint restore*/
|
||||
#else
|
||||
static stkalign_t buffer[MEM_ALIGN_NEXT(CH_CFG_MEMCORE_SIZE) /
|
||||
MEM_ALIGN_SIZE];
|
||||
|
||||
nextmem = (uint8_t *)&buffer[0];
|
||||
endmem = (uint8_t *)&buffer[MEM_ALIGN_NEXT(CH_CFG_MEMCORE_SIZE) /
|
||||
MEM_ALIGN_SIZE];
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocates a memory block.
|
||||
* @details The size of the returned block is aligned to the alignment
|
||||
* type so it is not possible to allocate less
|
||||
* than <code>MEM_ALIGN_SIZE</code>.
|
||||
*
|
||||
* @param[in] size the size of the block to be allocated
|
||||
* @return A pointer to the allocated memory block.
|
||||
* @retval NULL allocation failed, core memory exhausted.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void *chCoreAlloc(size_t size) {
|
||||
void *p;
|
||||
|
||||
chSysLock();
|
||||
p = chCoreAllocI(size);
|
||||
chSysUnlock();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocates a memory block.
|
||||
* @details The size of the returned block is aligned to the alignment
|
||||
* type so it is not possible to allocate less than
|
||||
* <code>MEM_ALIGN_SIZE</code>.
|
||||
*
|
||||
* @param[in] size the size of the block to be allocated.
|
||||
* @return A pointer to the allocated memory block.
|
||||
* @retval NULL allocation failed, core memory exhausted.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
void *chCoreAllocI(size_t size) {
|
||||
void *p;
|
||||
|
||||
chDbgCheckClassI();
|
||||
|
||||
size = MEM_ALIGN_NEXT(size);
|
||||
/*lint -save -e9033 [10.8] The cast is safe.*/
|
||||
if ((size_t)(endmem - nextmem) < size) {
|
||||
/*lint -restore*/
|
||||
return NULL;
|
||||
}
|
||||
p = nextmem;
|
||||
nextmem += size;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Core memory status.
|
||||
*
|
||||
* @return The size, in bytes, of the free core memory.
|
||||
*
|
||||
* @xclass
|
||||
*/
|
||||
size_t chCoreGetStatusX(void) {
|
||||
|
||||
/*lint -save -e9033 [10.8] The cast is safe.*/
|
||||
return (size_t)(endmem - nextmem);
|
||||
/*lint -restore*/
|
||||
}
|
||||
#endif /* CH_CFG_USE_MEMCORE == TRUE */
|
||||
|
||||
/** @} */
|
|
@ -1,202 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file chmempools.c
|
||||
* @brief Memory Pools code.
|
||||
*
|
||||
* @addtogroup pools
|
||||
* @details Memory Pools related APIs and services.
|
||||
* <h2>Operation mode</h2>
|
||||
* The Memory Pools APIs allow to allocate/free fixed size objects in
|
||||
* <b>constant time</b> and reliably without memory fragmentation
|
||||
* problems.<br>
|
||||
* Memory Pools do not enforce any alignment constraint on the
|
||||
* contained object however the objects must be properly aligned
|
||||
* to contain a pointer to void.
|
||||
* @pre In order to use the memory pools APIs the @p CH_CFG_USE_MEMPOOLS option
|
||||
* must be enabled in @p chconf.h.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
#if (CH_CFG_USE_MEMPOOLS == TRUE) || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Initializes an empty memory pool.
|
||||
*
|
||||
* @param[out] mp pointer to a @p memory_pool_t structure
|
||||
* @param[in] size the size of the objects contained in this memory pool,
|
||||
* the minimum accepted size is the size of a pointer to
|
||||
* void.
|
||||
* @param[in] provider memory provider function for the memory pool or
|
||||
* @p NULL if the pool is not allowed to grow
|
||||
* automatically
|
||||
*
|
||||
* @init
|
||||
*/
|
||||
void chPoolObjectInit(memory_pool_t *mp, size_t size, memgetfunc_t provider) {
|
||||
|
||||
chDbgCheck((mp != NULL) && (size >= sizeof(void *)));
|
||||
|
||||
mp->mp_next = NULL;
|
||||
mp->mp_object_size = size;
|
||||
mp->mp_provider = provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Loads a memory pool with an array of static objects.
|
||||
* @pre The memory pool must be already been initialized.
|
||||
* @pre The array elements must be of the right size for the specified
|
||||
* memory pool.
|
||||
* @post The memory pool contains the elements of the input array.
|
||||
*
|
||||
* @param[in] mp pointer to a @p memory_pool_t structure
|
||||
* @param[in] p pointer to the array first element
|
||||
* @param[in] n number of elements in the array
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void chPoolLoadArray(memory_pool_t *mp, void *p, size_t n) {
|
||||
|
||||
chDbgCheck((mp != NULL) && (n != 0U));
|
||||
|
||||
while (n != 0U) {
|
||||
chPoolAdd(mp, p);
|
||||
/*lint -save -e9087 [11.3] Safe cast.*/
|
||||
p = (void *)(((uint8_t *)p) + mp->mp_object_size);
|
||||
/*lint -restore*/
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocates an object from a memory pool.
|
||||
* @pre The memory pool must be already been initialized.
|
||||
*
|
||||
* @param[in] mp pointer to a @p memory_pool_t structure
|
||||
* @return The pointer to the allocated object.
|
||||
* @retval NULL if pool is empty.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
void *chPoolAllocI(memory_pool_t *mp) {
|
||||
void *objp;
|
||||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck(mp != NULL);
|
||||
|
||||
objp = mp->mp_next;
|
||||
/*lint -save -e9013 [15.7] There is no else because it is not needed.*/
|
||||
if (objp != NULL) {
|
||||
mp->mp_next = mp->mp_next->ph_next;
|
||||
}
|
||||
else if (mp->mp_provider != NULL) {
|
||||
objp = mp->mp_provider(mp->mp_object_size);
|
||||
}
|
||||
/*lint -restore*/
|
||||
|
||||
return objp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allocates an object from a memory pool.
|
||||
* @pre The memory pool must be already been initialized.
|
||||
*
|
||||
* @param[in] mp pointer to a @p memory_pool_t structure
|
||||
* @return The pointer to the allocated object.
|
||||
* @retval NULL if pool is empty.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void *chPoolAlloc(memory_pool_t *mp) {
|
||||
void *objp;
|
||||
|
||||
chSysLock();
|
||||
objp = chPoolAllocI(mp);
|
||||
chSysUnlock();
|
||||
|
||||
return objp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases an object into a memory pool.
|
||||
* @pre The memory pool must be already been initialized.
|
||||
* @pre The freed object must be of the right size for the specified
|
||||
* memory pool.
|
||||
* @pre The object must be properly aligned to contain a pointer to void.
|
||||
*
|
||||
* @param[in] mp pointer to a @p memory_pool_t structure
|
||||
* @param[in] objp the pointer to the object to be released
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
void chPoolFreeI(memory_pool_t *mp, void *objp) {
|
||||
struct pool_header *php = objp;
|
||||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck((mp != NULL) && (objp != NULL));
|
||||
|
||||
php->ph_next = mp->mp_next;
|
||||
mp->mp_next = php;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases an object into a memory pool.
|
||||
* @pre The memory pool must be already been initialized.
|
||||
* @pre The freed object must be of the right size for the specified
|
||||
* memory pool.
|
||||
* @pre The object must be properly aligned to contain a pointer to void.
|
||||
*
|
||||
* @param[in] mp pointer to a @p memory_pool_t structure
|
||||
* @param[in] objp the pointer to the object to be released
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void chPoolFree(memory_pool_t *mp, void *objp) {
|
||||
|
||||
chSysLock();
|
||||
chPoolFreeI(mp, objp);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
#endif /* CH_CFG_USE_MEMPOOLS == TRUE */
|
||||
|
||||
/** @} */
|
|
@ -90,13 +90,13 @@ msg_t chMsgSend(thread_t *tp, msg_t msg) {
|
|||
chDbgCheck(tp != NULL);
|
||||
|
||||
chSysLock();
|
||||
ctp->p_u.sentmsg = msg;
|
||||
msg_insert(ctp, &tp->p_msgqueue);
|
||||
if (tp->p_state == CH_STATE_WTMSG) {
|
||||
ctp->u.sentmsg = msg;
|
||||
msg_insert(ctp, &tp->msgqueue);
|
||||
if (tp->state == CH_STATE_WTMSG) {
|
||||
(void) chSchReadyI(tp);
|
||||
}
|
||||
chSchGoSleepS(CH_STATE_SNDMSGQ);
|
||||
msg = ctp->p_u.rdymsg;
|
||||
msg = ctp->u.rdymsg;
|
||||
chSysUnlock();
|
||||
|
||||
return msg;
|
||||
|
@ -123,8 +123,8 @@ thread_t *chMsgWait(void) {
|
|||
if (!chMsgIsPendingI(currp)) {
|
||||
chSchGoSleepS(CH_STATE_WTMSG);
|
||||
}
|
||||
tp = queue_fifo_remove(&currp->p_msgqueue);
|
||||
tp->p_state = CH_STATE_SNDMSG;
|
||||
tp = queue_fifo_remove(&currp->msgqueue);
|
||||
tp->state = CH_STATE_SNDMSG;
|
||||
chSysUnlock();
|
||||
|
||||
return tp;
|
||||
|
@ -143,7 +143,7 @@ thread_t *chMsgWait(void) {
|
|||
void chMsgRelease(thread_t *tp, msg_t msg) {
|
||||
|
||||
chSysLock();
|
||||
chDbgAssert(tp->p_state == CH_STATE_SNDMSG, "invalid state");
|
||||
chDbgAssert(tp->state == CH_STATE_SNDMSG, "invalid state");
|
||||
chMsgReleaseS(tp, msg);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
|
|
@ -104,10 +104,10 @@ void chMtxObjectInit(mutex_t *mp) {
|
|||
|
||||
chDbgCheck(mp != NULL);
|
||||
|
||||
queue_init(&mp->m_queue);
|
||||
mp->m_owner = NULL;
|
||||
queue_init(&mp->queue);
|
||||
mp->owner = NULL;
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
mp->m_cnt = (cnt_t)0;
|
||||
mp->cnt = (cnt_t)0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -143,35 +143,35 @@ void chMtxLockS(mutex_t *mp) {
|
|||
chDbgCheck(mp != NULL);
|
||||
|
||||
/* Is the mutex already locked? */
|
||||
if (mp->m_owner != NULL) {
|
||||
if (mp->owner != NULL) {
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
|
||||
chDbgAssert(mp->m_cnt >= (cnt_t)1, "counter is not positive");
|
||||
chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");
|
||||
|
||||
/* If the mutex is already owned by this thread, the counter is increased
|
||||
and there is no need of more actions.*/
|
||||
if (mp->m_owner == ctp) {
|
||||
mp->m_cnt++;
|
||||
if (mp->owner == ctp) {
|
||||
mp->cnt++;
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
/* Priority inheritance protocol; explores the thread-mutex dependencies
|
||||
boosting the priority of all the affected threads to equal the
|
||||
priority of the running thread requesting the mutex.*/
|
||||
thread_t *tp = mp->m_owner;
|
||||
thread_t *tp = mp->owner;
|
||||
|
||||
/* Does the running thread have higher priority than the mutex
|
||||
owning thread? */
|
||||
while (tp->p_prio < ctp->p_prio) {
|
||||
while (tp->prio < ctp->prio) {
|
||||
/* Make priority of thread tp match the running thread's priority.*/
|
||||
tp->p_prio = ctp->p_prio;
|
||||
tp->prio = ctp->prio;
|
||||
|
||||
/* The following states need priority queues reordering.*/
|
||||
switch (tp->p_state) {
|
||||
switch (tp->state) {
|
||||
case CH_STATE_WTMTX:
|
||||
/* Re-enqueues the mutex owner with its new priority.*/
|
||||
queue_prio_insert(queue_dequeue(tp), &tp->p_u.wtmtxp->m_queue);
|
||||
tp = tp->p_u.wtmtxp->m_owner;
|
||||
queue_prio_insert(queue_dequeue(tp), &tp->u.wtmtxp->queue);
|
||||
tp = tp->u.wtmtxp->owner;
|
||||
/*lint -e{9042} [16.1] Continues the while.*/
|
||||
continue;
|
||||
#if (CH_CFG_USE_CONDVARS == TRUE) || \
|
||||
|
@ -190,13 +190,13 @@ void chMtxLockS(mutex_t *mp) {
|
|||
case CH_STATE_SNDMSGQ:
|
||||
#endif
|
||||
/* Re-enqueues tp with its new priority on the queue.*/
|
||||
queue_prio_insert(queue_dequeue(tp), &tp->p_u.wtmtxp->m_queue);
|
||||
queue_prio_insert(queue_dequeue(tp), &tp->u.wtmtxp->queue);
|
||||
break;
|
||||
#endif
|
||||
case CH_STATE_READY:
|
||||
#if CH_DBG_ENABLE_ASSERTS == TRUE
|
||||
/* Prevents an assertion in chSchReadyI().*/
|
||||
tp->p_state = CH_STATE_CURRENT;
|
||||
tp->state = CH_STATE_CURRENT;
|
||||
#endif
|
||||
/* Re-enqueues tp with its new priority on the ready list.*/
|
||||
(void) chSchReadyI(queue_dequeue(tp));
|
||||
|
@ -209,29 +209,29 @@ void chMtxLockS(mutex_t *mp) {
|
|||
}
|
||||
|
||||
/* Sleep on the mutex.*/
|
||||
queue_prio_insert(ctp, &mp->m_queue);
|
||||
ctp->p_u.wtmtxp = mp;
|
||||
queue_prio_insert(ctp, &mp->queue);
|
||||
ctp->u.wtmtxp = mp;
|
||||
chSchGoSleepS(CH_STATE_WTMTX);
|
||||
|
||||
/* It is assumed that the thread performing the unlock operation assigns
|
||||
the mutex to this thread.*/
|
||||
chDbgAssert(mp->m_owner == ctp, "not owner");
|
||||
chDbgAssert(ctp->p_mtxlist == mp, "not owned");
|
||||
chDbgAssert(mp->owner == ctp, "not owner");
|
||||
chDbgAssert(ctp->mtxlist == mp, "not owned");
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
chDbgAssert(mp->m_cnt == (cnt_t)1, "counter is not one");
|
||||
chDbgAssert(mp->cnt == (cnt_t)1, "counter is not one");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
chDbgAssert(mp->m_cnt == (cnt_t)0, "counter is not zero");
|
||||
chDbgAssert(mp->cnt == (cnt_t)0, "counter is not zero");
|
||||
|
||||
mp->m_cnt++;
|
||||
mp->cnt++;
|
||||
#endif
|
||||
/* It was not owned, inserted in the owned mutexes list.*/
|
||||
mp->m_owner = ctp;
|
||||
mp->m_next = ctp->p_mtxlist;
|
||||
ctp->p_mtxlist = mp;
|
||||
mp->owner = ctp;
|
||||
mp->next = ctp->mtxlist;
|
||||
ctp->mtxlist = mp;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,13 +284,13 @@ bool chMtxTryLockS(mutex_t *mp) {
|
|||
chDbgCheckClassS();
|
||||
chDbgCheck(mp != NULL);
|
||||
|
||||
if (mp->m_owner != NULL) {
|
||||
if (mp->owner != NULL) {
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
|
||||
chDbgAssert(mp->m_cnt >= (cnt_t)1, "counter is not positive");
|
||||
chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");
|
||||
|
||||
if (mp->m_owner == currp) {
|
||||
mp->m_cnt++;
|
||||
if (mp->owner == currp) {
|
||||
mp->cnt++;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
@ -298,13 +298,13 @@ bool chMtxTryLockS(mutex_t *mp) {
|
|||
}
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
|
||||
chDbgAssert(mp->m_cnt == (cnt_t)0, "counter is not zero");
|
||||
chDbgAssert(mp->cnt == (cnt_t)0, "counter is not zero");
|
||||
|
||||
mp->m_cnt++;
|
||||
mp->cnt++;
|
||||
#endif
|
||||
mp->m_owner = currp;
|
||||
mp->m_next = currp->p_mtxlist;
|
||||
currp->p_mtxlist = mp;
|
||||
mp->owner = currp;
|
||||
mp->next = currp->mtxlist;
|
||||
currp->mtxlist = mp;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -328,20 +328,20 @@ void chMtxUnlock(mutex_t *mp) {
|
|||
|
||||
chSysLock();
|
||||
|
||||
chDbgAssert(ctp->p_mtxlist != NULL, "owned mutexes list empty");
|
||||
chDbgAssert(ctp->p_mtxlist->m_owner == ctp, "ownership failure");
|
||||
chDbgAssert(ctp->mtxlist != NULL, "owned mutexes list empty");
|
||||
chDbgAssert(ctp->mtxlist->owner == ctp, "ownership failure");
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
chDbgAssert(mp->m_cnt >= (cnt_t)1, "counter is not positive");
|
||||
chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");
|
||||
|
||||
if (--mp->m_cnt == (cnt_t)0) {
|
||||
if (--mp->cnt == (cnt_t)0) {
|
||||
#endif
|
||||
|
||||
chDbgAssert(ctp->p_mtxlist == mp, "not next in list");
|
||||
chDbgAssert(ctp->mtxlist == mp, "not next in list");
|
||||
|
||||
/* Removes the top mutex from the thread's owned mutexes list and marks
|
||||
it as not owned. Note, it is assumed to be the same mutex passed as
|
||||
parameter of this function.*/
|
||||
ctp->p_mtxlist = mp->m_next;
|
||||
ctp->mtxlist = mp->next;
|
||||
|
||||
/* If a thread is waiting on the mutex then the fun part begins.*/
|
||||
if (chMtxQueueNotEmptyS(mp)) {
|
||||
|
@ -349,32 +349,32 @@ void chMtxUnlock(mutex_t *mp) {
|
|||
|
||||
/* Recalculates the optimal thread priority by scanning the owned
|
||||
mutexes list.*/
|
||||
tprio_t newprio = ctp->p_realprio;
|
||||
lmp = ctp->p_mtxlist;
|
||||
tprio_t newprio = ctp->realprio;
|
||||
lmp = ctp->mtxlist;
|
||||
while (lmp != NULL) {
|
||||
/* If the highest priority thread waiting in the mutexes list has a
|
||||
greater priority than the current thread base priority then the
|
||||
final priority will have at least that priority.*/
|
||||
if (chMtxQueueNotEmptyS(lmp) &&
|
||||
(lmp->m_queue.p_next->p_prio > newprio)) {
|
||||
newprio = lmp->m_queue.p_next->p_prio;
|
||||
(lmp->queue.next->prio > newprio)) {
|
||||
newprio = lmp->queue.next->prio;
|
||||
}
|
||||
lmp = lmp->m_next;
|
||||
lmp = lmp->next;
|
||||
}
|
||||
|
||||
/* Assigns to the current thread the highest priority among all the
|
||||
waiting threads.*/
|
||||
ctp->p_prio = newprio;
|
||||
ctp->prio = newprio;
|
||||
|
||||
/* Awakens the highest priority thread waiting for the unlocked mutex and
|
||||
assigns the mutex to it.*/
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
mp->m_cnt = (cnt_t)1;
|
||||
mp->cnt = (cnt_t)1;
|
||||
#endif
|
||||
tp = queue_fifo_remove(&mp->m_queue);
|
||||
mp->m_owner = tp;
|
||||
mp->m_next = tp->p_mtxlist;
|
||||
tp->p_mtxlist = mp;
|
||||
tp = queue_fifo_remove(&mp->queue);
|
||||
mp->owner = tp;
|
||||
mp->next = tp->mtxlist;
|
||||
tp->mtxlist = mp;
|
||||
|
||||
/* Note, not using chSchWakeupS() becuase that function expects the
|
||||
current thread to have the higher or equal priority than the ones
|
||||
|
@ -384,7 +384,7 @@ void chMtxUnlock(mutex_t *mp) {
|
|||
chSchRescheduleS();
|
||||
}
|
||||
else {
|
||||
mp->m_owner = NULL;
|
||||
mp->owner = NULL;
|
||||
}
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
}
|
||||
|
@ -414,20 +414,20 @@ void chMtxUnlockS(mutex_t *mp) {
|
|||
chDbgCheckClassS();
|
||||
chDbgCheck(mp != NULL);
|
||||
|
||||
chDbgAssert(ctp->p_mtxlist != NULL, "owned mutexes list empty");
|
||||
chDbgAssert(ctp->p_mtxlist->m_owner == ctp, "ownership failure");
|
||||
chDbgAssert(ctp->mtxlist != NULL, "owned mutexes list empty");
|
||||
chDbgAssert(ctp->mtxlist->owner == ctp, "ownership failure");
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
chDbgAssert(mp->m_cnt >= (cnt_t)1, "counter is not positive");
|
||||
chDbgAssert(mp->cnt >= (cnt_t)1, "counter is not positive");
|
||||
|
||||
if (--mp->m_cnt == (cnt_t)0) {
|
||||
if (--mp->cnt == (cnt_t)0) {
|
||||
#endif
|
||||
|
||||
chDbgAssert(ctp->p_mtxlist == mp, "not next in list");
|
||||
chDbgAssert(ctp->mtxlist == mp, "not next in list");
|
||||
|
||||
/* Removes the top mutex from the thread's owned mutexes list and marks
|
||||
it as not owned. Note, it is assumed to be the same mutex passed as
|
||||
parameter of this function.*/
|
||||
ctp->p_mtxlist = mp->m_next;
|
||||
ctp->mtxlist = mp->next;
|
||||
|
||||
/* If a thread is waiting on the mutex then the fun part begins.*/
|
||||
if (chMtxQueueNotEmptyS(mp)) {
|
||||
|
@ -435,36 +435,36 @@ void chMtxUnlockS(mutex_t *mp) {
|
|||
|
||||
/* Recalculates the optimal thread priority by scanning the owned
|
||||
mutexes list.*/
|
||||
tprio_t newprio = ctp->p_realprio;
|
||||
lmp = ctp->p_mtxlist;
|
||||
tprio_t newprio = ctp->realprio;
|
||||
lmp = ctp->mtxlist;
|
||||
while (lmp != NULL) {
|
||||
/* If the highest priority thread waiting in the mutexes list has a
|
||||
greater priority than the current thread base priority then the
|
||||
final priority will have at least that priority.*/
|
||||
if (chMtxQueueNotEmptyS(lmp) &&
|
||||
(lmp->m_queue.p_next->p_prio > newprio)) {
|
||||
newprio = lmp->m_queue.p_next->p_prio;
|
||||
(lmp->queue.next->prio > newprio)) {
|
||||
newprio = lmp->queue.next->prio;
|
||||
}
|
||||
lmp = lmp->m_next;
|
||||
lmp = lmp->next;
|
||||
}
|
||||
|
||||
/* Assigns to the current thread the highest priority among all the
|
||||
waiting threads.*/
|
||||
ctp->p_prio = newprio;
|
||||
ctp->prio = newprio;
|
||||
|
||||
/* Awakens the highest priority thread waiting for the unlocked mutex and
|
||||
assigns the mutex to it.*/
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
mp->m_cnt = (cnt_t)1;
|
||||
mp->cnt = (cnt_t)1;
|
||||
#endif
|
||||
tp = queue_fifo_remove(&mp->m_queue);
|
||||
mp->m_owner = tp;
|
||||
mp->m_next = tp->p_mtxlist;
|
||||
tp->p_mtxlist = mp;
|
||||
tp = queue_fifo_remove(&mp->queue);
|
||||
mp->owner = tp;
|
||||
mp->next = tp->mtxlist;
|
||||
tp->mtxlist = mp;
|
||||
(void) chSchReadyI(tp);
|
||||
}
|
||||
else {
|
||||
mp->m_owner = NULL;
|
||||
mp->owner = NULL;
|
||||
}
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
}
|
||||
|
@ -486,28 +486,28 @@ void chMtxUnlockAll(void) {
|
|||
thread_t *ctp = currp;
|
||||
|
||||
chSysLock();
|
||||
if (ctp->p_mtxlist != NULL) {
|
||||
if (ctp->mtxlist != NULL) {
|
||||
do {
|
||||
mutex_t *mp = ctp->p_mtxlist;
|
||||
ctp->p_mtxlist = mp->m_next;
|
||||
mutex_t *mp = ctp->mtxlist;
|
||||
ctp->mtxlist = mp->next;
|
||||
if (chMtxQueueNotEmptyS(mp)) {
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
mp->m_cnt = (cnt_t)1;
|
||||
mp->cnt = (cnt_t)1;
|
||||
#endif
|
||||
thread_t *tp = queue_fifo_remove(&mp->m_queue);
|
||||
mp->m_owner = tp;
|
||||
mp->m_next = tp->p_mtxlist;
|
||||
tp->p_mtxlist = mp;
|
||||
thread_t *tp = queue_fifo_remove(&mp->queue);
|
||||
mp->owner = tp;
|
||||
mp->next = tp->mtxlist;
|
||||
tp->mtxlist = mp;
|
||||
(void) chSchReadyI(tp);
|
||||
}
|
||||
else {
|
||||
#if CH_CFG_USE_MUTEXES_RECURSIVE == TRUE
|
||||
mp->m_cnt = (cnt_t)0;
|
||||
mp->cnt = (cnt_t)0;
|
||||
#endif
|
||||
mp->m_owner = NULL;
|
||||
mp->owner = NULL;
|
||||
}
|
||||
} while (ctp->p_mtxlist != NULL);
|
||||
ctp->p_prio = ctp->p_realprio;
|
||||
} while (ctp->mtxlist != NULL);
|
||||
ctp->prio = ctp->realprio;
|
||||
chSchRescheduleS();
|
||||
}
|
||||
chSysUnlock();
|
||||
|
|
|
@ -87,14 +87,14 @@
|
|||
void chIQObjectInit(input_queue_t *iqp, uint8_t *bp, size_t size,
|
||||
qnotify_t infy, void *link) {
|
||||
|
||||
chThdQueueObjectInit(&iqp->q_waiting);
|
||||
iqp->q_counter = 0;
|
||||
iqp->q_buffer = bp;
|
||||
iqp->q_rdptr = bp;
|
||||
iqp->q_wrptr = bp;
|
||||
iqp->q_top = bp + size;
|
||||
iqp->q_notify = infy;
|
||||
iqp->q_link = link;
|
||||
chThdQueueObjectInit(&iqp->waiting);
|
||||
iqp->counter = 0;
|
||||
iqp->buffer = bp;
|
||||
iqp->rdptr = bp;
|
||||
iqp->wrptr = bp;
|
||||
iqp->top = bp + size;
|
||||
iqp->notify = infy;
|
||||
iqp->link = link;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,10 +112,10 @@ void chIQResetI(input_queue_t *iqp) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
|
||||
iqp->q_rdptr = iqp->q_buffer;
|
||||
iqp->q_wrptr = iqp->q_buffer;
|
||||
iqp->q_counter = 0;
|
||||
chThdDequeueAllI(&iqp->q_waiting, Q_RESET);
|
||||
iqp->rdptr = iqp->buffer;
|
||||
iqp->wrptr = iqp->buffer;
|
||||
iqp->counter = 0;
|
||||
chThdDequeueAllI(&iqp->waiting, Q_RESET);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,13 +139,13 @@ msg_t chIQPutI(input_queue_t *iqp, uint8_t b) {
|
|||
return Q_FULL;
|
||||
}
|
||||
|
||||
iqp->q_counter++;
|
||||
*iqp->q_wrptr++ = b;
|
||||
if (iqp->q_wrptr >= iqp->q_top) {
|
||||
iqp->q_wrptr = iqp->q_buffer;
|
||||
iqp->counter++;
|
||||
*iqp->wrptr++ = b;
|
||||
if (iqp->wrptr >= iqp->top) {
|
||||
iqp->wrptr = iqp->buffer;
|
||||
}
|
||||
|
||||
chThdDequeueNextI(&iqp->q_waiting, Q_OK);
|
||||
chThdDequeueNextI(&iqp->waiting, Q_OK);
|
||||
|
||||
return Q_OK;
|
||||
}
|
||||
|
@ -174,22 +174,22 @@ msg_t chIQGetTimeout(input_queue_t *iqp, systime_t timeout) {
|
|||
uint8_t b;
|
||||
|
||||
chSysLock();
|
||||
if (iqp->q_notify != NULL) {
|
||||
iqp->q_notify(iqp);
|
||||
if (iqp->notify != NULL) {
|
||||
iqp->notify(iqp);
|
||||
}
|
||||
|
||||
while (chIQIsEmptyI(iqp)) {
|
||||
msg_t msg = chThdEnqueueTimeoutS(&iqp->q_waiting, timeout);
|
||||
msg_t msg = chThdEnqueueTimeoutS(&iqp->waiting, timeout);
|
||||
if (msg < Q_OK) {
|
||||
chSysUnlock();
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
iqp->q_counter--;
|
||||
b = *iqp->q_rdptr++;
|
||||
if (iqp->q_rdptr >= iqp->q_top) {
|
||||
iqp->q_rdptr = iqp->q_buffer;
|
||||
iqp->counter--;
|
||||
b = *iqp->rdptr++;
|
||||
if (iqp->rdptr >= iqp->top) {
|
||||
iqp->rdptr = iqp->buffer;
|
||||
}
|
||||
chSysUnlock();
|
||||
|
||||
|
@ -222,7 +222,7 @@ msg_t chIQGetTimeout(input_queue_t *iqp, systime_t timeout) {
|
|||
*/
|
||||
size_t chIQReadTimeout(input_queue_t *iqp, uint8_t *bp,
|
||||
size_t n, systime_t timeout) {
|
||||
qnotify_t nfy = iqp->q_notify;
|
||||
qnotify_t nfy = iqp->notify;
|
||||
size_t r = 0;
|
||||
|
||||
chDbgCheck(n > 0U);
|
||||
|
@ -234,16 +234,16 @@ size_t chIQReadTimeout(input_queue_t *iqp, uint8_t *bp,
|
|||
}
|
||||
|
||||
while (chIQIsEmptyI(iqp)) {
|
||||
if (chThdEnqueueTimeoutS(&iqp->q_waiting, timeout) != Q_OK) {
|
||||
if (chThdEnqueueTimeoutS(&iqp->waiting, timeout) != Q_OK) {
|
||||
chSysUnlock();
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
iqp->q_counter--;
|
||||
*bp++ = *iqp->q_rdptr++;
|
||||
if (iqp->q_rdptr >= iqp->q_top) {
|
||||
iqp->q_rdptr = iqp->q_buffer;
|
||||
iqp->counter--;
|
||||
*bp++ = *iqp->rdptr++;
|
||||
if (iqp->rdptr >= iqp->top) {
|
||||
iqp->rdptr = iqp->buffer;
|
||||
}
|
||||
chSysUnlock(); /* Gives a preemption chance in a controlled point.*/
|
||||
|
||||
|
@ -275,14 +275,14 @@ size_t chIQReadTimeout(input_queue_t *iqp, uint8_t *bp,
|
|||
void chOQObjectInit(output_queue_t *oqp, uint8_t *bp, size_t size,
|
||||
qnotify_t onfy, void *link) {
|
||||
|
||||
chThdQueueObjectInit(&oqp->q_waiting);
|
||||
oqp->q_counter = size;
|
||||
oqp->q_buffer = bp;
|
||||
oqp->q_rdptr = bp;
|
||||
oqp->q_wrptr = bp;
|
||||
oqp->q_top = bp + size;
|
||||
oqp->q_notify = onfy;
|
||||
oqp->q_link = link;
|
||||
chThdQueueObjectInit(&oqp->waiting);
|
||||
oqp->counter = size;
|
||||
oqp->buffer = bp;
|
||||
oqp->rdptr = bp;
|
||||
oqp->wrptr = bp;
|
||||
oqp->top = bp + size;
|
||||
oqp->notify = onfy;
|
||||
oqp->link = link;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -300,10 +300,10 @@ void chOQResetI(output_queue_t *oqp) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
|
||||
oqp->q_rdptr = oqp->q_buffer;
|
||||
oqp->q_wrptr = oqp->q_buffer;
|
||||
oqp->q_counter = chQSizeX(oqp);
|
||||
chThdDequeueAllI(&oqp->q_waiting, Q_RESET);
|
||||
oqp->rdptr = oqp->buffer;
|
||||
oqp->wrptr = oqp->buffer;
|
||||
oqp->counter = chQSizeX(oqp);
|
||||
chThdDequeueAllI(&oqp->waiting, Q_RESET);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -332,21 +332,21 @@ msg_t chOQPutTimeout(output_queue_t *oqp, uint8_t b, systime_t timeout) {
|
|||
|
||||
chSysLock();
|
||||
while (chOQIsFullI(oqp)) {
|
||||
msg_t msg = chThdEnqueueTimeoutS(&oqp->q_waiting, timeout);
|
||||
msg_t msg = chThdEnqueueTimeoutS(&oqp->waiting, timeout);
|
||||
if (msg < Q_OK) {
|
||||
chSysUnlock();
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
oqp->q_counter--;
|
||||
*oqp->q_wrptr++ = b;
|
||||
if (oqp->q_wrptr >= oqp->q_top) {
|
||||
oqp->q_wrptr = oqp->q_buffer;
|
||||
oqp->counter--;
|
||||
*oqp->wrptr++ = b;
|
||||
if (oqp->wrptr >= oqp->top) {
|
||||
oqp->wrptr = oqp->buffer;
|
||||
}
|
||||
|
||||
if (oqp->q_notify != NULL) {
|
||||
oqp->q_notify(oqp);
|
||||
if (oqp->notify != NULL) {
|
||||
oqp->notify(oqp);
|
||||
}
|
||||
chSysUnlock();
|
||||
|
||||
|
@ -372,13 +372,13 @@ msg_t chOQGetI(output_queue_t *oqp) {
|
|||
return Q_EMPTY;
|
||||
}
|
||||
|
||||
oqp->q_counter++;
|
||||
b = *oqp->q_rdptr++;
|
||||
if (oqp->q_rdptr >= oqp->q_top) {
|
||||
oqp->q_rdptr = oqp->q_buffer;
|
||||
oqp->counter++;
|
||||
b = *oqp->rdptr++;
|
||||
if (oqp->rdptr >= oqp->top) {
|
||||
oqp->rdptr = oqp->buffer;
|
||||
}
|
||||
|
||||
chThdDequeueNextI(&oqp->q_waiting, Q_OK);
|
||||
chThdDequeueNextI(&oqp->waiting, Q_OK);
|
||||
|
||||
return (msg_t)b;
|
||||
}
|
||||
|
@ -409,7 +409,7 @@ msg_t chOQGetI(output_queue_t *oqp) {
|
|||
*/
|
||||
size_t chOQWriteTimeout(output_queue_t *oqp, const uint8_t *bp,
|
||||
size_t n, systime_t timeout) {
|
||||
qnotify_t nfy = oqp->q_notify;
|
||||
qnotify_t nfy = oqp->notify;
|
||||
size_t w = 0;
|
||||
|
||||
chDbgCheck(n > 0U);
|
||||
|
@ -417,16 +417,16 @@ size_t chOQWriteTimeout(output_queue_t *oqp, const uint8_t *bp,
|
|||
chSysLock();
|
||||
while (true) {
|
||||
while (chOQIsFullI(oqp)) {
|
||||
if (chThdEnqueueTimeoutS(&oqp->q_waiting, timeout) != Q_OK) {
|
||||
if (chThdEnqueueTimeoutS(&oqp->waiting, timeout) != Q_OK) {
|
||||
chSysUnlock();
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
oqp->q_counter--;
|
||||
*oqp->q_wrptr++ = *bp++;
|
||||
if (oqp->q_wrptr >= oqp->q_top) {
|
||||
oqp->q_wrptr = oqp->q_buffer;
|
||||
oqp->counter--;
|
||||
*oqp->wrptr++ = *bp++;
|
||||
if (oqp->wrptr >= oqp->top) {
|
||||
oqp->wrptr = oqp->buffer;
|
||||
}
|
||||
|
||||
if (nfy != NULL) {
|
||||
|
|
|
@ -87,30 +87,26 @@ ROMCONST chdebug_t ch_debug = {
|
|||
(uint8_t)sizeof (void *),
|
||||
(uint8_t)sizeof (systime_t),
|
||||
(uint8_t)sizeof (thread_t),
|
||||
(uint8_t)_offsetof(thread_t, p_prio),
|
||||
(uint8_t)_offsetof(thread_t, p_ctx),
|
||||
(uint8_t)_offsetof(thread_t, p_newer),
|
||||
(uint8_t)_offsetof(thread_t, p_older),
|
||||
(uint8_t)_offsetof(thread_t, p_name),
|
||||
(uint8_t)_offsetof(thread_t, prio),
|
||||
(uint8_t)_offsetof(thread_t, ctx),
|
||||
(uint8_t)_offsetof(thread_t, newer),
|
||||
(uint8_t)_offsetof(thread_t, older),
|
||||
(uint8_t)_offsetof(thread_t, name),
|
||||
#if CH_DBG_ENABLE_STACK_CHECK == TRUE
|
||||
(uint8_t)_offsetof(thread_t, p_stklimit),
|
||||
#else
|
||||
(uint8_t)0,
|
||||
#endif
|
||||
(uint8_t)_offsetof(thread_t, p_state),
|
||||
(uint8_t)_offsetof(thread_t, p_flags),
|
||||
#if CH_CFG_USE_DYNAMIC == TRUE
|
||||
(uint8_t)_offsetof(thread_t, p_refs),
|
||||
(uint8_t)_offsetof(thread_t, stklimit),
|
||||
#else
|
||||
(uint8_t)0,
|
||||
#endif
|
||||
(uint8_t)_offsetof(thread_t, state),
|
||||
(uint8_t)0, /* Flags no more part of the structure. */
|
||||
(uint8_t)0, /* Refs no more part of the structure. */
|
||||
#if CH_CFG_TIME_QUANTUM > 0
|
||||
(uint8_t)_offsetof(thread_t, p_preempt),
|
||||
(uint8_t)_offsetof(thread_t, preempt),
|
||||
#else
|
||||
(uint8_t)0,
|
||||
#endif
|
||||
#if CH_DBG_THREADS_PROFILING == TRUE
|
||||
(uint8_t)_offsetof(thread_t, p_time)
|
||||
(uint8_t)_offsetof(thread_t, time)
|
||||
#else
|
||||
(uint8_t)0
|
||||
#endif
|
||||
|
@ -132,10 +128,7 @@ thread_t *chRegFirstThread(void) {
|
|||
thread_t *tp;
|
||||
|
||||
chSysLock();
|
||||
tp = ch.rlist.r_newer;
|
||||
#if CH_CFG_USE_DYNAMIC == TRUE
|
||||
tp->p_refs++;
|
||||
#endif
|
||||
tp = ch.rlist.newer;
|
||||
chSysUnlock();
|
||||
|
||||
return tp;
|
||||
|
@ -156,22 +149,13 @@ thread_t *chRegNextThread(thread_t *tp) {
|
|||
thread_t *ntp;
|
||||
|
||||
chSysLock();
|
||||
ntp = tp->p_newer;
|
||||
ntp = tp->newer;
|
||||
/*lint -save -e9087 -e740 [11.3, 1.3] Cast required by list handling.*/
|
||||
if (ntp == (thread_t *)&ch.rlist) {
|
||||
/*lint -restore*/
|
||||
ntp = NULL;
|
||||
}
|
||||
#if CH_CFG_USE_DYNAMIC == TRUE
|
||||
else {
|
||||
chDbgAssert(ntp->p_refs < (trefs_t)255, "too many references");
|
||||
ntp->p_refs++;
|
||||
}
|
||||
#endif
|
||||
chSysUnlock();
|
||||
#if CH_CFG_USE_DYNAMIC == TRUE
|
||||
chThdRelease(tp);
|
||||
#endif
|
||||
|
||||
return ntp;
|
||||
}
|
||||
|
|
|
@ -64,11 +64,11 @@ ch_system_t ch;
|
|||
*/
|
||||
void _scheduler_init(void) {
|
||||
|
||||
queue_init(&ch.rlist.r_queue);
|
||||
ch.rlist.r_prio = NOPRIO;
|
||||
queue_init(&ch.rlist.queue);
|
||||
ch.rlist.prio = NOPRIO;
|
||||
#if CH_CFG_USE_REGISTRY == TRUE
|
||||
ch.rlist.r_newer = (thread_t *)&ch.rlist;
|
||||
ch.rlist.r_older = (thread_t *)&ch.rlist;
|
||||
ch.rlist.newer = (thread_t *)&ch.rlist;
|
||||
ch.rlist.older = (thread_t *)&ch.rlist;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -87,12 +87,12 @@ void queue_prio_insert(thread_t *tp, threads_queue_t *tqp) {
|
|||
|
||||
thread_t *cp = (thread_t *)tqp;
|
||||
do {
|
||||
cp = cp->p_next;
|
||||
} while ((cp != (thread_t *)tqp) && (cp->p_prio >= tp->p_prio));
|
||||
tp->p_next = cp;
|
||||
tp->p_prev = cp->p_prev;
|
||||
tp->p_prev->p_next = tp;
|
||||
cp->p_prev = tp;
|
||||
cp = cp->next;
|
||||
} while ((cp != (thread_t *)tqp) && (cp->prio >= tp->prio));
|
||||
tp->next = cp;
|
||||
tp->prev = cp->prev;
|
||||
tp->prev->next = tp;
|
||||
cp->prev = tp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,10 +105,10 @@ void queue_prio_insert(thread_t *tp, threads_queue_t *tqp) {
|
|||
*/
|
||||
void queue_insert(thread_t *tp, threads_queue_t *tqp) {
|
||||
|
||||
tp->p_next = (thread_t *)tqp;
|
||||
tp->p_prev = tqp->p_prev;
|
||||
tp->p_prev->p_next = tp;
|
||||
tqp->p_prev = tp;
|
||||
tp->next = (thread_t *)tqp;
|
||||
tp->prev = tqp->prev;
|
||||
tp->prev->next = tp;
|
||||
tqp->prev = tp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,10 +122,10 @@ void queue_insert(thread_t *tp, threads_queue_t *tqp) {
|
|||
* @notapi
|
||||
*/
|
||||
thread_t *queue_fifo_remove(threads_queue_t *tqp) {
|
||||
thread_t *tp = tqp->p_next;
|
||||
thread_t *tp = tqp->next;
|
||||
|
||||
tqp->p_next = tp->p_next;
|
||||
tqp->p_next->p_prev = (thread_t *)tqp;
|
||||
tqp->next = tp->next;
|
||||
tqp->next->prev = (thread_t *)tqp;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
@ -141,10 +141,10 @@ thread_t *queue_fifo_remove(threads_queue_t *tqp) {
|
|||
* @notapi
|
||||
*/
|
||||
thread_t *queue_lifo_remove(threads_queue_t *tqp) {
|
||||
thread_t *tp = tqp->p_prev;
|
||||
thread_t *tp = tqp->prev;
|
||||
|
||||
tqp->p_prev = tp->p_prev;
|
||||
tqp->p_prev->p_next = (thread_t *)tqp;
|
||||
tqp->prev = tp->prev;
|
||||
tqp->prev->next = (thread_t *)tqp;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
@ -161,8 +161,8 @@ thread_t *queue_lifo_remove(threads_queue_t *tqp) {
|
|||
*/
|
||||
thread_t *queue_dequeue(thread_t *tp) {
|
||||
|
||||
tp->p_prev->p_next = tp->p_next;
|
||||
tp->p_next->p_prev = tp->p_prev;
|
||||
tp->prev->next = tp->next;
|
||||
tp->next->prev = tp->prev;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
@ -177,8 +177,8 @@ thread_t *queue_dequeue(thread_t *tp) {
|
|||
*/
|
||||
void list_insert(thread_t *tp, threads_list_t *tlp) {
|
||||
|
||||
tp->p_next = tlp->p_next;
|
||||
tlp->p_next = tp;
|
||||
tp->next = tlp->next;
|
||||
tlp->next = tp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -192,19 +192,19 @@ void list_insert(thread_t *tp, threads_list_t *tlp) {
|
|||
*/
|
||||
thread_t *list_remove(threads_list_t *tlp) {
|
||||
|
||||
thread_t *tp = tlp->p_next;
|
||||
tlp->p_next = tp->p_next;
|
||||
thread_t *tp = tlp->next;
|
||||
tlp->next = tp->next;
|
||||
|
||||
return tp;
|
||||
}
|
||||
#endif /* CH_CFG_OPTIMIZE_SPEED */
|
||||
|
||||
/**
|
||||
* @brief Inserts a thread in the Ready List.
|
||||
* @brief Inserts a thread in the Ready List placing it behind its peers.
|
||||
* @details The thread is positioned behind all threads with higher or equal
|
||||
* priority.
|
||||
* @pre The thread must not be already inserted in any list through its
|
||||
* @p p_next and @p p_prev or list corruption would occur.
|
||||
* @p next and @p prev or list corruption would occur.
|
||||
* @post This function does not reschedule so a call to a rescheduling
|
||||
* function must be performed before unlocking the kernel. Note that
|
||||
* interrupt handlers always reschedule on exit so an explicit
|
||||
|
@ -220,20 +220,59 @@ thread_t *chSchReadyI(thread_t *tp) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck(tp != NULL);
|
||||
chDbgAssert((tp->p_state != CH_STATE_READY) &&
|
||||
(tp->p_state != CH_STATE_FINAL),
|
||||
chDbgAssert((tp->state != CH_STATE_READY) &&
|
||||
(tp->state != CH_STATE_FINAL),
|
||||
"invalid state");
|
||||
|
||||
tp->p_state = CH_STATE_READY;
|
||||
cp = (thread_t *)&ch.rlist.r_queue;
|
||||
tp->state = CH_STATE_READY;
|
||||
cp = (thread_t *)&ch.rlist.queue;
|
||||
do {
|
||||
cp = cp->p_next;
|
||||
} while (cp->p_prio >= tp->p_prio);
|
||||
/* Insertion on p_prev.*/
|
||||
tp->p_next = cp;
|
||||
tp->p_prev = cp->p_prev;
|
||||
tp->p_prev->p_next = tp;
|
||||
cp->p_prev = tp;
|
||||
cp = cp->next;
|
||||
} while (cp->prio >= tp->prio);
|
||||
/* Insertion on prev.*/
|
||||
tp->next = cp;
|
||||
tp->prev = cp->prev;
|
||||
tp->prev->next = tp;
|
||||
cp->prev = tp;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts a thread in the Ready List placing it ahead its peers.
|
||||
* @details The thread is positioned ahead all threads with higher or equal
|
||||
* priority.
|
||||
* @pre The thread must not be already inserted in any list through its
|
||||
* @p next and @p prev or list corruption would occur.
|
||||
* @post This function does not reschedule so a call to a rescheduling
|
||||
* function must be performed before unlocking the kernel. Note that
|
||||
* interrupt handlers always reschedule on exit so an explicit
|
||||
* reschedule must not be performed in ISRs.
|
||||
*
|
||||
* @param[in] tp the thread to be made ready
|
||||
* @return The thread pointer.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
thread_t *chSchReadyAheadI(thread_t *tp) {
|
||||
thread_t *cp;
|
||||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck(tp != NULL);
|
||||
chDbgAssert((tp->state != CH_STATE_READY) &&
|
||||
(tp->state != CH_STATE_FINAL),
|
||||
"invalid state");
|
||||
|
||||
tp->state = CH_STATE_READY;
|
||||
cp = (thread_t *)&ch.rlist.queue;
|
||||
do {
|
||||
cp = cp->next;
|
||||
} while (cp->prio > tp->prio);
|
||||
/* Insertion on prev.*/
|
||||
tp->next = cp;
|
||||
tp->prev = cp->prev;
|
||||
tp->prev->next = tp;
|
||||
cp->prev = tp;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
@ -253,19 +292,21 @@ void chSchGoSleepS(tstate_t newstate) {
|
|||
chDbgCheckClassS();
|
||||
|
||||
otp = currp;
|
||||
otp->p_state = newstate;
|
||||
otp->state = newstate;
|
||||
#if CH_CFG_TIME_QUANTUM > 0
|
||||
/* The thread is renouncing its remaining time slices so it will have a new
|
||||
time quantum when it will wakeup.*/
|
||||
otp->p_preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
|
||||
otp->preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
|
||||
#endif
|
||||
setcurrp(queue_fifo_remove(&ch.rlist.r_queue));
|
||||
#if defined(CH_CFG_IDLE_ENTER_HOOK)
|
||||
if (currp->p_prio == IDLEPRIO) {
|
||||
currp = queue_fifo_remove(&ch.rlist.queue);
|
||||
if (currp->prio == IDLEPRIO) {
|
||||
CH_CFG_IDLE_ENTER_HOOK();
|
||||
}
|
||||
#endif
|
||||
currp->p_state = CH_STATE_CURRENT;
|
||||
|
||||
/* The extracted thread is marked as current.*/
|
||||
currp->state = CH_STATE_CURRENT;
|
||||
|
||||
/* Swap operation as tail call.*/
|
||||
chSysSwitch(currp, otp);
|
||||
}
|
||||
|
||||
|
@ -276,18 +317,18 @@ static void wakeup(void *p) {
|
|||
thread_t *tp = (thread_t *)p;
|
||||
|
||||
chSysLockFromISR();
|
||||
switch (tp->p_state) {
|
||||
switch (tp->state) {
|
||||
case CH_STATE_READY:
|
||||
/* Handling the special case where the thread has been made ready by
|
||||
another thread with higher priority.*/
|
||||
chSysUnlockFromISR();
|
||||
return;
|
||||
case CH_STATE_SUSPENDED:
|
||||
*tp->p_u.wttrp = NULL;
|
||||
*tp->u.wttrp = NULL;
|
||||
break;
|
||||
#if CH_CFG_USE_SEMAPHORES == TRUE
|
||||
case CH_STATE_WTSEM:
|
||||
chSemFastSignalI(tp->p_u.wtsemp);
|
||||
chSemFastSignalI(tp->u.wtsemp);
|
||||
/* Falls into, intentional. */
|
||||
#endif
|
||||
#if (CH_CFG_USE_CONDVARS == TRUE) && (CH_CFG_USE_CONDVARS_TIMEOUT == TRUE)
|
||||
|
@ -301,7 +342,7 @@ static void wakeup(void *p) {
|
|||
/* Any other state, nothing to do.*/
|
||||
break;
|
||||
}
|
||||
tp->p_u.rdymsg = MSG_TIMEOUT;
|
||||
tp->u.rdymsg = MSG_TIMEOUT;
|
||||
(void) chSchReadyI(tp);
|
||||
chSysUnlockFromISR();
|
||||
}
|
||||
|
@ -344,7 +385,7 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
|
|||
chSchGoSleepS(newstate);
|
||||
}
|
||||
|
||||
return currp->p_u.rdymsg;
|
||||
return currp->u.rdymsg;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -353,7 +394,7 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
|
|||
* running depending on its relative priority compared to the current
|
||||
* thread.
|
||||
* @pre The thread must not be already inserted in any list through its
|
||||
* @p p_next and @p p_prev or list corruption would occur.
|
||||
* @p next and @p prev or list corruption would occur.
|
||||
* @note It is equivalent to a @p chSchReadyI() followed by a
|
||||
* @p chSchRescheduleS() but much more efficient.
|
||||
* @note The function assumes that the current thread has the highest
|
||||
|
@ -368,30 +409,32 @@ void chSchWakeupS(thread_t *ntp, msg_t msg) {
|
|||
|
||||
chDbgCheckClassS();
|
||||
|
||||
chDbgAssert((ch.rlist.r_queue.p_next == (thread_t *)&ch.rlist.r_queue) ||
|
||||
(ch.rlist.r_current->p_prio >= ch.rlist.r_queue.p_next->p_prio),
|
||||
chDbgAssert((ch.rlist.queue.next == (thread_t *)&ch.rlist.queue) ||
|
||||
(ch.rlist.current->prio >= ch.rlist.queue.next->prio),
|
||||
"priority order violation");
|
||||
|
||||
/* Storing the message to be retrieved by the target thread when it will
|
||||
restart execution.*/
|
||||
ntp->p_u.rdymsg = msg;
|
||||
ntp->u.rdymsg = msg;
|
||||
|
||||
/* If the waken thread has a not-greater priority than the current
|
||||
one then it is just inserted in the ready list else it made
|
||||
running immediately and the invoking thread goes in the ready
|
||||
list instead.*/
|
||||
if (ntp->p_prio <= currp->p_prio) {
|
||||
if (ntp->prio <= currp->prio) {
|
||||
(void) chSchReadyI(ntp);
|
||||
}
|
||||
else {
|
||||
thread_t *otp = chSchReadyI(currp);
|
||||
setcurrp(ntp);
|
||||
#if defined(CH_CFG_IDLE_LEAVE_HOOK)
|
||||
if (otp->p_prio == IDLEPRIO) {
|
||||
currp = ntp;
|
||||
if (otp->prio == IDLEPRIO) {
|
||||
CH_CFG_IDLE_LEAVE_HOOK();
|
||||
}
|
||||
#endif
|
||||
ntp->p_state = CH_STATE_CURRENT;
|
||||
|
||||
/* The extracted thread is marked as current.*/
|
||||
ntp->state = CH_STATE_CURRENT;
|
||||
|
||||
/* Swap operation as tail call.*/
|
||||
chSysSwitch(ntp, otp);
|
||||
}
|
||||
}
|
||||
|
@ -426,15 +469,15 @@ void chSchRescheduleS(void) {
|
|||
* @special
|
||||
*/
|
||||
bool chSchIsPreemptionRequired(void) {
|
||||
tprio_t p1 = firstprio(&ch.rlist.r_queue);
|
||||
tprio_t p2 = currp->p_prio;
|
||||
tprio_t p1 = firstprio(&ch.rlist.queue);
|
||||
tprio_t p2 = currp->prio;
|
||||
|
||||
#if CH_CFG_TIME_QUANTUM > 0
|
||||
/* If the running thread has not reached its time quantum, reschedule only
|
||||
if the first thread on the ready queue has a higher priority.
|
||||
Otherwise, if the running thread has used up its time quantum, reschedule
|
||||
if the first thread on the ready queue has equal or higher priority.*/
|
||||
return (currp->p_preempt > (tslices_t)0) ? (p1 > p2) : (p1 >= p2);
|
||||
return (currp->preempt > (tslices_t)0) ? (p1 > p2) : (p1 >= p2);
|
||||
#else
|
||||
/* If the round robin preemption feature is not enabled then performs a
|
||||
simpler comparison.*/
|
||||
|
@ -448,26 +491,30 @@ bool chSchIsPreemptionRequired(void) {
|
|||
* threads having the same priority. The thread regains its time
|
||||
* quantum.
|
||||
* @note Not a user function, it is meant to be invoked by the scheduler
|
||||
* itself or from within the port layer.
|
||||
* itself.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
void chSchDoRescheduleBehind(void) {
|
||||
thread_t *otp;
|
||||
thread_t *otp = currp;
|
||||
|
||||
otp = currp;
|
||||
/* Picks the first thread from the ready queue and makes it current.*/
|
||||
setcurrp(queue_fifo_remove(&ch.rlist.r_queue));
|
||||
#if defined(CH_CFG_IDLE_LEAVE_HOOK)
|
||||
if (otp->p_prio == IDLEPRIO) {
|
||||
currp = queue_fifo_remove(&ch.rlist.queue);
|
||||
if (otp->prio == IDLEPRIO) {
|
||||
CH_CFG_IDLE_LEAVE_HOOK();
|
||||
}
|
||||
#endif
|
||||
currp->p_state = CH_STATE_CURRENT;
|
||||
|
||||
/* The extracted thread is marked as current.*/
|
||||
currp->state = CH_STATE_CURRENT;
|
||||
|
||||
#if CH_CFG_TIME_QUANTUM > 0
|
||||
otp->p_preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
|
||||
otp->preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
|
||||
#endif
|
||||
(void) chSchReadyI(otp);
|
||||
|
||||
/* Placing in ready list behind peers.*/
|
||||
otp = chSchReadyI(otp);
|
||||
|
||||
/* Swap operation as tail call.*/
|
||||
chSysSwitch(currp, otp);
|
||||
}
|
||||
|
||||
|
@ -476,34 +523,26 @@ void chSchDoRescheduleBehind(void) {
|
|||
* @details The current thread is positioned in the ready list ahead of all
|
||||
* threads having the same priority.
|
||||
* @note Not a user function, it is meant to be invoked by the scheduler
|
||||
* itself or from within the port layer.
|
||||
* itself.
|
||||
*
|
||||
* @special
|
||||
*/
|
||||
void chSchDoRescheduleAhead(void) {
|
||||
thread_t *otp, *cp;
|
||||
thread_t *otp = currp;
|
||||
|
||||
otp = currp;
|
||||
/* Picks the first thread from the ready queue and makes it current.*/
|
||||
setcurrp(queue_fifo_remove(&ch.rlist.r_queue));
|
||||
#if defined(CH_CFG_IDLE_LEAVE_HOOK)
|
||||
if (otp->p_prio == IDLEPRIO) {
|
||||
currp = queue_fifo_remove(&ch.rlist.queue);
|
||||
if (otp->prio == IDLEPRIO) {
|
||||
CH_CFG_IDLE_LEAVE_HOOK();
|
||||
}
|
||||
#endif
|
||||
currp->p_state = CH_STATE_CURRENT;
|
||||
|
||||
otp->p_state = CH_STATE_READY;
|
||||
cp = (thread_t *)&ch.rlist.r_queue;
|
||||
do {
|
||||
cp = cp->p_next;
|
||||
} while (cp->p_prio > otp->p_prio);
|
||||
/* Insertion on p_prev.*/
|
||||
otp->p_next = cp;
|
||||
otp->p_prev = cp->p_prev;
|
||||
otp->p_prev->p_next = otp;
|
||||
cp->p_prev = otp;
|
||||
/* The extracted thread is marked as current.*/
|
||||
currp->state = CH_STATE_CURRENT;
|
||||
|
||||
/* Placing in ready list ahead of peers.*/
|
||||
otp = chSchReadyAheadI(otp);
|
||||
|
||||
/* Swap operation as tail call.*/
|
||||
chSysSwitch(currp, otp);
|
||||
}
|
||||
|
||||
|
@ -518,25 +557,42 @@ void chSchDoRescheduleAhead(void) {
|
|||
* @special
|
||||
*/
|
||||
void chSchDoReschedule(void) {
|
||||
thread_t *otp = currp;
|
||||
|
||||
/* Picks the first thread from the ready queue and makes it current.*/
|
||||
currp = queue_fifo_remove(&ch.rlist.queue);
|
||||
if (otp->prio == IDLEPRIO) {
|
||||
CH_CFG_IDLE_LEAVE_HOOK();
|
||||
}
|
||||
|
||||
/* The extracted thread is marked as current.*/
|
||||
currp->state = CH_STATE_CURRENT;
|
||||
|
||||
#if CH_CFG_TIME_QUANTUM > 0
|
||||
/* If CH_CFG_TIME_QUANTUM is enabled then there are two different scenarios
|
||||
to handle on preemption: time quantum elapsed or not.*/
|
||||
if (currp->p_preempt == (tslices_t)0) {
|
||||
if (currp->preempt == (tslices_t)0) {
|
||||
|
||||
/* The thread consumed its time quantum so it is enqueued behind threads
|
||||
with same priority level, however, it acquires a new time quantum.*/
|
||||
chSchDoRescheduleBehind();
|
||||
otp = chSchReadyI(otp);
|
||||
|
||||
/* The thread being swapped out receives a new time quantum.*/
|
||||
otp->preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
|
||||
}
|
||||
else {
|
||||
/* The thread didn't consume all its time quantum so it is put ahead of
|
||||
threads with equal priority and does not acquire a new time quantum.*/
|
||||
chSchDoRescheduleAhead();
|
||||
otp = chSchReadyAheadI(otp);
|
||||
}
|
||||
#else /* !(CH_CFG_TIME_QUANTUM > 0) */
|
||||
/* If the round-robin mechanism is disabled then the thread goes always
|
||||
ahead of its peers.*/
|
||||
chSchDoRescheduleAhead();
|
||||
otp = chSchReadyAheadI(otp);
|
||||
#endif /* !(CH_CFG_TIME_QUANTUM > 0) */
|
||||
|
||||
/* Swap operation as tail call.*/
|
||||
chSysSwitch(currp, otp);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -98,8 +98,8 @@ void chSemObjectInit(semaphore_t *sp, cnt_t n) {
|
|||
|
||||
chDbgCheck((sp != NULL) && (n >= (cnt_t)0));
|
||||
|
||||
queue_init(&sp->s_queue);
|
||||
sp->s_cnt = n;
|
||||
queue_init(&sp->queue);
|
||||
sp->cnt = n;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,14 +149,14 @@ void chSemResetI(semaphore_t *sp, cnt_t n) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck((sp != NULL) && (n >= (cnt_t)0));
|
||||
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
|
||||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
|
||||
chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) ||
|
||||
((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)),
|
||||
"inconsistent semaphore");
|
||||
|
||||
cnt = sp->s_cnt;
|
||||
sp->s_cnt = n;
|
||||
cnt = sp->cnt;
|
||||
sp->cnt = n;
|
||||
while (++cnt <= (cnt_t)0) {
|
||||
chSchReadyI(queue_lifo_remove(&sp->s_queue))->p_u.rdymsg = MSG_RESET;
|
||||
chSchReadyI(queue_lifo_remove(&sp->queue))->u.rdymsg = MSG_RESET;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,16 +198,16 @@ msg_t chSemWaitS(semaphore_t *sp) {
|
|||
|
||||
chDbgCheckClassS();
|
||||
chDbgCheck(sp != NULL);
|
||||
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
|
||||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
|
||||
chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) ||
|
||||
((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)),
|
||||
"inconsistent semaphore");
|
||||
|
||||
if (--sp->s_cnt < (cnt_t)0) {
|
||||
currp->p_u.wtsemp = sp;
|
||||
sem_insert(currp, &sp->s_queue);
|
||||
if (--sp->cnt < (cnt_t)0) {
|
||||
currp->u.wtsemp = sp;
|
||||
sem_insert(currp, &sp->queue);
|
||||
chSchGoSleepS(CH_STATE_WTSEM);
|
||||
|
||||
return currp->p_u.rdymsg;
|
||||
return currp->u.rdymsg;
|
||||
}
|
||||
|
||||
return MSG_OK;
|
||||
|
@ -265,18 +265,18 @@ msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t time) {
|
|||
|
||||
chDbgCheckClassS();
|
||||
chDbgCheck(sp != NULL);
|
||||
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
|
||||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
|
||||
chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) ||
|
||||
((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)),
|
||||
"inconsistent semaphore");
|
||||
|
||||
if (--sp->s_cnt < (cnt_t)0) {
|
||||
if (--sp->cnt < (cnt_t)0) {
|
||||
if (TIME_IMMEDIATE == time) {
|
||||
sp->s_cnt++;
|
||||
sp->cnt++;
|
||||
|
||||
return MSG_TIMEOUT;
|
||||
}
|
||||
currp->p_u.wtsemp = sp;
|
||||
sem_insert(currp, &sp->s_queue);
|
||||
currp->u.wtsemp = sp;
|
||||
sem_insert(currp, &sp->queue);
|
||||
|
||||
return chSchGoSleepTimeoutS(CH_STATE_WTSEM, time);
|
||||
}
|
||||
|
@ -294,13 +294,13 @@ msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t time) {
|
|||
void chSemSignal(semaphore_t *sp) {
|
||||
|
||||
chDbgCheck(sp != NULL);
|
||||
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
|
||||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
|
||||
chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) ||
|
||||
((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)),
|
||||
"inconsistent semaphore");
|
||||
|
||||
chSysLock();
|
||||
if (++sp->s_cnt <= (cnt_t)0) {
|
||||
chSchWakeupS(queue_fifo_remove(&sp->s_queue), MSG_OK);
|
||||
if (++sp->cnt <= (cnt_t)0) {
|
||||
chSchWakeupS(queue_fifo_remove(&sp->queue), MSG_OK);
|
||||
}
|
||||
chSysUnlock();
|
||||
}
|
||||
|
@ -320,15 +320,15 @@ void chSemSignalI(semaphore_t *sp) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck(sp != NULL);
|
||||
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
|
||||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
|
||||
chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) ||
|
||||
((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)),
|
||||
"inconsistent semaphore");
|
||||
|
||||
if (++sp->s_cnt <= (cnt_t)0) {
|
||||
if (++sp->cnt <= (cnt_t)0) {
|
||||
/* Note, it is done this way in order to allow a tail call on
|
||||
chSchReadyI().*/
|
||||
thread_t *tp = queue_fifo_remove(&sp->s_queue);
|
||||
tp->p_u.rdymsg = MSG_OK;
|
||||
thread_t *tp = queue_fifo_remove(&sp->queue);
|
||||
tp->u.rdymsg = MSG_OK;
|
||||
(void) chSchReadyI(tp);
|
||||
}
|
||||
}
|
||||
|
@ -350,13 +350,13 @@ void chSemAddCounterI(semaphore_t *sp, cnt_t n) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck((sp != NULL) && (n > (cnt_t)0));
|
||||
chDbgAssert(((sp->s_cnt >= (cnt_t)0) && queue_isempty(&sp->s_queue)) ||
|
||||
((sp->s_cnt < (cnt_t)0) && queue_notempty(&sp->s_queue)),
|
||||
chDbgAssert(((sp->cnt >= (cnt_t)0) && queue_isempty(&sp->queue)) ||
|
||||
((sp->cnt < (cnt_t)0) && queue_notempty(&sp->queue)),
|
||||
"inconsistent semaphore");
|
||||
|
||||
while (n > (cnt_t)0) {
|
||||
if (++sp->s_cnt <= (cnt_t)0) {
|
||||
chSchReadyI(queue_fifo_remove(&sp->s_queue))->p_u.rdymsg = MSG_OK;
|
||||
if (++sp->cnt <= (cnt_t)0) {
|
||||
chSchReadyI(queue_fifo_remove(&sp->queue))->u.rdymsg = MSG_OK;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
|
@ -379,23 +379,23 @@ msg_t chSemSignalWait(semaphore_t *sps, semaphore_t *spw) {
|
|||
msg_t msg;
|
||||
|
||||
chDbgCheck((sps != NULL) && (spw != NULL));
|
||||
chDbgAssert(((sps->s_cnt >= (cnt_t)0) && queue_isempty(&sps->s_queue)) ||
|
||||
((sps->s_cnt < (cnt_t)0) && queue_notempty(&sps->s_queue)),
|
||||
chDbgAssert(((sps->cnt >= (cnt_t)0) && queue_isempty(&sps->queue)) ||
|
||||
((sps->cnt < (cnt_t)0) && queue_notempty(&sps->queue)),
|
||||
"inconsistent semaphore");
|
||||
chDbgAssert(((spw->s_cnt >= (cnt_t)0) && queue_isempty(&spw->s_queue)) ||
|
||||
((spw->s_cnt < (cnt_t)0) && queue_notempty(&spw->s_queue)),
|
||||
chDbgAssert(((spw->cnt >= (cnt_t)0) && queue_isempty(&spw->queue)) ||
|
||||
((spw->cnt < (cnt_t)0) && queue_notempty(&spw->queue)),
|
||||
"inconsistent semaphore");
|
||||
|
||||
chSysLock();
|
||||
if (++sps->s_cnt <= (cnt_t)0) {
|
||||
chSchReadyI(queue_fifo_remove(&sps->s_queue))->p_u.rdymsg = MSG_OK;
|
||||
if (++sps->cnt <= (cnt_t)0) {
|
||||
chSchReadyI(queue_fifo_remove(&sps->queue))->u.rdymsg = MSG_OK;
|
||||
}
|
||||
if (--spw->s_cnt < (cnt_t)0) {
|
||||
if (--spw->cnt < (cnt_t)0) {
|
||||
thread_t *ctp = currp;
|
||||
sem_insert(ctp, &spw->s_queue);
|
||||
ctp->p_u.wtsemp = spw;
|
||||
sem_insert(ctp, &spw->queue);
|
||||
ctp->u.wtsemp = spw;
|
||||
chSchGoSleepS(CH_STATE_WTSEM);
|
||||
msg = ctp->p_u.rdymsg;
|
||||
msg = ctp->u.rdymsg;
|
||||
}
|
||||
else {
|
||||
chSchRescheduleS();
|
||||
|
|
|
@ -86,7 +86,7 @@ void _stats_increase_irq(void) {
|
|||
void _stats_ctxswc(thread_t *ntp, thread_t *otp) {
|
||||
|
||||
ch.kernel_stats.n_ctxswc++;
|
||||
chTMChainMeasurementToX(&otp->p_stats, &ntp->p_stats);
|
||||
chTMChainMeasurementToX(&otp->stats, &ntp->stats);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -91,13 +91,11 @@ static void _idle_thread(void *p) {
|
|||
* @special
|
||||
*/
|
||||
void chSysInit(void) {
|
||||
#if CH_DBG_ENABLE_STACK_CHECK == TRUE
|
||||
extern stkalign_t __main_thread_stack_base__;
|
||||
#endif
|
||||
|
||||
port_init();
|
||||
_scheduler_init();
|
||||
_vt_init();
|
||||
|
||||
#if CH_DBG_SYSTEM_STATE_CHECK == TRUE
|
||||
ch.dbg.isr_cnt = (cnt_t)0;
|
||||
ch.dbg.lock_cnt = (cnt_t)0;
|
||||
|
@ -114,30 +112,34 @@ void chSysInit(void) {
|
|||
#if CH_DBG_STATISTICS == TRUE
|
||||
_stats_init();
|
||||
#endif
|
||||
#if CH_DBG_ENABLE_TRACE == TRUE
|
||||
#if CH_DBG_TRACE_MASK != CH_DBG_TRACE_MASK_NONE
|
||||
_dbg_trace_init();
|
||||
#endif
|
||||
|
||||
#if CH_CFG_NO_IDLE_THREAD == FALSE
|
||||
/* Now this instructions flow becomes the main thread.*/
|
||||
setcurrp(_thread_init(&ch.mainthread, NORMALPRIO));
|
||||
currp = _thread_init(&ch.mainthread, "main", NORMALPRIO);
|
||||
#else
|
||||
/* Now this instructions flow becomes the idle thread.*/
|
||||
setcurrp(_thread_init(&ch.mainthread, IDLEPRIO));
|
||||
currp = _thread_init(&ch.mainthread, "idle", IDLEPRIO));
|
||||
#endif
|
||||
|
||||
currp->p_state = CH_STATE_CURRENT;
|
||||
#if CH_DBG_ENABLE_STACK_CHECK == TRUE
|
||||
/* This is a special case because the main thread thread_t structure is not
|
||||
adjacent to its stack area.*/
|
||||
currp->p_stklimit = &__main_thread_stack_base__;
|
||||
#endif
|
||||
/* Setting up the base address of the static main thread stack.*/
|
||||
currp->stklimit = &__main_thread_stack_base__;
|
||||
|
||||
/* Setting up the caller as current thread.*/
|
||||
currp->state = CH_STATE_CURRENT;
|
||||
|
||||
/* Port layer initialization last because it depend on some of the
|
||||
initializations performed before.*/
|
||||
port_init();
|
||||
|
||||
#if CH_DBG_STATISTICS == TRUE
|
||||
/* Starting measurement for this thread.*/
|
||||
chTMStartMeasurementX(&currp->p_stats);
|
||||
#endif
|
||||
|
||||
/* It is alive now.*/
|
||||
chSysEnable();
|
||||
|
||||
#if CH_CFG_USE_REGISTRY == TRUE
|
||||
|
@ -148,15 +150,19 @@ void chSysInit(void) {
|
|||
|
||||
#if CH_CFG_NO_IDLE_THREAD == FALSE
|
||||
{
|
||||
static const thread_descriptor_t idle_descriptor = {
|
||||
"idle",
|
||||
THD_WORKING_AREA_BASE(ch.idle_thread_wa),
|
||||
THD_WORKING_AREA_END(ch.idle_thread_wa),
|
||||
IDLEPRIO,
|
||||
_idle_thread,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* This thread has the lowest priority in the system, its role is just to
|
||||
serve interrupts in its context while keeping the lowest energy saving
|
||||
mode compatible with the system status.*/
|
||||
thread_t *tp = chThdCreateStatic(ch.idle_thread_wa,
|
||||
sizeof(ch.idle_thread_wa),
|
||||
IDLEPRIO,
|
||||
(tfunc_t)_idle_thread,
|
||||
NULL);
|
||||
chRegSetThreadNameX(tp, "idle");
|
||||
(void) chThdCreate(&idle_descriptor);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -177,9 +183,11 @@ void chSysHalt(const char *reason) {
|
|||
|
||||
port_disable();
|
||||
|
||||
#if defined(CH_CFG_SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
|
||||
/* Halt hook code, usually empty.*/
|
||||
CH_CFG_SYSTEM_HALT_HOOK(reason);
|
||||
#endif
|
||||
|
||||
/* Logging the event.*/
|
||||
_dbg_trace_halt(reason);
|
||||
|
||||
/* Pointing to the passed message.*/
|
||||
ch.dbg.panic_msg = reason;
|
||||
|
@ -224,17 +232,17 @@ bool chSysIntegrityCheckI(unsigned testmask) {
|
|||
|
||||
/* Scanning the ready list forward.*/
|
||||
n = (cnt_t)0;
|
||||
tp = ch.rlist.r_queue.p_next;
|
||||
while (tp != (thread_t *)&ch.rlist.r_queue) {
|
||||
tp = ch.rlist.queue.next;
|
||||
while (tp != (thread_t *)&ch.rlist.queue) {
|
||||
n++;
|
||||
tp = tp->p_next;
|
||||
tp = tp->next;
|
||||
}
|
||||
|
||||
/* Scanning the ready list backward.*/
|
||||
tp = ch.rlist.r_queue.p_prev;
|
||||
while (tp != (thread_t *)&ch.rlist.r_queue) {
|
||||
tp = ch.rlist.queue.prev;
|
||||
while (tp != (thread_t *)&ch.rlist.queue) {
|
||||
n--;
|
||||
tp = tp->p_prev;
|
||||
tp = tp->prev;
|
||||
}
|
||||
|
||||
/* The number of elements must match.*/
|
||||
|
@ -249,17 +257,17 @@ bool chSysIntegrityCheckI(unsigned testmask) {
|
|||
|
||||
/* Scanning the timers list forward.*/
|
||||
n = (cnt_t)0;
|
||||
vtp = ch.vtlist.vt_next;
|
||||
vtp = ch.vtlist.next;
|
||||
while (vtp != (virtual_timer_t *)&ch.vtlist) {
|
||||
n++;
|
||||
vtp = vtp->vt_next;
|
||||
vtp = vtp->next;
|
||||
}
|
||||
|
||||
/* Scanning the timers list backward.*/
|
||||
vtp = ch.vtlist.vt_prev;
|
||||
vtp = ch.vtlist.prev;
|
||||
while (vtp != (virtual_timer_t *)&ch.vtlist) {
|
||||
n--;
|
||||
vtp = vtp->vt_prev;
|
||||
vtp = vtp->prev;
|
||||
}
|
||||
|
||||
/* The number of elements must match.*/
|
||||
|
@ -274,17 +282,17 @@ bool chSysIntegrityCheckI(unsigned testmask) {
|
|||
|
||||
/* Scanning the ready list forward.*/
|
||||
n = (cnt_t)0;
|
||||
tp = ch.rlist.r_newer;
|
||||
tp = ch.rlist.newer;
|
||||
while (tp != (thread_t *)&ch.rlist) {
|
||||
n++;
|
||||
tp = tp->p_newer;
|
||||
tp = tp->newer;
|
||||
}
|
||||
|
||||
/* Scanning the ready list backward.*/
|
||||
tp = ch.rlist.r_older;
|
||||
tp = ch.rlist.older;
|
||||
while (tp != (thread_t *)&ch.rlist) {
|
||||
n--;
|
||||
tp = tp->p_older;
|
||||
tp = tp->older;
|
||||
}
|
||||
|
||||
/* The number of elements must match.*/
|
||||
|
@ -320,18 +328,16 @@ void chSysTimerHandlerI(void) {
|
|||
|
||||
#if CH_CFG_TIME_QUANTUM > 0
|
||||
/* Running thread has not used up quantum yet? */
|
||||
if (currp->p_preempt > (tslices_t)0) {
|
||||
if (currp->preempt > (tslices_t)0) {
|
||||
/* Decrement remaining quantum.*/
|
||||
currp->p_preempt--;
|
||||
currp->preempt--;
|
||||
}
|
||||
#endif
|
||||
#if CH_DBG_THREADS_PROFILING == TRUE
|
||||
currp->p_time++;
|
||||
currp->time++;
|
||||
#endif
|
||||
chVTDoTickI();
|
||||
#if defined(CH_CFG_SYSTEM_TICK_HOOK)
|
||||
CH_CFG_SYSTEM_TICK_HOOK();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -45,10 +45,6 @@
|
|||
* - <b>SetPriority</b>, a thread changes its own priority level.
|
||||
* - <b>Yield</b>, a thread voluntarily renounces to its time slot.
|
||||
* .
|
||||
* The threads subsystem is implicitly included in kernel however
|
||||
* some of its part may be excluded by disabling them in @p chconf.h,
|
||||
* see the @p CH_CFG_USE_WAITEXIT and @p CH_CFG_USE_DYNAMIC configuration
|
||||
* options.
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
@ -83,51 +79,42 @@
|
|||
* @note This is an internal functions, do not use it in application code.
|
||||
*
|
||||
* @param[in] tp pointer to the thread
|
||||
* @param[in] name thread name
|
||||
* @param[in] prio the priority level for the new thread
|
||||
* @return The same thread pointer passed as parameter.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
thread_t *_thread_init(thread_t *tp, tprio_t prio) {
|
||||
thread_t *_thread_init(thread_t *tp, const char *name, tprio_t prio) {
|
||||
|
||||
tp->p_prio = prio;
|
||||
tp->p_state = CH_STATE_WTSTART;
|
||||
tp->p_flags = CH_FLAG_MODE_STATIC;
|
||||
tp->prio = prio;
|
||||
#if CH_CFG_TIME_QUANTUM > 0
|
||||
tp->p_preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
|
||||
tp->preempt = (tslices_t)CH_CFG_TIME_QUANTUM;
|
||||
#endif
|
||||
#if CH_CFG_USE_MUTEXES == TRUE
|
||||
tp->p_realprio = prio;
|
||||
tp->p_mtxlist = NULL;
|
||||
tp->realprio = prio;
|
||||
tp->mtxlist = NULL;
|
||||
#endif
|
||||
#if CH_CFG_USE_EVENTS == TRUE
|
||||
tp->p_epending = (eventmask_t)0;
|
||||
tp->epending = (eventmask_t)0;
|
||||
#endif
|
||||
#if CH_DBG_THREADS_PROFILING == TRUE
|
||||
tp->p_time = (systime_t)0;
|
||||
#endif
|
||||
#if CH_CFG_USE_DYNAMIC == TRUE
|
||||
tp->p_refs = (trefs_t)1;
|
||||
tp->time = (systime_t)0;
|
||||
#endif
|
||||
#if CH_CFG_USE_REGISTRY == TRUE
|
||||
tp->p_name = NULL;
|
||||
tp->name = name;
|
||||
REG_INSERT(tp);
|
||||
#endif
|
||||
#if CH_CFG_USE_WAITEXIT == TRUE
|
||||
list_init(&tp->p_waiting);
|
||||
list_init(&tp->waiting);
|
||||
#endif
|
||||
#if CH_CFG_USE_MESSAGES == TRUE
|
||||
queue_init(&tp->p_msgqueue);
|
||||
#endif
|
||||
#if CH_DBG_ENABLE_STACK_CHECK == TRUE
|
||||
tp->p_stklimit = (stkalign_t *)(tp + 1);
|
||||
queue_init(&tp->msgqueue);
|
||||
#endif
|
||||
#if CH_DBG_STATISTICS == TRUE
|
||||
chTMObjectInit(&tp->p_stats);
|
||||
chTMObjectInit(&tp->stats);
|
||||
#endif
|
||||
#if defined(CH_CFG_THREAD_INIT_HOOK)
|
||||
CH_CFG_THREAD_INIT_HOOK(tp);
|
||||
#endif
|
||||
return tp;
|
||||
}
|
||||
|
||||
|
@ -162,30 +149,126 @@ void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v) {
|
|||
* @p CH_DBG_FILL_THREADS debug option because it would keep
|
||||
* the kernel locked for too much time.
|
||||
*
|
||||
* @param[out] wsp pointer to a working area dedicated to the thread stack
|
||||
* @param[in] size size of the working area
|
||||
* @param[in] prio the priority level for the new thread
|
||||
* @param[in] pf the thread function
|
||||
* @param[in] arg an argument passed to the thread function. It can be
|
||||
* @p NULL.
|
||||
* @param[out] tdp pointer to the thread descriptor
|
||||
* @return The pointer to the @p thread_t structure allocated for
|
||||
* the thread into the working space area.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
thread_t *chThdCreateI(void *wsp, size_t size,
|
||||
tprio_t prio, tfunc_t pf, void *arg) {
|
||||
/* The thread structure is laid out in the lower part of the thread
|
||||
workspace.*/
|
||||
thread_t *tp = wsp;
|
||||
thread_t *chThdCreateSuspendedI(const thread_descriptor_t *tdp) {
|
||||
thread_t *tp;
|
||||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck((wsp != NULL) && (size >= THD_WORKING_AREA_SIZE(0)) &&
|
||||
(prio <= HIGHPRIO) && (pf != NULL));
|
||||
chDbgCheck(tdp != NULL);
|
||||
chDbgCheck(MEM_IS_ALIGNED(tdp->wbase, PORT_WORKING_AREA_ALIGN) &&
|
||||
MEM_IS_ALIGNED(tdp->wend, PORT_STACK_ALIGN) &&
|
||||
(tdp->wend > tdp->wbase) &&
|
||||
((size_t)((tdp->wend - tdp->wbase) *
|
||||
sizeof (stkalign_t)) >= THD_WORKING_AREA_SIZE(0)));
|
||||
chDbgCheck((tdp->prio <= HIGHPRIO) && (tdp->funcp != NULL));
|
||||
|
||||
PORT_SETUP_CONTEXT(tp, wsp, size, pf, arg);
|
||||
/* The thread structure is laid out in the upper part of the thread
|
||||
workspace. The thread position structure is aligned to the required
|
||||
stack alignment because it represents the stack top.*/
|
||||
tp = (thread_t *)((uint8_t *)tdp->wend -
|
||||
MEM_ALIGN_NEXT(sizeof (thread_t), PORT_STACK_ALIGN));
|
||||
|
||||
return _thread_init(tp, prio);
|
||||
/* Initial state.*/
|
||||
tp->state = CH_STATE_WTSTART;
|
||||
|
||||
/* Stack boundary.*/
|
||||
tp->stklimit = tdp->wbase;
|
||||
|
||||
/* Setting up the port-dependent part of the working area.*/
|
||||
PORT_SETUP_CONTEXT(tp, tdp->wbase, tp, tdp->funcp, tdp->arg);
|
||||
|
||||
/* The driver object is initialized but not started.*/
|
||||
return _thread_init(tp, tdp->name, tdp->prio);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Creates a new thread into a static memory area.
|
||||
* @details The new thread is initialized but not inserted in the ready list,
|
||||
* the initial state is @p CH_STATE_WTSTART.
|
||||
* @post The initialized thread can be subsequently started by invoking
|
||||
* @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
|
||||
* depending on the execution context.
|
||||
* @note A thread can terminate by calling @p chThdExit() or by simply
|
||||
* returning from its main function.
|
||||
*
|
||||
* @param[out] tdp pointer to the thread descriptor
|
||||
* @return The pointer to the @p thread_t structure allocated for
|
||||
* the thread into the working space area.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
thread_t *chThdCreateSuspended(const thread_descriptor_t *tdp) {
|
||||
thread_t *tp;
|
||||
|
||||
#if CH_DBG_FILL_THREADS == TRUE
|
||||
_thread_memfill((uint8_t *)tdp->wbase,
|
||||
(uint8_t *)tdp->wend,
|
||||
CH_DBG_STACK_FILL_VALUE);
|
||||
#endif
|
||||
|
||||
chSysLock();
|
||||
tp = chThdCreateSuspendedI(tdp);
|
||||
chSysUnlock();
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new thread into a static memory area.
|
||||
* @details The new thread is initialized and make ready to execute.
|
||||
* @post The initialized thread can be subsequently started by invoking
|
||||
* @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
|
||||
* depending on the execution context.
|
||||
* @note A thread can terminate by calling @p chThdExit() or by simply
|
||||
* returning from its main function.
|
||||
* @note Threads created using this function do not obey to the
|
||||
* @p CH_DBG_FILL_THREADS debug option because it would keep
|
||||
* the kernel locked for too much time.
|
||||
*
|
||||
* @param[out] tdp pointer to the thread descriptor
|
||||
* @return The pointer to the @p thread_t structure allocated for
|
||||
* the thread into the working space area.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
thread_t *chThdCreateI(const thread_descriptor_t *tdp) {
|
||||
|
||||
return chSchReadyI(chThdCreateSuspendedI(tdp));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new thread into a static memory area.
|
||||
* @details The new thread is initialized and make ready to execute.
|
||||
* @note A thread can terminate by calling @p chThdExit() or by simply
|
||||
* returning from its main function.
|
||||
*
|
||||
* @param[out] tdp pointer to the thread descriptor
|
||||
* @return The pointer to the @p thread_t structure allocated for
|
||||
* the thread into the working space area.
|
||||
*
|
||||
* @iclass
|
||||
*/
|
||||
thread_t *chThdCreate(const thread_descriptor_t *tdp) {
|
||||
thread_t *tp;
|
||||
|
||||
#if CH_DBG_FILL_THREADS == TRUE
|
||||
_thread_memfill((uint8_t *)tdp->wbase,
|
||||
(uint8_t *)tdp->wend,
|
||||
CH_DBG_STACK_FILL_VALUE);
|
||||
#endif
|
||||
|
||||
chSysLock();
|
||||
tp = chThdCreateSuspendedI(tdp);
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSysUnlock();
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -208,17 +291,35 @@ thread_t *chThdCreateStatic(void *wsp, size_t size,
|
|||
tprio_t prio, tfunc_t pf, void *arg) {
|
||||
thread_t *tp;
|
||||
|
||||
chDbgCheck((wsp != NULL) &&
|
||||
MEM_IS_ALIGNED(wsp, PORT_WORKING_AREA_ALIGN) &&
|
||||
(size >= THD_WORKING_AREA_SIZE(0)) &&
|
||||
MEM_IS_ALIGNED(size, PORT_STACK_ALIGN) &&
|
||||
(prio <= HIGHPRIO) && (pf != NULL));
|
||||
|
||||
#if CH_DBG_FILL_THREADS == TRUE
|
||||
_thread_memfill((uint8_t *)wsp,
|
||||
(uint8_t *)wsp + sizeof(thread_t),
|
||||
CH_DBG_THREAD_FILL_VALUE);
|
||||
_thread_memfill((uint8_t *)wsp + sizeof(thread_t),
|
||||
(uint8_t *)wsp + size,
|
||||
CH_DBG_STACK_FILL_VALUE);
|
||||
#endif
|
||||
|
||||
chSysLock();
|
||||
tp = chThdCreateI(wsp, size, prio, pf, arg);
|
||||
|
||||
/* The thread structure is laid out in the upper part of the thread
|
||||
workspace. The thread position structure is aligned to the required
|
||||
stack alignment because it represents the stack top.*/
|
||||
tp = (thread_t *)((uint8_t *)wsp + size -
|
||||
MEM_ALIGN_NEXT(sizeof (thread_t), PORT_STACK_ALIGN));
|
||||
|
||||
/* Stack boundary.*/
|
||||
tp->stklimit = (stkalign_t *)wsp;
|
||||
|
||||
/* Setting up the port-dependent part of the working area.*/
|
||||
PORT_SETUP_CONTEXT(tp, wsp, tp, pf, arg);
|
||||
|
||||
tp = _thread_init(tp, "noname", prio);
|
||||
|
||||
/* Starting the thread immediately.*/
|
||||
chSchWakeupS(tp, MSG_OK);
|
||||
chSysUnlock();
|
||||
|
||||
|
@ -262,14 +363,14 @@ tprio_t chThdSetPriority(tprio_t newprio) {
|
|||
|
||||
chSysLock();
|
||||
#if CH_CFG_USE_MUTEXES == TRUE
|
||||
oldprio = currp->p_realprio;
|
||||
if ((currp->p_prio == currp->p_realprio) || (newprio > currp->p_prio)) {
|
||||
currp->p_prio = newprio;
|
||||
oldprio = currp->realprio;
|
||||
if ((currp->prio == currp->realprio) || (newprio > currp->prio)) {
|
||||
currp->prio = newprio;
|
||||
}
|
||||
currp->p_realprio = newprio;
|
||||
currp->realprio = newprio;
|
||||
#else
|
||||
oldprio = currp->p_prio;
|
||||
currp->p_prio = newprio;
|
||||
oldprio = currp->prio;
|
||||
currp->prio = newprio;
|
||||
#endif
|
||||
chSchRescheduleS();
|
||||
chSysUnlock();
|
||||
|
@ -277,25 +378,6 @@ tprio_t chThdSetPriority(tprio_t newprio) {
|
|||
return oldprio;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Requests a thread termination.
|
||||
* @pre The target thread must be written to invoke periodically
|
||||
* @p chThdShouldTerminate() and terminate cleanly if it returns
|
||||
* @p true.
|
||||
* @post The specified thread will terminate after detecting the termination
|
||||
* condition.
|
||||
*
|
||||
* @param[in] tp pointer to the thread
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void chThdTerminate(thread_t *tp) {
|
||||
|
||||
chSysLock();
|
||||
tp->p_flags |= CH_FLAG_TERMINATE;
|
||||
chSysUnlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Suspends the invoking thread for the specified time.
|
||||
*
|
||||
|
@ -417,21 +499,15 @@ void chThdExit(msg_t msg) {
|
|||
void chThdExitS(msg_t msg) {
|
||||
thread_t *tp = currp;
|
||||
|
||||
tp->p_u.exitcode = msg;
|
||||
#if defined(CH_CFG_THREAD_EXIT_HOOK)
|
||||
tp->u.exitcode = msg;
|
||||
CH_CFG_THREAD_EXIT_HOOK(tp);
|
||||
#endif
|
||||
#if CH_CFG_USE_WAITEXIT == TRUE
|
||||
while (list_notempty(&tp->p_waiting)) {
|
||||
(void) chSchReadyI(list_remove(&tp->p_waiting));
|
||||
while (list_notempty(&tp->waiting)) {
|
||||
(void) chSchReadyI(list_remove(&tp->waiting));
|
||||
}
|
||||
#endif
|
||||
#if CH_CFG_USE_REGISTRY == TRUE
|
||||
/* Static threads are immediately removed from the registry because
|
||||
there is no memory to recover.*/
|
||||
if ((tp->p_flags & CH_FLAG_MODE_MASK) == CH_FLAG_MODE_STATIC) {
|
||||
REG_REMOVE(tp);
|
||||
}
|
||||
#endif
|
||||
chSchGoSleepS(CH_STATE_FINAL);
|
||||
|
||||
|
@ -443,28 +519,12 @@ void chThdExitS(msg_t msg) {
|
|||
/**
|
||||
* @brief Blocks the execution of the invoking thread until the specified
|
||||
* thread terminates then the exit code is returned.
|
||||
* @details This function waits for the specified thread to terminate then
|
||||
* decrements its reference counter, if the counter reaches zero then
|
||||
* the thread working area is returned to the proper allocator.<br>
|
||||
* The memory used by the exited thread is handled in different ways
|
||||
* depending on the API that spawned the thread:
|
||||
* - If the thread was spawned by @p chThdCreateStatic() or by
|
||||
* @p chThdCreateI() then nothing happens and the thread working
|
||||
* area is not released or modified in any way. This is the
|
||||
* default, totally static, behavior.
|
||||
* - If the thread was spawned by @p chThdCreateFromHeap() then
|
||||
* the working area is returned to the system heap.
|
||||
* - If the thread was spawned by @p chThdCreateFromMemoryPool()
|
||||
* then the working area is returned to the owning memory pool.
|
||||
* .
|
||||
* @pre The configuration option @p CH_CFG_USE_WAITEXIT must be enabled in
|
||||
* order to use this function.
|
||||
* @post Enabling @p chThdWait() requires 2-4 (depending on the
|
||||
* architecture) extra bytes in the @p thread_t structure.
|
||||
* @post After invoking @p chThdWait() the thread pointer becomes invalid
|
||||
* and must not be used as parameter for further system calls.
|
||||
* @note If @p CH_CFG_USE_DYNAMIC is not specified this function just waits for
|
||||
* the thread termination, no memory allocators are involved.
|
||||
*
|
||||
* @param[in] tp pointer to the thread
|
||||
* @return The exit code from the terminated thread.
|
||||
|
@ -478,21 +538,13 @@ msg_t chThdWait(thread_t *tp) {
|
|||
|
||||
chSysLock();
|
||||
chDbgAssert(tp != currp, "waiting self");
|
||||
#if CH_CFG_USE_DYNAMIC == TRUE
|
||||
chDbgAssert(tp->p_refs > (trefs_t)0, "not referenced");
|
||||
#endif
|
||||
if (tp->p_state != CH_STATE_FINAL) {
|
||||
list_insert(currp, &tp->p_waiting);
|
||||
if (tp->state != CH_STATE_FINAL) {
|
||||
list_insert(currp, &tp->waiting);
|
||||
chSchGoSleepS(CH_STATE_WTEXIT);
|
||||
}
|
||||
msg = tp->p_u.exitcode;
|
||||
msg = tp->u.exitcode;
|
||||
chSysUnlock();
|
||||
|
||||
#if CH_CFG_USE_DYNAMIC == TRUE
|
||||
/* Releasing a lock if it is a dynamic thread.*/
|
||||
chThdRelease(tp);
|
||||
#endif
|
||||
|
||||
return msg;
|
||||
}
|
||||
#endif /* CH_CFG_USE_WAITEXIT */
|
||||
|
@ -513,10 +565,10 @@ msg_t chThdSuspendS(thread_reference_t *trp) {
|
|||
chDbgAssert(*trp == NULL, "not NULL");
|
||||
|
||||
*trp = tp;
|
||||
tp->p_u.wttrp = trp;
|
||||
tp->u.wttrp = trp;
|
||||
chSchGoSleepS(CH_STATE_SUSPENDED);
|
||||
|
||||
return chThdGetSelfX()->p_u.rdymsg;
|
||||
return chThdGetSelfX()->u.rdymsg;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -548,7 +600,7 @@ msg_t chThdSuspendTimeoutS(thread_reference_t *trp, systime_t timeout) {
|
|||
}
|
||||
|
||||
*trp = tp;
|
||||
tp->p_u.wttrp = trp;
|
||||
tp->u.wttrp = trp;
|
||||
|
||||
return chSchGoSleepTimeoutS(CH_STATE_SUSPENDED, timeout);
|
||||
}
|
||||
|
@ -568,11 +620,10 @@ void chThdResumeI(thread_reference_t *trp, msg_t msg) {
|
|||
if (*trp != NULL) {
|
||||
thread_t *tp = *trp;
|
||||
|
||||
chDbgAssert(tp->p_state == CH_STATE_SUSPENDED,
|
||||
"not THD_STATE_SUSPENDED");
|
||||
chDbgAssert(tp->state == CH_STATE_SUSPENDED, "not CH_STATE_SUSPENDED");
|
||||
|
||||
*trp = NULL;
|
||||
tp->p_u.rdymsg = msg;
|
||||
tp->u.rdymsg = msg;
|
||||
(void) chSchReadyI(tp);
|
||||
}
|
||||
}
|
||||
|
@ -592,8 +643,7 @@ void chThdResumeS(thread_reference_t *trp, msg_t msg) {
|
|||
if (*trp != NULL) {
|
||||
thread_t *tp = *trp;
|
||||
|
||||
chDbgAssert(tp->p_state == CH_STATE_SUSPENDED,
|
||||
"not THD_STATE_SUSPENDED");
|
||||
chDbgAssert(tp->state == CH_STATE_SUSPENDED, "not CH_STATE_SUSPENDED");
|
||||
|
||||
*trp = NULL;
|
||||
chSchWakeupS(tp, msg);
|
||||
|
|
102
os/rt/src/chvt.c
102
os/rt/src/chvt.c
|
@ -60,13 +60,13 @@
|
|||
*/
|
||||
void _vt_init(void) {
|
||||
|
||||
ch.vtlist.vt_next = (virtual_timer_t *)&ch.vtlist;
|
||||
ch.vtlist.vt_prev = (virtual_timer_t *)&ch.vtlist;
|
||||
ch.vtlist.vt_delta = (systime_t)-1;
|
||||
ch.vtlist.next = (virtual_timer_t *)&ch.vtlist;
|
||||
ch.vtlist.prev = (virtual_timer_t *)&ch.vtlist;
|
||||
ch.vtlist.delta = (systime_t)-1;
|
||||
#if CH_CFG_ST_TIMEDELTA == 0
|
||||
ch.vtlist.vt_systime = (systime_t)0;
|
||||
ch.vtlist.systime = (systime_t)0;
|
||||
#else /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||
ch.vtlist.vt_lasttime = (systime_t)0;
|
||||
ch.vtlist.lasttime = (systime_t)0;
|
||||
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||
}
|
||||
|
||||
|
@ -100,8 +100,8 @@ void chVTDoSetI(virtual_timer_t *vtp, systime_t delay,
|
|||
chDbgCheckClassI();
|
||||
chDbgCheck((vtp != NULL) && (vtfunc != NULL) && (delay != TIME_IMMEDIATE));
|
||||
|
||||
vtp->vt_par = par;
|
||||
vtp->vt_func = vtfunc;
|
||||
vtp->par = par;
|
||||
vtp->func = vtfunc;
|
||||
|
||||
#if CH_CFG_ST_TIMEDELTA > 0
|
||||
{
|
||||
|
@ -114,30 +114,30 @@ void chVTDoSetI(virtual_timer_t *vtp, systime_t delay,
|
|||
}
|
||||
|
||||
/* Special case where the timers list is empty.*/
|
||||
if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.vt_next) {
|
||||
if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.next) {
|
||||
|
||||
/* The delta list is empty, the current time becomes the new
|
||||
delta list base time, the timer is inserted.*/
|
||||
ch.vtlist.vt_lasttime = now;
|
||||
ch.vtlist.vt_next = vtp;
|
||||
ch.vtlist.vt_prev = vtp;
|
||||
vtp->vt_next = (virtual_timer_t *)&ch.vtlist;
|
||||
vtp->vt_prev = (virtual_timer_t *)&ch.vtlist;
|
||||
vtp->vt_delta = delay;
|
||||
ch.vtlist.lasttime = now;
|
||||
ch.vtlist.next = vtp;
|
||||
ch.vtlist.prev = vtp;
|
||||
vtp->next = (virtual_timer_t *)&ch.vtlist;
|
||||
vtp->prev = (virtual_timer_t *)&ch.vtlist;
|
||||
vtp->delta = delay;
|
||||
|
||||
/* Being the first element in the list the alarm timer is started.*/
|
||||
port_timer_start_alarm(ch.vtlist.vt_lasttime + delay);
|
||||
port_timer_start_alarm(ch.vtlist.lasttime + delay);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Special case where the timer will be placed as first element in a
|
||||
non-empty list, the alarm needs to be recalculated.*/
|
||||
delta = now + delay - ch.vtlist.vt_lasttime;
|
||||
if (delta < ch.vtlist.vt_next->vt_delta) {
|
||||
delta = now + delay - ch.vtlist.lasttime;
|
||||
if (delta < ch.vtlist.next->delta) {
|
||||
|
||||
/* New alarm deadline.*/
|
||||
port_timer_set_alarm(ch.vtlist.vt_lasttime + delta);
|
||||
port_timer_set_alarm(ch.vtlist.lasttime + delta);
|
||||
}
|
||||
}
|
||||
#else /* CH_CFG_ST_TIMEDELTA == 0 */
|
||||
|
@ -147,23 +147,23 @@ void chVTDoSetI(virtual_timer_t *vtp, systime_t delay,
|
|||
|
||||
/* The delta list is scanned in order to find the correct position for
|
||||
this timer. */
|
||||
p = ch.vtlist.vt_next;
|
||||
while (p->vt_delta < delta) {
|
||||
delta -= p->vt_delta;
|
||||
p = p->vt_next;
|
||||
p = ch.vtlist.next;
|
||||
while (p->delta < delta) {
|
||||
delta -= p->delta;
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
/* The timer is inserted in the delta list.*/
|
||||
vtp->vt_next = p;
|
||||
vtp->vt_prev = vtp->vt_next->vt_prev;
|
||||
vtp->vt_prev->vt_next = vtp;
|
||||
p->vt_prev = vtp;
|
||||
vtp->vt_delta = delta
|
||||
vtp->next = p;
|
||||
vtp->prev = vtp->next->prev;
|
||||
vtp->prev->next = vtp;
|
||||
p->prev = vtp;
|
||||
vtp->delta = delta
|
||||
|
||||
/* Special case when the timer is in last position in the list, the
|
||||
value in the header must be restored.*/;
|
||||
p->vt_delta -= delta;
|
||||
ch.vtlist.vt_delta = (systime_t)-1;
|
||||
p->delta -= delta;
|
||||
ch.vtlist.delta = (systime_t)-1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,71 +178,71 @@ void chVTDoResetI(virtual_timer_t *vtp) {
|
|||
|
||||
chDbgCheckClassI();
|
||||
chDbgCheck(vtp != NULL);
|
||||
chDbgAssert(vtp->vt_func != NULL, "timer not set or already triggered");
|
||||
chDbgAssert(vtp->func != NULL, "timer not set or already triggered");
|
||||
|
||||
#if CH_CFG_ST_TIMEDELTA == 0
|
||||
|
||||
/* The delta of the timer is added to the next timer.*/
|
||||
vtp->vt_next->vt_delta += vtp->vt_delta;
|
||||
vtp->next->delta += vtp->delta;
|
||||
|
||||
/* Removing the element from the delta list.*/
|
||||
vtp->vt_prev->vt_next = vtp->vt_next;
|
||||
vtp->vt_next->vt_prev = vtp->vt_prev;
|
||||
vtp->vt_func = NULL;
|
||||
vtp->prev->next = vtp->next;
|
||||
vtp->next->prev = vtp->prev;
|
||||
vtp->func = NULL;
|
||||
|
||||
/* The above code changes the value in the header when the removed element
|
||||
is the last of the list, restoring it.*/
|
||||
ch.vtlist.vt_delta = (systime_t)-1;
|
||||
ch.vtlist.delta = (systime_t)-1;
|
||||
#else /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||
systime_t nowdelta, delta;
|
||||
|
||||
/* If the timer is not the first of the list then it is simply unlinked
|
||||
else the operation is more complex.*/
|
||||
if (ch.vtlist.vt_next != vtp) {
|
||||
if (ch.vtlist.next != vtp) {
|
||||
/* Removing the element from the delta list.*/
|
||||
vtp->vt_prev->vt_next = vtp->vt_next;
|
||||
vtp->vt_next->vt_prev = vtp->vt_prev;
|
||||
vtp->vt_func = NULL;
|
||||
vtp->prev->next = vtp->next;
|
||||
vtp->next->prev = vtp->prev;
|
||||
vtp->func = NULL;
|
||||
|
||||
/* Adding delta to the next element, if it is not the last one.*/
|
||||
if (&ch.vtlist != (virtual_timers_list_t *)vtp->vt_next)
|
||||
vtp->vt_next->vt_delta += vtp->vt_delta;
|
||||
if (&ch.vtlist != (virtual_timers_list_t *)vtp->next)
|
||||
vtp->next->delta += vtp->delta;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Removing the first timer from the list.*/
|
||||
ch.vtlist.vt_next = vtp->vt_next;
|
||||
ch.vtlist.vt_next->vt_prev = (virtual_timer_t *)&ch.vtlist;
|
||||
vtp->vt_func = NULL;
|
||||
ch.vtlist.next = vtp->next;
|
||||
ch.vtlist.next->prev = (virtual_timer_t *)&ch.vtlist;
|
||||
vtp->func = NULL;
|
||||
|
||||
/* If the list become empty then the alarm timer is stopped and done.*/
|
||||
if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.vt_next) {
|
||||
if (&ch.vtlist == (virtual_timers_list_t *)ch.vtlist.next) {
|
||||
port_timer_stop_alarm();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* The delta of the removed timer is added to the new first timer.*/
|
||||
ch.vtlist.vt_next->vt_delta += vtp->vt_delta;
|
||||
ch.vtlist.next->delta += vtp->delta;
|
||||
|
||||
/* If the new first timer has a delta of zero then the alarm is not
|
||||
modified, the already programmed alarm will serve it.*/
|
||||
/* if (ch.vtlist.vt_next->vt_delta == 0) {
|
||||
/* if (ch.vtlist.next->delta == 0) {
|
||||
return;
|
||||
}*/
|
||||
|
||||
/* Distance in ticks between the last alarm event and current time.*/
|
||||
nowdelta = chVTGetSystemTimeX() - ch.vtlist.vt_lasttime;
|
||||
nowdelta = chVTGetSystemTimeX() - ch.vtlist.lasttime;
|
||||
|
||||
/* If the current time surpassed the time of the next element in list
|
||||
then the event interrupt is already pending, just return.*/
|
||||
if (nowdelta >= ch.vtlist.vt_next->vt_delta) {
|
||||
if (nowdelta >= ch.vtlist.next->delta) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Distance from the next scheduled event and now.*/
|
||||
delta = ch.vtlist.vt_next->vt_delta - nowdelta;
|
||||
delta = ch.vtlist.next->delta - nowdelta;
|
||||
|
||||
/* Making sure to not schedule an event closer than CH_CFG_ST_TIMEDELTA
|
||||
ticks from now.*/
|
||||
|
@ -250,7 +250,7 @@ void chVTDoResetI(virtual_timer_t *vtp) {
|
|||
delta = (systime_t)CH_CFG_ST_TIMEDELTA;
|
||||
}
|
||||
|
||||
port_timer_set_alarm(ch.vtlist.vt_lasttime + nowdelta + delta);
|
||||
port_timer_set_alarm(ch.vtlist.lasttime + nowdelta + delta);
|
||||
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#ifndef _CHCONF_H_
|
||||
#define _CHCONF_H_
|
||||
|
||||
#define _CHIBIOS_RT_CONF_
|
||||
|
||||
/*===========================================================================*/
|
||||
/**
|
||||
* @name System timers settings
|
||||
|
@ -46,7 +48,7 @@
|
|||
* @details Frequency of the system timer that drives the system ticks. This
|
||||
* setting also defines the system tick time unit.
|
||||
*/
|
||||
#define CH_CFG_ST_FREQUENCY 10000
|
||||
#define CH_CFG_ST_FREQUENCY 1000
|
||||
|
||||
/**
|
||||
* @brief Time delta constant for the tick-less mode.
|
||||
|
@ -56,7 +58,7 @@
|
|||
* The value one is not valid, timeouts are rounded up to
|
||||
* this value.
|
||||
*/
|
||||
#define CH_CFG_ST_TIMEDELTA 2
|
||||
#define CH_CFG_ST_TIMEDELTA 0
|
||||
|
||||
/** @} */
|
||||
|
||||
|
@ -138,7 +140,7 @@
|
|||
*
|
||||
* @note The default is @p TRUE.
|
||||
*/
|
||||
#define CH_CFG_USE_TM TRUE
|
||||
#define CH_CFG_USE_TM FALSE
|
||||
|
||||
/**
|
||||
* @brief Threads registry APIs.
|
||||
|
@ -190,6 +192,7 @@
|
|||
* memory footprint.
|
||||
*
|
||||
* @note The default is @p FALSE.
|
||||
* @note Requires @p CH_CFG_USE_MUTEXES.
|
||||
*/
|
||||
#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE
|
||||
|
||||
|
@ -333,7 +336,7 @@
|
|||
*
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#define CH_DBG_SYSTEM_STATE_CHECK FALSE
|
||||
#define CH_DBG_SYSTEM_STATE_CHECK TRUE
|
||||
|
||||
/**
|
||||
* @brief Debug option, parameters checks.
|
||||
|
@ -342,7 +345,7 @@
|
|||
*
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#define CH_DBG_ENABLE_CHECKS FALSE
|
||||
#define CH_DBG_ENABLE_CHECKS TRUE
|
||||
|
||||
/**
|
||||
* @brief Debug option, consistency checks.
|
||||
|
@ -352,16 +355,23 @@
|
|||
*
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#define CH_DBG_ENABLE_ASSERTS FALSE
|
||||
#define CH_DBG_ENABLE_ASSERTS TRUE
|
||||
|
||||
/**
|
||||
* @brief Debug option, trace buffer.
|
||||
* @details If enabled then the context switch circular trace buffer is
|
||||
* activated.
|
||||
*
|
||||
* @note The default is @p FALSE.
|
||||
* @note The default is @p CH_DBG_TRACE_MASK_NONE.
|
||||
*/
|
||||
#define CH_DBG_ENABLE_TRACE FALSE
|
||||
#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_ALL
|
||||
|
||||
/**
|
||||
* @brief Trace buffer entries.
|
||||
* @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is
|
||||
* different from @p CH_DBG_TRACE_MASK_NONE.
|
||||
*/
|
||||
#define CH_DBG_TRACE_BUFFER_SIZE 128
|
||||
|
||||
/**
|
||||
* @brief Debug option, stack checks.
|
||||
|
@ -373,7 +383,7 @@
|
|||
* @note The default failure mode is to halt the system with the global
|
||||
* @p panic_msg variable set to @p NULL.
|
||||
*/
|
||||
#define CH_DBG_ENABLE_STACK_CHECK FALSE
|
||||
#define CH_DBG_ENABLE_STACK_CHECK TRUE
|
||||
|
||||
/**
|
||||
* @brief Debug option, stacks initialization.
|
||||
|
@ -383,7 +393,7 @@
|
|||
*
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#define CH_DBG_FILL_THREADS FALSE
|
||||
#define CH_DBG_FILL_THREADS TRUE
|
||||
|
||||
/**
|
||||
* @brief Debug option, threads profiling.
|
||||
|
@ -426,10 +436,6 @@
|
|||
/**
|
||||
* @brief Threads finalization hook.
|
||||
* @details User finalization code added to the @p chThdExit() API.
|
||||
*
|
||||
* @note It is inserted into lock zone.
|
||||
* @note It is also invoked when the threads simply return in order to
|
||||
* terminate.
|
||||
*/
|
||||
#define CH_CFG_THREAD_EXIT_HOOK(tp) { \
|
||||
/* Add threads finalization code here.*/ \
|
||||
|
@ -443,6 +449,20 @@
|
|||
/* Context switch code here.*/ \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ISR enter hook.
|
||||
*/
|
||||
#define CH_CFG_IRQ_PROLOGUE_HOOK() { \
|
||||
/* IRQ prologue code here.*/ \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ISR exit hook.
|
||||
*/
|
||||
#define CH_CFG_IRQ_EPILOGUE_HOOK() { \
|
||||
/* IRQ epilogue code here.*/ \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Idle thread enter hook.
|
||||
* @note This hook is invoked within a critical zone, no OS functions
|
||||
|
@ -450,6 +470,7 @@
|
|||
* @note This macro can be used to activate a power saving mode.
|
||||
*/
|
||||
#define CH_CFG_IDLE_ENTER_HOOK() { \
|
||||
/* Idle-enter code here.*/ \
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -459,6 +480,7 @@
|
|||
* @note This macro can be used to deactivate a power saving mode.
|
||||
*/
|
||||
#define CH_CFG_IDLE_LEAVE_HOOK() { \
|
||||
/* Idle-leave code here.*/ \
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -487,6 +509,15 @@
|
|||
/* System halt code here.*/ \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Trace hook.
|
||||
* @details This hook is invoked each time a new record is written in the
|
||||
* trace buffer.
|
||||
*/
|
||||
#define CH_CFG_TRACE_HOOK(tep) { \
|
||||
/* Trace code here.*/ \
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file templates/chcore.c
|
||||
* @brief Port related template code.
|
||||
* @details This file is a template of the system driver functions provided by
|
||||
* a port. Some of the following functions may be implemented as
|
||||
* macros in chcore.h if the implementer decides that there is an
|
||||
* advantage in doing so, for example because performance concerns.
|
||||
*
|
||||
* @addtogroup core
|
||||
* @details Non portable code templates.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Port-related initialization code.
|
||||
* @note This function is usually empty.
|
||||
*/
|
||||
void _port_init(void) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs a context switch between two threads.
|
||||
* @details This is the most critical code in any port, this function
|
||||
* is responsible for the context switch between 2 threads.
|
||||
* @note The implementation of this code affects <b>directly</b> the context
|
||||
* switch performance so optimize here as much as you can.
|
||||
*
|
||||
* @param[in] ntp the thread to be switched in
|
||||
* @param[in] otp the thread to be switched out
|
||||
*/
|
||||
void _port_switch(thread_t *ntp, thread_t *otp) {
|
||||
}
|
||||
|
||||
/** @} */
|
|
@ -1,412 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file templates/chcore.h
|
||||
* @brief Port related template macros and structures.
|
||||
* @details This file is a template of the system driver macros provided by
|
||||
* a port.
|
||||
*
|
||||
* @addtogroup core
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHCORE_H_
|
||||
#define _CHCORE_H_
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Architecture and Compiler
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Macro defining an XXX architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_XXX
|
||||
|
||||
/**
|
||||
* @brief Macro defining the specific XXX architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_XXX_YYY
|
||||
|
||||
/**
|
||||
* @brief Name of the implemented architecture.
|
||||
*/
|
||||
#define PORT_ARCHITECTURE_NAME "XXX Architecture"
|
||||
|
||||
/**
|
||||
* @brief Compiler name and version.
|
||||
*/
|
||||
#if defined(__GNUC__) || defined(__DOXYGEN__)
|
||||
#define PORT_COMPILER_NAME "GCC " __VERSION__
|
||||
|
||||
#else
|
||||
#error "unsupported compiler"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief This port supports a realtime counter.
|
||||
*/
|
||||
#define PORT_SUPPORTS_RT FALSE
|
||||
|
||||
/**
|
||||
* @brief Port-specific information string.
|
||||
*/
|
||||
#define PORT_INFO "no info"
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Stack size for the system idle thread.
|
||||
* @details This size depends on the idle thread implementation, usually
|
||||
* the idle thread should take no more space than those reserved
|
||||
* by @p PORT_INT_REQUIRED_STACK.
|
||||
*/
|
||||
#if !defined(PORT_IDLE_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
|
||||
#define PORT_IDLE_THREAD_STACK_SIZE 32
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Per-thread stack overhead for interrupts servicing.
|
||||
* @details This constant is used in the calculation of the correct working
|
||||
* area size.
|
||||
*/
|
||||
#if !defined(PORT_INT_REQUIRED_STACK) || defined(__DOXYGEN__)
|
||||
#define PORT_INT_REQUIRED_STACK 256
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enables an alternative timer implementation.
|
||||
* @details Usually the port uses a timer interface defined in the file
|
||||
* @p chcore_timer.h, if this option is enabled then the file
|
||||
* @p chcore_timer_alt.h is included instead.
|
||||
*/
|
||||
#if !defined(PORT_USE_ALT_TIMER)
|
||||
#define PORT_USE_ALT_TIMER FALSE
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
/**
|
||||
* @brief Type of stack and memory alignment enforcement.
|
||||
* @note In this architecture the stack alignment is enforced to 64 bits.
|
||||
*/
|
||||
typedef uint64_t stkalign_t;
|
||||
|
||||
/**
|
||||
* @brief Interrupt saved context.
|
||||
* @details This structure represents the stack frame saved during a
|
||||
* preemption-capable interrupt handler.
|
||||
* @note R2 and R13 are not saved because those are assumed to be immutable
|
||||
* during the system life cycle.
|
||||
*/
|
||||
struct port_extctx {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief System saved context.
|
||||
* @details This structure represents the inner stack frame during a context
|
||||
* switching.
|
||||
* @note R2 and R13 are not saved because those are assumed to be immutable
|
||||
* during the system life cycle.
|
||||
* @note LR is stored in the caller context so it is not present in this
|
||||
* structure.
|
||||
*/
|
||||
struct port_intctx {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p thread_t structure.
|
||||
* @details This structure usually contains just the saved stack pointer
|
||||
* defined as a pointer to a @p port_intctx structure.
|
||||
*/
|
||||
struct context {
|
||||
struct port_intctx *sp;
|
||||
};
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Platform dependent part of the @p chThdCreateI() API.
|
||||
* @details This code usually setup the context switching frame represented
|
||||
* by an @p port_intctx structure.
|
||||
*/
|
||||
#define PORT_SETUP_CONTEXT(tp, workspace, wsize, pf, arg) { \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the thread working area global size.
|
||||
* @note There is no need to perform alignments in this macro.
|
||||
*/
|
||||
#define PORT_WA_SIZE(n) (sizeof(struct port_intctx) + \
|
||||
sizeof(struct port_extctx) + \
|
||||
((size_t)(n)) + ((size_t)(PORT_INT_REQUIRED_STACK)))
|
||||
|
||||
/**
|
||||
* @brief Priority level verification macro.
|
||||
*/
|
||||
#define PORT_IRQ_IS_VALID_PRIORITY(n) false
|
||||
|
||||
/**
|
||||
* @brief Priority level verification macro.
|
||||
*/
|
||||
#define PORT_IRQ_IS_VALID_KERNEL_PRIORITY(n) false
|
||||
|
||||
/**
|
||||
* @brief IRQ prologue code.
|
||||
* @details This macro must be inserted at the start of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#define PORT_IRQ_PROLOGUE()
|
||||
|
||||
/**
|
||||
* @brief IRQ epilogue code.
|
||||
* @details This macro must be inserted at the end of all IRQ handlers
|
||||
* enabled to invoke system APIs.
|
||||
*/
|
||||
#define PORT_IRQ_EPILOGUE()
|
||||
|
||||
/**
|
||||
* @brief IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_IRQ_HANDLER(id) void id(void)
|
||||
|
||||
/**
|
||||
* @brief Fast IRQ handler function declaration.
|
||||
* @note @p id can be a function name or a vector number depending on the
|
||||
* port implementation.
|
||||
*/
|
||||
#define PORT_FAST_IRQ_HANDLER(id) void id(void)
|
||||
|
||||
/**
|
||||
* @brief Performs a context switch between two threads.
|
||||
* @details This is the most critical code in any port, this function
|
||||
* is responsible for the context switch between 2 threads.
|
||||
* @note The implementation of this code affects <b>directly</b> the context
|
||||
* switch performance so optimize here as much as you can.
|
||||
*
|
||||
* @param[in] ntp the thread to be switched in
|
||||
* @param[in] otp the thread to be switched out
|
||||
*/
|
||||
#if !CH_DBG_ENABLE_STACK_CHECK || defined(__DOXYGEN__)
|
||||
#define port_switch(ntp, otp) _port_switch(ntp, otp)
|
||||
#else
|
||||
#define port_switch(ntp, otp) { \
|
||||
register struct port_intctx *sp asm ("%r1"); \
|
||||
if ((stkalign_t *)(sp - 1) < otp->p_stklimit) \
|
||||
chSysHalt("stack overflow"); \
|
||||
_port_switch(ntp, otp); \
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void _port_init(void);
|
||||
void _port_switch(thread_t *ntp, thread_t *otp);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module inline functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
/**
|
||||
* @brief Returns a word encoding the current interrupts status.
|
||||
*
|
||||
* @return The interrupts status.
|
||||
*/
|
||||
static inline syssts_t port_get_irq_status(void) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks the interrupt status.
|
||||
*
|
||||
* @param[in] sts the interrupt status word
|
||||
*
|
||||
* @return The interrupt status.
|
||||
* @retval false the word specified a disabled interrupts status.
|
||||
* @retval true the word specified an enabled interrupts status.
|
||||
*/
|
||||
static inline bool port_irq_enabled(syssts_t sts) {
|
||||
|
||||
(void)sts;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines the current execution context.
|
||||
*
|
||||
* @return The execution context.
|
||||
* @retval false not running in ISR mode.
|
||||
* @retval true running in ISR mode.
|
||||
*/
|
||||
static inline bool port_is_isr_context(void) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action.
|
||||
* @details Usually this function just disables interrupts but may perform more
|
||||
* actions.
|
||||
*/
|
||||
static inline void port_lock(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action.
|
||||
* @details Usually this function just enables interrupts but may perform more
|
||||
* actions.
|
||||
*/
|
||||
static inline void port_unlock(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-lock action from an interrupt handler.
|
||||
* @details This function is invoked before invoking I-class APIs from
|
||||
* interrupt handlers. The implementation is architecture dependent,
|
||||
* in its simplest form it is void.
|
||||
*/
|
||||
static inline void port_lock_from_isr(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Kernel-unlock action from an interrupt handler.
|
||||
* @details This function is invoked after invoking I-class APIs from interrupt
|
||||
* handlers. The implementation is architecture dependent, in its
|
||||
* simplest form it is void.
|
||||
*/
|
||||
static inline void port_unlock_from_isr(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables all the interrupt sources.
|
||||
* @note Of course non-maskable interrupt sources are not included.
|
||||
*/
|
||||
static inline void port_disable(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables the interrupt sources below kernel-level priority.
|
||||
* @note Interrupt sources above kernel level remains enabled.
|
||||
*/
|
||||
static inline void port_suspend(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables all the interrupt sources.
|
||||
*/
|
||||
static inline void port_enable(void) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enters an architecture-dependent IRQ-waiting mode.
|
||||
* @details The function is meant to return when an interrupt becomes pending.
|
||||
* The simplest implementation is an empty function or macro but this
|
||||
* would not take advantage of architecture-specific power saving
|
||||
* modes.
|
||||
*/
|
||||
static inline void port_wait_for_interrupt(void) {
|
||||
|
||||
#if PPC_ENABLE_WFI_IDLE
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current value of the realtime counter.
|
||||
*
|
||||
* @return The realtime counter value.
|
||||
*/
|
||||
static inline rtcnt_t port_rt_get_counter_value(void) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Module late inclusions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/* The following code is not processed when the file is included from an
|
||||
asm module.*/
|
||||
#if !defined(_FROM_ASM_)
|
||||
|
||||
#if CH_CFG_ST_TIMEDELTA > 0
|
||||
#if !PORT_USE_ALT_TIMER
|
||||
#include "chcore_timer.h"
|
||||
#else /* PORT_USE_ALT_TIMER */
|
||||
#include "chcore_timer_alt.h"
|
||||
#endif /* PORT_USE_ALT_TIMER */
|
||||
#endif /* CH_CFG_ST_TIMEDELTA > 0 */
|
||||
|
||||
#endif /* !defined(_FROM_ASM_) */
|
||||
|
||||
#endif /* _CHCORE_H_ */
|
||||
|
||||
/** @} */
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio.
|
||||
|
||||
This file is part of ChibiOS.
|
||||
|
||||
ChibiOS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ChibiOS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file templates/chtypes.h
|
||||
* @brief System types template.
|
||||
* @details The types defined in this file may change depending on the target
|
||||
* architecture. You may also try to optimize the size of the various
|
||||
* types in order to privilege size or performance, be careful in
|
||||
* doing so.
|
||||
*
|
||||
* @addtogroup types
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _CHTYPES_H_
|
||||
#define _CHTYPES_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @name Common constants
|
||||
*/
|
||||
/**
|
||||
* @brief Generic 'false' boolean constant.
|
||||
*/
|
||||
#if !defined(FALSE) || defined(__DOXYGEN__)
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Generic 'true' boolean constant.
|
||||
*/
|
||||
#if !defined(TRUE) || defined(__DOXYGEN__)
|
||||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Kernel types
|
||||
* @{
|
||||
*/
|
||||
typedef uint32_t rtcnt_t; /**< Realtime counter. */
|
||||
typedef uint64_t rttime_t; /**< Realtime accumulator. */
|
||||
typedef uint32_t syssts_t; /**< System status word. */
|
||||
typedef uint8_t tmode_t; /**< Thread flags. */
|
||||
typedef uint8_t tstate_t; /**< Thread state. */
|
||||
typedef uint8_t trefs_t; /**< Thread references counter. */
|
||||
typedef uint8_t tslices_t; /**< Thread time slices counter.*/
|
||||
typedef uint32_t tprio_t; /**< Thread priority. */
|
||||
typedef int32_t msg_t; /**< Inter-thread message. */
|
||||
typedef int32_t eventid_t; /**< Numeric event identifier. */
|
||||
typedef uint32_t eventmask_t; /**< Mask of event identifiers. */
|
||||
typedef uint32_t eventflags_t; /**< Mask of event flags. */
|
||||
typedef int32_t cnt_t; /**< Generic signed counter. */
|
||||
typedef uint32_t ucnt_t; /**< Generic unsigned counter. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief ROM constant modifier.
|
||||
* @note It is set to use the "const" keyword in this port.
|
||||
*/
|
||||
#define ROMCONST const
|
||||
|
||||
/**
|
||||
* @brief Makes functions not inlineable.
|
||||
* @note If the compiler does not support such attribute then the
|
||||
* realtime counter precision could be degraded.
|
||||
*/
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
|
||||
/**
|
||||
* @brief Optimized thread function declaration macro.
|
||||
*/
|
||||
#define PORT_THD_FUNCTION(tname, arg) msg_t tname(void *arg)
|
||||
|
||||
/**
|
||||
* @brief Packed variable specifier.
|
||||
*/
|
||||
#define PACKED_VAR __attribute__((packed))
|
||||
|
||||
#endif /* _CHTYPES_H_ */
|
||||
|
||||
/** @} */
|
|
@ -51,7 +51,7 @@ thread_reference_t gtr1;
|
|||
*/
|
||||
THD_WORKING_AREA(wa_test_support, 128);
|
||||
THD_FUNCTION(test_support, arg) {
|
||||
#if NIL_CFG_USE_EVENTS == TRUE
|
||||
#if CH_CFG_USE_EVENTS == TRUE
|
||||
thread_t *tp = (thread_t *)arg;
|
||||
#else
|
||||
(void)arg;
|
||||
|
@ -68,7 +68,7 @@ THD_FUNCTION(test_support, arg) {
|
|||
chSemSignalI(&gsem1);
|
||||
chSemResetI(&gsem2, 0);
|
||||
chThdResumeI(>r1, MSG_OK);
|
||||
#if NIL_CFG_USE_EVENTS == TRUE
|
||||
#if CH_CFG_USE_EVENTS == TRUE
|
||||
chEvtSignalI(tp, 0x55);
|
||||
#endif
|
||||
chSchRescheduleS();
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#ifndef _TEST_ROOT_H_
|
||||
#define _TEST_ROOT_H_
|
||||
|
||||
#include "nil.h"
|
||||
#include "ch.h"
|
||||
|
||||
#include "test_sequence_001.h"
|
||||
#include "test_sequence_002.h"
|
||||
|
|
|
@ -327,7 +327,7 @@ static const testcase_t test_002_004 = {
|
|||
};
|
||||
#endif /* TRUE */
|
||||
|
||||
#if (NIL_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @page test_002_005 Events functionality
|
||||
*
|
||||
|
@ -408,7 +408,7 @@ static const testcase_t test_002_005 = {
|
|||
NULL,
|
||||
test_002_005_execute
|
||||
};
|
||||
#endif /* NIL_CFG_USE_EVENTS == TRUE */
|
||||
#endif /* CH_CFG_USE_EVENTS == TRUE */
|
||||
|
||||
/****************************************************************************
|
||||
* Exported data.
|
||||
|
@ -430,7 +430,7 @@ const testcase_t * const test_sequence_002[] = {
|
|||
#if TRUE || defined(__DOXYGEN__)
|
||||
&test_002_004,
|
||||
#endif
|
||||
#if (NIL_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
||||
#if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__)
|
||||
&test_002_005,
|
||||
#endif
|
||||
NULL
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "testevt.h"
|
||||
#include "testheap.h"
|
||||
#include "testpools.h"
|
||||
#include "testdyn.h"
|
||||
#include "testqueues.h"
|
||||
#include "testbmk.h"
|
||||
|
||||
|
@ -52,7 +51,6 @@ static ROMCONST struct testcase * ROMCONST *patterns[] = {
|
|||
patternevt,
|
||||
patternheap,
|
||||
patternpools,
|
||||
patterndyn,
|
||||
patternqueues,
|
||||
patternbmk,
|
||||
NULL
|
||||
|
@ -193,17 +191,6 @@ bool _test_assert_time_window(unsigned point, systime_t start, systime_t end) {
|
|||
* Threads utils.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Sets a termination request in all the test-spawned threads.
|
||||
*/
|
||||
void test_terminate_threads(void) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_THREADS; i++)
|
||||
if (threads[i])
|
||||
chThdTerminate(threads[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits for the completion of all the test-spawned threads.
|
||||
*/
|
||||
|
|
|
@ -90,7 +90,6 @@ extern "C" {
|
|||
bool _test_assert(unsigned point, bool condition);
|
||||
bool _test_assert_sequence(unsigned point, char *expected);
|
||||
bool _test_assert_time_window(unsigned point, systime_t start, systime_t end);
|
||||
void test_terminate_threads(void);
|
||||
void test_wait_threads(void);
|
||||
systime_t test_wait_tick(void);
|
||||
void test_start_timer(unsigned ms);
|
||||
|
|
|
@ -8,7 +8,6 @@ TESTSRC = ${CHIBIOS}/test/rt/test.c \
|
|||
${CHIBIOS}/test/rt/testevt.c \
|
||||
${CHIBIOS}/test/rt/testheap.c \
|
||||
${CHIBIOS}/test/rt/testpools.c \
|
||||
${CHIBIOS}/test/rt/testdyn.c \
|
||||
${CHIBIOS}/test/rt/testqueues.c \
|
||||
${CHIBIOS}/test/rt/testsys.c \
|
||||
${CHIBIOS}/test/rt/testbmk.c
|
||||
|
|
|
@ -211,7 +211,7 @@ static THD_FUNCTION(thread4, p) {
|
|||
chSysLock();
|
||||
do {
|
||||
chSchGoSleepS(CH_STATE_SUSPENDED);
|
||||
msg = self->p_u.rdymsg;
|
||||
msg = self->u.rdymsg;
|
||||
} while (msg == MSG_OK);
|
||||
chSysUnlock();
|
||||
}
|
||||
|
@ -344,8 +344,7 @@ ROMCONST struct testcase testbmk6 = {
|
|||
|
||||
static THD_FUNCTION(thread3, p) {
|
||||
|
||||
(void)p;
|
||||
while (!chThdShouldTerminateX())
|
||||
while (!*(bool *)p)
|
||||
chSemWait(&sem1);
|
||||
}
|
||||
|
||||
|
@ -356,12 +355,13 @@ static void bmk7_setup(void) {
|
|||
|
||||
static void bmk7_execute(void) {
|
||||
uint32_t n;
|
||||
bool terminate = false;
|
||||
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread3, NULL);
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+4, thread3, NULL);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread3, NULL);
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+2, thread3, NULL);
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+1, thread3, NULL);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()+5, thread3, &terminate);
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()+4, thread3, &terminate);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()+3, thread3, &terminate);
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()+2, thread3, &terminate);
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()+1, thread3, &terminate);
|
||||
|
||||
n = 0;
|
||||
test_wait_tick();
|
||||
|
@ -373,7 +373,7 @@ static void bmk7_execute(void) {
|
|||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while (!test_timer_done);
|
||||
test_terminate_threads();
|
||||
terminate = true;
|
||||
chSemReset(&sem1, 0);
|
||||
test_wait_threads();
|
||||
|
||||
|
@ -401,39 +401,44 @@ ROMCONST struct testcase testbmk7 = {
|
|||
* The performance is calculated by measuring the number of iterations after
|
||||
* a second of continuous operations.
|
||||
*/
|
||||
typedef struct {
|
||||
bool terminate;
|
||||
uint32_t n;
|
||||
} params_t;
|
||||
|
||||
static THD_FUNCTION(thread8, p) {
|
||||
params_t *pp = (params_t *)p;
|
||||
|
||||
do {
|
||||
chThdYield();
|
||||
chThdYield();
|
||||
chThdYield();
|
||||
chThdYield();
|
||||
(*(uint32_t *)p) += 4;
|
||||
pp->n += 4;
|
||||
#if defined(SIMULATOR)
|
||||
_sim_check_for_interrupts();
|
||||
#endif
|
||||
} while(!chThdShouldTerminateX());
|
||||
} while (!pp->terminate);
|
||||
}
|
||||
|
||||
static void bmk8_execute(void) {
|
||||
uint32_t n;
|
||||
params_t params = {false, 0};
|
||||
|
||||
n = 0;
|
||||
params.n = 0;
|
||||
test_wait_tick();
|
||||
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n);
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n);
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n);
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)&n);
|
||||
threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)¶ms);
|
||||
threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)¶ms);
|
||||
threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)¶ms);
|
||||
threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)¶ms);
|
||||
threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriorityX()-1, thread8, (void *)¶ms);
|
||||
|
||||
chThdSleepSeconds(1);
|
||||
test_terminate_threads();
|
||||
params.terminate = true;
|
||||
test_wait_threads();
|
||||
|
||||
test_print("--- Score : ");
|
||||
test_printn(n);
|
||||
test_printn(params.n);
|
||||
test_println(" ctxswc/S");
|
||||
}
|
||||
|
||||
|
|
|
@ -81,10 +81,9 @@ static void dyn1_setup(void) {
|
|||
|
||||
static void dyn1_execute(void) {
|
||||
size_t n, sz;
|
||||
void *p1;
|
||||
tprio_t prio = chThdGetPriorityX();
|
||||
|
||||
(void)chHeapStatus(&heap1, &sz);
|
||||
(void)chHeapStatus(&heap1, &sz, NULL);
|
||||
/* Starting threads from the heap. */
|
||||
threads[0] = chThdCreateFromHeap(&heap1,
|
||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
|
||||
|
@ -92,13 +91,10 @@ static void dyn1_execute(void) {
|
|||
threads[1] = chThdCreateFromHeap(&heap1,
|
||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
|
||||
prio-2, thread, "B");
|
||||
/* Allocating the whole heap in order to make the thread creation fail.*/
|
||||
(void)chHeapStatus(&heap1, &n);
|
||||
p1 = chHeapAlloc(&heap1, n);
|
||||
/* Large working area in order to make the thread creation fail.*/
|
||||
threads[2] = chThdCreateFromHeap(&heap1,
|
||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE),
|
||||
THD_WORKING_AREA_SIZE(THREADS_STACK_SIZE * 16),
|
||||
prio-3, thread, "C");
|
||||
chHeapFree(p1);
|
||||
|
||||
test_assert(1, (threads[0] != NULL) &&
|
||||
(threads[1] != NULL) &&
|
||||
|
@ -112,7 +108,7 @@ static void dyn1_execute(void) {
|
|||
test_assert_sequence(2, "AB");
|
||||
|
||||
/* Heap status checked again.*/
|
||||
test_assert(3, chHeapStatus(&heap1, &n) == 1, "heap fragmented");
|
||||
test_assert(3, chHeapStatus(&heap1, &n, NULL) == 1, "heap fragmented");
|
||||
test_assert(4, n == sz, "heap size changed");
|
||||
}
|
||||
|
||||
|
@ -212,11 +208,11 @@ static void dyn3_execute(void) {
|
|||
|
||||
/* Testing references increase/decrease and final detach.*/
|
||||
tp = chThdCreateFromHeap(&heap1, WA_SIZE, prio-1, thread, "A");
|
||||
test_assert(1, tp->p_refs == 1, "wrong initial reference counter");
|
||||
test_assert(1, tp->refs == 1, "wrong initial reference counter");
|
||||
chThdAddRef(tp);
|
||||
test_assert(2, tp->p_refs == 2, "references increase failure");
|
||||
test_assert(2, tp->refs == 2, "references increase failure");
|
||||
chThdRelease(tp);
|
||||
test_assert(3, tp->p_refs == 1, "references decrease failure");
|
||||
test_assert(3, tp->refs == 1, "references decrease failure");
|
||||
|
||||
/* Verify the new threads count.*/
|
||||
test_assert(4, regfind(tp), "thread missing from registry");
|
||||
|
@ -224,12 +220,12 @@ static void dyn3_execute(void) {
|
|||
|
||||
/* Detach and let the thread execute and terminate.*/
|
||||
chThdRelease(tp);
|
||||
test_assert(6, tp->p_refs == 0, "detach failure");
|
||||
test_assert(7, tp->p_state == CH_STATE_READY, "invalid state");
|
||||
test_assert(6, tp->refs == 0, "detach failure");
|
||||
test_assert(7, tp->state == CH_STATE_READY, "invalid state");
|
||||
test_assert(8, regfind(tp), "thread disappeared");
|
||||
test_assert(9, regfind(tp), "thread disappeared");
|
||||
chThdSleepMilliseconds(50); /* The thread just terminates. */
|
||||
test_assert(10, tp->p_state == CH_STATE_FINAL, "invalid state");
|
||||
test_assert(10, tp->state == CH_STATE_FINAL, "invalid state");
|
||||
|
||||
/* Clearing the zombie by scanning the registry.*/
|
||||
test_assert(11, regfind(tp), "thread disappeared");
|
||||
|
|
|
@ -77,7 +77,7 @@ static void heap1_execute(void) {
|
|||
* Test on the default heap in order to cover the core allocator at
|
||||
* least one time.
|
||||
*/
|
||||
(void)chHeapStatus(NULL, &sz);
|
||||
(void)chHeapStatus(NULL, &sz, NULL);
|
||||
p1 = chHeapAlloc(NULL, SIZE);
|
||||
test_assert(1, p1 != NULL, "allocation failed");
|
||||
chHeapFree(p1);
|
||||
|
@ -85,7 +85,7 @@ static void heap1_execute(void) {
|
|||
test_assert(2, p1 == NULL, "allocation not failed");
|
||||
|
||||
/* Initial local heap state.*/
|
||||
(void)chHeapStatus(&test_heap, &sz);
|
||||
(void)chHeapStatus(&test_heap, &sz, NULL);
|
||||
|
||||
/* Same order.*/
|
||||
p1 = chHeapAlloc(&test_heap, SIZE);
|
||||
|
@ -94,7 +94,7 @@ static void heap1_execute(void) {
|
|||
chHeapFree(p1); /* Does not merge.*/
|
||||
chHeapFree(p2); /* Merges backward.*/
|
||||
chHeapFree(p3); /* Merges both sides.*/
|
||||
test_assert(3, chHeapStatus(&test_heap, &n) == 1, "heap fragmented");
|
||||
test_assert(3, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
|
||||
/* Reverse order.*/
|
||||
p1 = chHeapAlloc(&test_heap, SIZE);
|
||||
|
@ -103,39 +103,39 @@ static void heap1_execute(void) {
|
|||
chHeapFree(p3); /* Merges forward.*/
|
||||
chHeapFree(p2); /* Merges forward.*/
|
||||
chHeapFree(p1); /* Merges forward.*/
|
||||
test_assert(4, chHeapStatus(&test_heap, &n) == 1, "heap fragmented");
|
||||
test_assert(4, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
|
||||
/* Small fragments handling.*/
|
||||
p1 = chHeapAlloc(&test_heap, SIZE + 1);
|
||||
p2 = chHeapAlloc(&test_heap, SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert(5, chHeapStatus(&test_heap, &n) == 2, "invalid state");
|
||||
test_assert(5, chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
|
||||
p1 = chHeapAlloc(&test_heap, SIZE);
|
||||
/* Note, the first situation happens when the alignment size is smaller
|
||||
than the header size, the second in the other cases.*/
|
||||
test_assert(6, (chHeapStatus(&test_heap, &n) == 1) ||
|
||||
(chHeapStatus(&test_heap, &n) == 2), "heap fragmented");
|
||||
test_assert(6, (chHeapStatus(&test_heap, &n, NULL) == 1) ||
|
||||
(chHeapStatus(&test_heap, &n, NULL) == 2), "heap fragmented");
|
||||
chHeapFree(p2);
|
||||
chHeapFree(p1);
|
||||
test_assert(7, chHeapStatus(&test_heap, &n) == 1, "heap fragmented");
|
||||
test_assert(7, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
|
||||
/* Skip fragment handling.*/
|
||||
p1 = chHeapAlloc(&test_heap, SIZE);
|
||||
p2 = chHeapAlloc(&test_heap, SIZE);
|
||||
chHeapFree(p1);
|
||||
test_assert(8, chHeapStatus(&test_heap, &n) == 2, "invalid state");
|
||||
test_assert(8, chHeapStatus(&test_heap, &n, NULL) == 2, "invalid state");
|
||||
p1 = chHeapAlloc(&test_heap, SIZE * 2); /* Skips first fragment.*/
|
||||
chHeapFree(p1);
|
||||
chHeapFree(p2);
|
||||
test_assert(9, chHeapStatus(&test_heap, &n) == 1, "heap fragmented");
|
||||
test_assert(9, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
|
||||
/* Allocate all handling.*/
|
||||
(void)chHeapStatus(&test_heap, &n);
|
||||
(void)chHeapStatus(&test_heap, &n, NULL);
|
||||
p1 = chHeapAlloc(&test_heap, n);
|
||||
test_assert(10, chHeapStatus(&test_heap, &n) == 0, "not empty");
|
||||
test_assert(10, chHeapStatus(&test_heap, &n, NULL) == 0, "not empty");
|
||||
chHeapFree(p1);
|
||||
|
||||
test_assert(11, chHeapStatus(&test_heap, &n) == 1, "heap fragmented");
|
||||
test_assert(11, chHeapStatus(&test_heap, &n, NULL) == 1, "heap fragmented");
|
||||
test_assert(12, n == sz, "size changed");
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue