Цитата(_lexa_ @ Jun 4 2017, 21:14)

Интерес есть. Кидайте.
Обработчик прерывания SVC выглядит у меня следующим образом. Много подсмотрено по ссылкам, указанным в комментариях.
Код
// ---------------------------------------------------------------------------
//
// SVC_Handler used for "atomic" operations based on the the fact, that
// SVC handler cannot be interrupted by higher placed interrupts.
//
// Upon call to SVC vector the stack holds saved register:
// xPSR 0x1C (7)
// PC 0x18 (6)
// R14(LR) 0x14 (5)
// R12 0x10 (4)
// R3 0x0C (3)
// R2 0x08 (2)
// R1 0x04 (1)
// [SP]-> R0 0x00 (0)
//
// The registers will be restored upon leaving the handler. The handler
// to return a result, a value in the stack must be modified.
//
// Via stacked R0..R3 the parameters can be passed through to the
// handler. For this purpose the definition of the user SVC call can
// be done as (the type 'int' is for example):
//
// __svc(n) myfunc(int [,int, int, int]);
//
// See Chapter 6.19, Figure 6.5 in:
// http://infocenter.arm.com/help/topic/com.arm.doc.dui0471c/ \
// DUI0471C_developing_for_arm_processors.pdf
//
// and
//
// http://www.mikrocontroller.net/topic/295183
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471j/pge1358787038365.html
// http://sites.fas.harvard.edu/~libe251/spring2014/CauseOfDefaultISR.txt
//
// To PRESERVE8 for stack 8 bytes alignment see
// http://infocenter.arm.com/help/topic/com.arm.doc.faqs/ka4127.html
//
__asm
void SVC_Handler(void) {
PRESERVE8
EXPORT SVC_Handler
; get the pointer to the saved R0-R3 to pass it
; to SVC_Dispatcher() as the second parameter
; (via R1):
#ifdef SVC_OS_MODE
TST LR, #4 ; kernel mode?
ITE EQ
MRSEQ R1, MSP ; kernel stack
MRSNE R1, PSP ; user stack
; get SVC n instruction code field and
; pass it to SVC_Dispatcher() as the first
; parameter (via R0):
LDR R0, [R1, #6*4] ; PC
#if defined(__CORE_CM0_H_GENERIC) || defined(__CORE_CM0PLUS_H_GENERIC)
SUBS R0, R0, #2
LDRB R0, [R0, #0] ; SVC OPCODE low byte
#else
LDRB R0, [R0, #-2] ; SVC OPCODE low byte
#endif
PUSH {LR, R1}
EXTERN SVC_Dispatcher
BL SVC_Dispatcher ; return value in R0
POP {R1}
; return the result in R0 via stacked R0:
STR R0, [R1]
#else
MOV R1, SP ; kernel=user stack (no OS)
; get SVC n instruction code field and
; pass it to SVC_Dispatcher() as the first
; parameter (via R0):
LDR R0, [R1, #6*4] ; PC
#if defined(__CORE_CM0_H_GENERIC) || defined(__CORE_CM0PLUS_H_GENERIC)
SUBS R0, R0, #2
LDRB R0, [R0, #0] ; SVC OPCODE low byte M0/M0+
#else
LDRB R0, [R0, #-2] ; SVC OPCODE low byte M3 and higher
#endif
PUSH {LR} ; preserve return address
EXTERN SVC_Dispatcher
BL SVC_Dispatcher ; return value in R0
; return the result in R0 via stacked R0:
STR R0, [SP, #4] ; #4 to skip LR in the stack
#endif
POP {PC} ; exit by LR
}
//------------------------------------------------------------------------------
Если исключить условные трансляции, которые разбирают варианты под OS, а также оставить универсальный вариант, работающий и на -M0 (не поддерживающих отрицательные смещения), то обработчик упростится для исполнения и понимания:
Код
__asm
void SVC_Handler(void) {
PRESERVE8
EXPORT SVC_Handler
; get the pointer to the saved R0-R3 to pass it
; to SVC_Dispatcher() as the second parameter
; (via R1):
MOV R1, SP ; kernel=user stack (no OS)
; get SVC n instruction code field and
; pass it to SVC_Dispatcher() as the first
; parameter (via R0):
LDR R0, [R1, #6*4] ; PC
SUBS R0, R0, #2
LDRB R0, [R0, #0] ; SVC OPCODE low byte M0/M0+
PUSH {LR} ; preserve return address
EXTERN SVC_Dispatcher
BL SVC_Dispatcher ; return value in R0
; return the result in R0 via stacked R0:
STR R0, [SP, #4] ; #4 to skip LR in the stack
POP {PC} ; exit by LR
}
//------------------------------------------------------------------------------
Как видно, все готовилось для вызова C-шной процедуры-обработчика ниже. Я выбросил многие мои специфические ветви, оставив те, что иллюстрируют идею:
Код
uint32_t SVC_Dispatcher(int svc, SVC_Param_TypeDef *ptr)
{
uint32_t res = UINT32_MAX;
switch (svc) {
case _SVC_ATOMIC_FLAG8: // atomic clear of an U8 flag
res = *(uint8_t *)ptr->R0; // return the last state
*(uint8_t *)ptr->R0 = 0; // clear it
break;
case _SVC_ATOMIC_FLAG16: // atomic clear of an U16 flag
res = *(uint16_t *)ptr->R0; // return the last state
*(uint16_t *)ptr->R0 = 0; // clear it
break;
case _SVC_ATOMIC_ADD32: // atomic add 32
res =
*(uint32_t *)ptr->R0 += (int32_t)ptr->R1;
break;
case _SVC_ATOMIC_DEC8:
res = *(uint8_t *)ptr->R0;
if (res)
{
*(uint8_t *)ptr->R0 = --res;
}
break;
case _SVC_MUTEX8: // mutex in an U8 variable
res = !(*(uint8_t *)ptr->R0); // current mutex state
*(uint8_t *)ptr->R0 = ptr->R1; // set the value
break;
}
return res;
}
К этому пристегивается заголовок (существенный фрагмент):
Код
typedef struct svc_params_s {
uint32_t R0, R1, R2, R3;
} SVC_Param_TypeDef;
#define _SVC_GETSYSCLOCKVALUE 4
#define _SVC_ATOMIC_FLAG8 8
#define _SVC_ATOMIC_FLAG16 9
#define _SVC_ATOMIC_FLAG32 10
#define _SVC_ATOMIC_ADD8 11
#define _SVC_ATOMIC_ADD16 12
#define _SVC_ATOMIC_ADD32 13
#define _SVC_ATOMIC_DEC8 14
#define _SVC_MUTEX8 16
#define _SVC_ATOMIC_SET8 21
#define _SVC_ATOMIC_SET16 22
#define _SVC_ATOMIC_SET32 23
#define _SVC_CALL_ME_PAR 25
//------------------------------------------------------------------------------
//
// Clears an U8 flag pointed by 'pflag' but returns its latest value.
//
uint8_t __svc(_SVC_ATOMIC_FLAG8) Atomic_Flag8(uint8_t *pflag);
//------------------------------------------------------------------------------
//
// Adds an I32 value to the value pointed by 'pvalue' and returns the result
//
uint32_t __svc(_SVC_ATOMIC_ADD32) Atomic_Add32(uint32_t *pvalue, int32_t val);
//------------------------------------------------------------------------------
//
// Decrements a non zero value pointed by 'pvalue' and returns the result
//
uint8_t __svc(_SVC_ATOMIC_DEC8) Atomic_Dec8(uint8_t *pvalue);
//------------------------------------------------------------------------------
//
// Sets the mutex ('setit'=true) pointed by 'pflag' and returns true if success.
// Otherwise the mutex has been busy.
//
// Clears ('setit'=false) the mutex unconditionally. It's up to the user to take
// care, if the mutex is allowed to be cleared. The return result to be ignored.
//
// NOTE: THE MUTEX VALUE AND THE SETIT PARAMETER ARE EXPECTED TO BE ONLY 0 OR 1.
// NO OTHER VALUES ARE ALLOWED, SHOULD FOR INSTANCE THE MUTEX VARIABLE BE
// CHANGED ELSEWHERE.
//
int __svc(_SVC_MUTEX8) Mutex8(uint8_t *pflag, uint8_t setit);
//------------------------------------------------------------------------------
extern uint32_t SVC_Dispatcher(int svc, SVC_Param_TypeDef *ptr);
Теперь о вызове на примере флага:
Код
uint8_t sb = Atomic_Flag8(&flag); // atomic reset
if (sb) {
// ...
}
Там для некой переменной uint8_t flag, которая устанавливается в прерывании, функция возвращает мне последнее состояние флага и сбрасывает его. Благодаря непрерываемости SVC операция по сбросу флага является атомарной.