|
Критическия секция, оцените и выскажите своё мнение |
|
|
|
Dec 12 2007, 12:13
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
sam7x + arm-elf-gcc Решил этот вопрос вынести в отдельную тему. По совету Сергея Борща переделал критические секция из FreeRTOS для себя. Так как переделовать пришлось код на асме, а в асме я позорно слаб, поэтому просьба покритиковать если что. На какие вещи опирался. Сделал дизасм своего проекта и увидел, что переменная переданная в функцию в конечном счёте оказывается в R0 до выполнения кода функции. Поэтому значение CSPR регистра я сохраняю и соответсвенно восстанавливаю по адресу хранящемуся в R0. И ещё меня смущает одна вещь, собрал проект с оптимизацией -Os. Естественно никакой передачи параметров в функцию нет, но указатель на переменную всё равно оказался в R0 Но в тоже время я вижу что SP и R0 имеют всегда одинаковое значение до начала выполнения тела функции. Верно ли моё наблюдение про R0. И если верно ли оно для оптимизированного кода. хидерник Код typedef uint32_t atomic_t;
void StartAtomic(atomic_t volatile *pAtomic);
void EndAtomic(atomic_t volatile *pAtomic);
#define ATOMIC_SECTION_ENTER {volatile atomic_t __atomic; StartAtomic(&__atomic); #define ATOMIC_SECTION_LEAVE EndAtomic(&__atomic);} сишник Код void StartAtomic(atomic_t volatile *pAtomic) { /* Disable interrupts as per portDISABLE_INTERRUPTS(); */ asm volatile ( "STMDB SP!, {R1} \n\t" /* Push R1. */ "MRS R1, CPSR \n\t" /* Get CPSR. */ "STR R1, [R0] \n\t" "ORR R1, R1, #0xC0 \n\t" /* Disable IRQ, FIQ. */ "MSR CPSR, R1 \n\t" /* Write back modified value. */ "LDMIA SP!, {R1}" ); /* Pop R1. */ }
void EndAtomic(atomic_t volatile *pAtomic) { asm volatile ( "STMDB SP!, {R1} \n\t" /* Push R1. */ "LDR R1, [R0] \n\t" "MSR CPSR, R1 \n\t" /* Write back modified value. */ "LDMIA SP!, {R1}" ); /* Pop R1. */ } З.Ы. Работает уже почти час. Пока живёт.
Сообщение отредактировал xelax - Dec 12 2007, 12:15
|
|
|
|
|
 |
Ответов
(1 - 8)
|
Dec 12 2007, 12:39
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
А почему бы не попросить StartAtomic возвращать предыдущее значение CPSR вместо запоминания его? И при выходе передавать не адрес, а само значение. Согласно APCS ( ARM Procedure Call Standart), значение интегрального типа возвращается в R0. К тому же функция должна сохранять только R4-R11, а R1 можно не сохранять. Код typedef uint32_t atomic_t; atomic_t volatile void StartAtomic(); void EndAtomic(atomic_t volatile Atomic); #define ATOMIC_SECTION_ENTER {volatile atomic_t __atomic = StartAtomic(); #define ATOMIC_SECTION_LEAVE EndAtomic(__atomic);} сишник Код atomic_t volatile StartAtomic() { /* Disable interrupts as per portDISABLE_INTERRUPTS(); */ asm volatile ( "STMDB SP!, {R1} \n\t" /* Push R1. */ "MRS R0, CPSR \n\t" /* Get CPSR. */ "ORR R1, R0, #0xC0 \n\t" /* Disable IRQ, FIQ. */ "MSR CPSR, R1 \n\t" /* Write back modified value. */ "LDMIA SP!, {R1}" ); /* Pop R1. */ }
void EndAtomic(atomic_t volatile Atomic) { asm volatile ( "STMDB SP!, {R1} \n\t" /* Push R1. */ "MSR CPSR, R1 \n\t" /* Write back modified value. */ "LDMIA SP!, {R1}" ); /* Pop R1. */ } Только замечу, что этот код портит все остальные флаги в CPSR, может вылезти в любой момент. Надо бы в сохраненном значении маскировать все флаги. Подумать, чтобы при выходе одной командой AND включались только нужные прерывания.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 12 2007, 13:01
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Цитата(Сергей Борщ @ Dec 12 2007, 15:39)  А почему бы не попросить StartAtomic возвращать предыдущее значение CPSR вместо запоминания его? И при выходе передавать не адрес, а само значение. Согласно APCS ( ARM Procedure Call Standart), значение интегрального типа возвращается в R0. К тому же функция должна сохранять только R4-R11, а R1 можно не сохранять. Не понял, зачем мне R4-R11 в стек сохранять, если я к ним не обращаюсь??? А по поводу возвращения из функции тоже не понятно. Что в return указывать? Цитата(Сергей Борщ @ Dec 12 2007, 15:39)  Только замечу, что этот код портит все остальные флаги в CPSR, может вылезти в любой момент. Надо бы в сохраненном значении маскировать все флаги. Подумать, чтобы при выходе одной командой AND включались только нужные прерывания. Согласен, надо исправить.
|
|
|
|
|
Dec 12 2007, 14:32
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Цитата(xelax @ Dec 12 2007, 16:01)  Не понял, зачем мне R4-R11 в стек сохранять, если я к ним не обращаюсь???
А по поводу возвращения из функции тоже не понятно. Что в return указывать? Согласен, надо исправить. 2 Сергей Борщ. Спасибо за документик  . Теперь понятно. То что переменная лежит в R0. Это стандарт. Зачем сохранять R4-11 тоже понятно  . Но в моём случае смысла не вижу.
|
|
|
|
|
Dec 12 2007, 14:35
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(xelax @ Dec 12 2007, 15:01)  Не понял, зачем мне R4-R11 в стек сохранять, если я к ним не обращаюсь??? Это я к тому, что R1 сохранять не нужно. Цитата(xelax @ Dec 12 2007, 15:01)  А по поводу возвращения из функции тоже не понятно. Что в return указывать? Хороший вопрос. Я не изучал еще его инлайн-ассемблер, не знаю как сказать, что результат в R0. Если бы это был WinAVR, я бы написал что-то вроде Код inline static atomic_t volatile StartAtomic() { register atomic_t result asm ("r0"); asm volatile ( "MRS R0, CPSR \n\t" /* Get CPSR. */ "ORR R1, R0, #0xC0 \n\t" /* Disable IRQ, FIQ. */ "MSR CPSR, R1 \n\t" /* Write back modified value. */ :"=r" (result) : :R1 ); return result; } Ха, а там есть где развернуться: ARM GCC Inline Assembler Cookbookтогда Код inline static atomic_t volatile StartAtomic() { asm volatile ( "MRS %0, CPSR \n\t" "ORR %1, %0, #0xC0 \n\t" "MSR CPSR, %1 \n\t" "ORR %0, %0, #0xFFFFFF3F \n\t" // mask all, but int bits :"=r" (result) : :"r" ); return result; } inline static void EndAtomic(atomic_t volatile Atomic) { asm volatile ( "MRS %1, CPSR \n\t" "AND %1, %1, %0 \n\t" "MSR CPSR, %1 \n\t" : :"=r" (Atomic) :"r" ); } Кажется так... По документику - только сейчас обратил внимание, что это стандарт на вызовы ARM<->THUMB (ATPCS). Для ARM<->ARM есть свой стандарт APCS, для THUMB<->THUMB - TPCS. Они описаны тут: ARM Software Development Toolkit. Reference Guide
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 12 2007, 16:12
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(xelax @ Dec 12 2007, 17:20)  К стати при оптимизации -Os, в R1 не замечал, а вот в R2 что-то хранилось, хотя по стандарту не должно. В любом случае в последних вариантах мы указываем clobber register, а компилятор сам выберет, какой сейчас свободный и использует его, а если свободного нет - сам сохранит какой-нибудь на стеке.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 13 2007, 06:51
|
Местный
  
Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034

|
По поводу масок флагов вы перемудрили. В ARM всё уже есть. вместо Код MSR cpsr, Rx пользуйте Код MSR cpsr_c, Rx
|
|
|
|
|
Dec 13 2007, 12:32
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Alex03 @ Dec 13 2007, 08:51)  По поводу масок флагов вы перемудрили. Точно! И вообще можно все переписать, максимально уменьшив асм: Код typedef uint32_t status_reg_t;
inline static status_reg_t get_cpsr() { asm volatile ( "MRS %0, cpsr" :"=r" (cpsr_value) : ); return cpsr_value; } inline static set_cpsr_c(status_reg_t cpsr_value) { asm volatile ( "MSR cpsr_c, %0" : :"r" (cpsr_value) ); }
inline static status_reg_t StartAtomic() { status_reg_t CPSR = get_cpsr(); status_reg_t Tmp = CPSR; do // Atmel Application Note Rev. 1156A–08/98 { set_cpsr_c(Tmp | 0xC0); // disable IRQ, FIQ } while (!((Tmp = get_cpsr()) & 0xC0)); } inline static void EndAtomic(status_reg_t cpsr_value) { set_cpsr_c(cpsr_value); }
#define ATOMIC_SECTION_ENTER {volatile status_reg_t cpsr = StartAtomic(); #define ATOMIC_SECTION_LEAVE EndAtomic(cpsr);}
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|