Перейти к содержанию
    

AVR STACK

Написал макросы для работы со стеком...

Но я не являюсь спецом по ASM в AVRGCC.

Прошу великих Гуру окинуть сие творчество на передмет косяков...

И вообще, можно-ли в GCC использовать стек в таком ключе или есть нюансы?

// ============================================================================
#define __avr_stack_pop()                 \
(__extension__({                          \
    uint8_t __result;                     \
    __asm__ __volatile__                  \
    (                                     \
        "pop %0"            "\n\t"        \
        : "=r" (__result)                 \
        :                                 \
    );                                    \
    __result;                             \
}))

// ============================================================================
#define __avr_stack_push(value)           \
(__extension__({                          \
    uint8_t __value = (uint8_t)value;     \
    __asm__ __volatile__                  \
    (                                     \
        "push %0"            "\n\t"       \
        :                                 \
        : "r" (__value)                   \
    );                                    \
}))

Тест:

#define stack_push  __avr_stack_push
#define stack_pop   __avr_stack_pop
    unsigned char i = 0;
    do
    {
        stack_push(i);
        i = stack_pop();
    } while (++i<5);

Выход:

    cabe:    80 e0           ldi    r24, 0x00; 0
    cac0:    8f 93           push    r24
    cac2:    8f 91           pop    r24
    cac4:    8f 5f           subi    r24, 0xFF; 255
    cac6:    85 30           cpi    r24, 0x05; 5
    cac8:    d8 f3           brcs    .-10     ; 0xcac0 <main+0x2>

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Парсить удобно...

 

Да ещё была одна задумка, но она похоже накрылсь...

 

Хотел сохранять номер пункта родительского меню для последующего восстановления при возврате -

но пока не работает - MCU ресетится...

Разбираюсь в чём дело.

Если push и pop в одной процедуре - всё ок....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если push и pop в одной процедуре - всё ок....
Естественно. Потому что в другой процедуре на стек еще положен адрес возврата, локальные переменные, сохраненный SREG. Даже в одной процедуре в теле компилятор может положить на стек временную переменную и вся ваша стройная система рухнет. По макросу: поскольку push изменяет ОЗУ, совсем честно было бы указать memory в списке clobber

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Естественно. Потому что в другой процедуре на стек еще положен адрес возврата, локальные переменные, сохраненный SREG. Даже в одной процедуре в теле компилятор может положить на стек временную переменную и вся ваша стройная система рухнет.

С адресом возврата я согласен.

Из Вашей ремарки можно сделать не совсем правильный вывод о том, что компилятор использует лишь стек, а как же куча?

Когда она используется?

К слову, бывает, что компиляторы разделяют аппаратный стек и программный ибо он быстрее на некоторых системах...

Я думаю что и для AVR архитектуры это тоже м.б. разумно...

 

По макросу: поскольку push изменяет ОЗУ, совсем честно было бы указать memory в списке clobber

Доработал. Спасибо за совет!

// ============================================================================
#define __avr_stack_pop()                 \
(__extension__({                          \
    uint8_t __result;                     \
    __asm__ __volatile__                  \
    (                                     \
        "pop %0"            "\n\t"        \
        : "=r" (__result)                 \
        :                                 \
        : "memory"                        \
    );                                    \
    __result;                             \
}))

// ============================================================================
#define __avr_stack_push(value)           \
(__extension__({                          \
    uint8_t __value = (uint8_t)value;     \
    __asm__ __volatile__                  \
    (                                     \
        "push %0"            "\n\t"       \
        :                                 \
        : "r" (__value)                   \
        : "memory"                        \
    );                                    \
}))

Ещё раз убеждаюсь, что задавать правильные вопросы очень полезно для здоровья:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С адресом возврата я согласен.

Из Вашей ремарки можно сделать не совсем правильный вывод о том, что компилятор использует лишь стек, а как же куча? Когда она используется?

Компилятор "сам" использует кучу только в одном случае - в С++ при создании объектов через new. В С кучу использует программист, через вызов функций malloc/free.
К слову, бывает, что компиляторы разделяют аппаратный стек и программный ибо он быстрее на некоторых системах...

Я думаю что и для AVR архитектуры это тоже м.б. разумно...

Да, есть у такого подхода плюсы, есть минусы. В данном случае вы спрашивали по avr-gcc, а у него всего один стек.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо за разъяснение. Буду копать под кучу:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Компилятор "сам" использует кучу только в одном случае - в С++....

В С кучу использует программист, через вызов функций malloc/free.

Не совсем так - компилятор-то "сам" не использует, но некоторые вполне сишные библиотечные функции heap вынуждены пользовать - на вскидку strdup(), time()...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не совсем так - компилятор-то "сам" не использует, но некоторые вполне сишные библиотечные функции heap вынуждены пользовать - на вскидку strdup(), time()...
Естественно, но это функции, в исходнике которых явно указаны malloc/free. При использовании new компилятор вставляет malloc/free "от себя". Хотя... new тоже пишет программист.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да ещё была одна задумка, но она похоже накрылсь...

Хотел сохранять номер пункта родительского меню для последующего восстановления при возврате -

но пока не работает - MCU ресетится...

А зачем для этого использовать аппаратный стек контроллера?

Сделать свой отдельно.

Пусть максимум вложенности меню будет MAX_SUBMENU - тогда по сусекам всё равно придётся выделить столько байт на восстановления. Соберём их в одном месте

static uint8_t menu_stack[MAX_SUBMENU];
static uint8_t menu_stack_ptr = 0;

void push_index( uint8_t index)
{
    if( menu_stack_ptr < MAX_SUBMENU )
        menu_stack[ menu_stack_ptr++ ] = index;
}

uint8_t pop_index()
{
    return menu_stack_ptr ? menu_stack[--menu_stack_ptr] : 0;        
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Именно так я и сделал.

Прежде хотелось выпендриться - не вышло:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...