реклама на сайте
подробности

 
 
> Критическия секция, оцените и выскажите своё мнение
xelax
сообщение Dec 12 2007, 12:13
Сообщение #1


Местный
***

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



sam7x + arm-elf-gcc
Решил этот вопрос вынести в отдельную тему.
По совету Сергея Борща переделал критические секция из FreeRTOS для себя.

Так как переделовать пришлось код на асме, а в асме я позорно слаб, поэтому просьба покритиковать если что.

На какие вещи опирался.
Сделал дизасм своего проекта и увидел, что переменная переданная в функцию в конечном счёте оказывается в R0 до выполнения кода функции. Поэтому значение CSPR регистра я сохраняю и соответсвенно восстанавливаю по адресу хранящемуся в R0.

И ещё меня смущает одна вещь, собрал проект с оптимизацией -Os. Естественно никакой передачи параметров в функцию нет, но указатель на переменную всё равно оказался в R0 smile.gif
Но в тоже время я вижу что 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.                        */
}


З.Ы. Работает уже почти час. Пока живёт. 05.gif

Сообщение отредактировал xelax - Dec 12 2007, 12:15
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 8)
Сергей Борщ
сообщение Dec 12 2007, 12:39
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
xelax
сообщение Dec 12 2007, 13:01
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 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 включались только нужные прерывания.


Согласен, надо исправить.
Go to the top of the page
 
+Quote Post
xelax
сообщение Dec 12 2007, 14:32
Сообщение #4


Местный
***

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



Цитата(xelax @ Dec 12 2007, 16:01) *
Не понял, зачем мне R4-R11 в стек сохранять, если я к ним не обращаюсь???

А по поводу возвращения из функции тоже не понятно. Что в return указывать?
Согласен, надо исправить.


2 Сергей Борщ. Спасибо за документик a14.gif . Теперь понятно. То что переменная лежит в R0. Это стандарт.
Зачем сохранять R4-11 тоже понятно smile.gif . Но в моём случае смысла не вижу.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 12 2007, 14:35
Сообщение #5


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
xelax
сообщение Dec 12 2007, 15:20
Сообщение #6


Местный
***

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



К стати при оптимизации -Os, в R1 не замечал, а вот в R2 что-то хранилось, хотя по стандарту не должно.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 12 2007, 16:12
Сообщение #7


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
Alex03
сообщение Dec 13 2007, 06:51
Сообщение #8


Местный
***

Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034



По поводу масок флагов вы перемудрили. В ARM всё уже есть.
вместо
Код
MSR    cpsr, Rx

пользуйте
Код
MSR    cpsr_c, Rx
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 13 2007, 12:32
Сообщение #9


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 12:15
Рейтинг@Mail.ru


Страница сгенерированна за 0.01453 секунд с 7
ELECTRONIX ©2004-2016