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

Что такое СТЕК и с чем его едят?

Пять лет успешно программля на С. Пришло время.... Пришлось сталкнуться с ассеблером. Все понятно... Вот только не пойму я что такое СТЕК? Поясните пожалуйста особо популярно что это такое? Как он работает? И что в нем по обыкновению храниться? И почему без операций:

 

ldi r16, high(RAMEND)

out SPH, r16

 

ldi r16, low(RAMEND)

out SPL, r16

 

Конроллер МЕГА128 нормально не работает?

 

Заранее огромное спасибо.......

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


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

>> Пять лет успешно программля на С

успешно???

 

стек - область памяти для хранения адреса возврата, передачи параметров в функцию, выделения памяти для локальных переменных функции.

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


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

Стек (Stack) в переводе "палка". В применении к аппаратно-программной части микроконтроллеров это линейная часть ОЗУ, выделенная для хранения данных по принципу LIFO (Last In - First Out) Последним Вошел - Первым Вышел. Стек нужен для организации работы прерываний и подпрограмм/функций. В стеке могут хранится, как уже указал Alex B._, адреса возврата из функции/прерывания, данные для передачи параметров в/из функцию, буфер(а) для локальных переменных. Прерывания используют стек на аппаратном уровне как минимум для записи текущего адреса выполняемой программы (некоторые сохраняют в стек еще и слово состояния АЛУ ядра МК и пр.), чтобы после обработки прерывания, можно было вернуться и продолжить ее выполнение. Поэтому. если вы заранее не установили указатель стека на свободную часть ОЗУ, то при вызове прерываний последовательность выполнения программы может быть нарушена. В отличие от счетчика команд, который работает с автоинкрементом, то указатель стека работает с автодекрементом. Поэтому указателю стека обычно присваивают значение адреса не начала, а конца ОЗУ. Напротив, глобальные переменные и "куча", используемые в Си, располагаются с начала ОЗУ. Поэтому эти две области данных "растут" навстречу друг другу. Переполнение стека, при котором содержимое стека "наползает" на область глобальных переменных и/или "кучи", это одна из самых типичных и в то же время весьма трудно обнаруживаемая ошибка, возникающих при программировании МК.

Есть еще другие понятия стека, например, "стек протоколов". За разъяснениями можно обратиться к Википедии, например.

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


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

Стек (Stack) в переводе "палка"

Отличное объяснение. Перевод только немного надо подправить: стек (stack) в переводе означает "скирда, стог; кипа" (а палка это stick).

 

Для образности ещё добавлю, что стек можно представить себе в виде автоматного магазина, патроны вставляются последовательно 1-2-3-4-5..., а вынимаются ...5-4-3-2-1.

 

А вот в нижеприведенном фрагменте теряется безвозвратно один байт ОЗУ.

     ldi   r16,high(RAMEND)
     out   SPH,r16
     ldi   r16,low(RAMEND)
     out   SPL,r16

 

Надо бы писать так

     ldi   r16,high(RAMEND+1)
     out   SPH,r16
     ldi   r16,low(RAMEND+1)
     out   SPL,r16

Кто бы мне объяснил, почему так не делают? Инерция мышления?

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


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

Если быть более точным, то направление куда "ползёт" стек определяется схемотехникой CPU. Действительно чаще он ползёт вниз и это очень удобно. В то же время, например в 8051 он ползёт вверх и устанавливается аппаратно. То есть приведённых вами команд инициализации можно и не делать.

 

Куча (Heap) в Си или другом языке программирования - напротив вещь не аппаратная и приведение каких-нибудь сравнений, аналогий и примеров, как мне кажется неуместно. Тем более если правильно ей пользоваться. Хотя указание, что нарушение стека ведёт к трудно находимым ошибкам совершенно правильно!

 

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

 

 

Отмечу ещё одно место, где стек совершенно необходим! Без него просто нельзя (не аппаратный так программный). Это рекурсия. То есть вызов процедурой самой себя (при правильном написании).

 

В завершение скажу что компилятор СИ от IAR использует два стека. Аппаратный и программный. На сколько я понял программный используется для удобства работы с переменными расположенными на стеке. (чаще всего это параметры процедур).

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


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

успешно???

 

Я программировал в иаре. И никода не задумывался что это такое. Об этом за меня думал компилятор...

:)

 

За ответы большое спасибо... Я хоть сообразил что такое инициализация стека и как стек вообще работает и где храниться и зачем он нужен....

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


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

Еще вдогонку - через стек передаються в функцию параметры, если они не помещаются в регистры (зависит от компилятора).

В стеке создаються локальные переменные.

Сам принцип стека, который не требует каких-то манипуляций с адресами (используется только указатель вершины), очень удобен для запоминания каких-либо временных данных.

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


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

Я программировал в иаре. И никода не задумывался что это такое. Об этом за меня думал компилятор...

:)

За ответы большое спасибо... Я хоть сообразил что такое инициализация стека и как стек вообще работает и где храниться и зачем он нужен....

Смотрю, как ваяют мои студенты... Нет, что такое стек, их учили. Но не задумываются ни о длительности выполнения функций прерывания, ни о частоте запросов, ни о вложенности прерываний, ни об обьеме памяти. Фсетки современные компьютеры (да и компиляторы, черт бы их побрал) развращают программиста :biggrin:

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


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

Стек (Stack) в переводе "палка"

Отличное объяснение. Перевод только немного надо подправить: стек (stack) в переводе означает "скирда, стог; кипа" (а палка это stick).

 

Для образности ещё добавлю, что стек можно представить себе в виде автоматного магазина, патроны вставляются последовательно 1-2-3-4-5..., а вынимаются ...5-4-3-2-1.

 

А вот в нижеприведенном фрагменте теряется безвозвратно один байт ОЗУ.

     ldi   r16,high(RAMEND)
     out   SPH,r16
     ldi   r16,low(RAMEND)
     out   SPL,r16

 

Надо бы писать так

     ldi   r16,high(RAMEND+1)
     out   SPH,r16
     ldi   r16,low(RAMEND+1)
     out   SPL,r16

Кто бы мне объяснил, почему так не делают? Инерция мышления?

 

 

Господин GM, зачем вводите в заблуждение и так не окрепшие умы инженеров.

Предложенная вами инициализация стека совершенно не правильна и работать не будет.

Предлагаю вам обратить внимание на команду push

 

This instruction stores the contents of register Rr on the STACK. The stack pointer is post-decremented by 1 after the PUSH.

 

А так же предлагаю вам просимулировать в студии код:

 

; Ваш код
RESET:

    ldi     tmp,    high(RAMEND+1); Main program start
    out     SPH,    tmp; Set stack pointer to top of RAM
    ldi     tmp,    low(RAMEND+1)
    out     SPL,    tmp

    clr        zero

    push    zero

; Правильный код
RESET:

    ldi     tmp,    high(RAMEND); Main program start
    out     SPH,    tmp; Set stack pointer to top of RAM
    ldi     tmp,    low(RAMEND)
    out     SPL,    tmp

    clr        zero

    push    zero

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


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

Я программировал в иаре. И никода не задумывался что это такое. Об этом за меня думал компилятор...

:)

 

За ответы большое спасибо... Я хоть сообразил что такое инициализация стека и как стек вообще работает и где храниться и зачем он нужен....

 

А зря. Об CSTACK & RSTACK неплохо бы подумать самому. Во избежание выражений типа "Глюки компилятора"

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


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

успешно???

Я программировал в иаре. И никода не задумывался что это такое. Об этом за меня думал компилятор...

:)

Гм? Компилятор не заботится о стеке. Интересно как Ваши программы вообще работали с тем мизером который выделяется IAR'ом под стек по-умолчанию.

 

Ради интереса, откройте любой проект в IAR'е и зайдите во вкладку опций проекта: General->System

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


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

Господин GM, зачем вводите в заблуждение и так не окрепшие умы инженеров.

Прошу прощения, что невольно ввёл всех аврщиков в заблуждение, не хотел. Вообще, если честно, я и не предлагал так делать, просто просил объяснить мне, почему так не делают. Вот, кстати, посмотрел старые проекты с авр на борту, там исходный указатель указывает на последнюю ячейку памяти.

 

А пошло это, скорее всего, вот откуда. Недавно интенсивно работал с TMS320C5402, надо было реанимировать старый проект, а там для push как раз предекремент стека, вот видимо и отложилось в голове, другого объяснения нет.

 

Ну и, с праздником всех!

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


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

А пошло это, скорее всего, вот откуда. Недавно интенсивно работал с TMS320C5402, надо было реанимировать старый проект, а там для push как раз предекремент стека, вот видимо и отложилось в голове, другого объяснения нет.

В большинстве архитектур, с которыми мне приходилось сталкиваться, действительно используется предекрементная схема (в классической системе команд PDP-11 применяемая как MOV R1, -(SP) для push, MOV (SP)+, R1 для pop. AVR в этом плане действительно извращенно реализован. Видимо, к тому были какие-то аппаратные предпосылки. Например, проще поместить в память по адресу указателя байт, а потом параллельно с выборкой следующей инструкции уже декрементировать указатель стека. Но это только версия, а на деле имеем то, что имеем - такой подарок писателям RTOS-ов под AVR :-)

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


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

Но это только версия, а на деле имеем то, что имеем - такой подарок писателям RTOS-ов под AVR :-)

Писателям RTOSов должно быть грубоко фиолетово как работает стек. Главное что работает.

 

А вот по логике работы схема в AVR куда более прозрачная и правильная чем у процессоров с пре-декрементом. Указатель стека всегда указывает на адрес действительной ячейки памяти а не на no-memory cell. Ведь физически нет такого адреса как RAMEND+1.

Каков смысл в предекременте, кроме как чтобы специально добавить дополнительный риск в программы.

 

Так что здесь Atmel'овцы молодцы, вопреки уже реализованной аппаратной схеме предекремента для адресных регистров X, Y, Z - со стеком они работают правильно через постдекремент.

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


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

Но это только версия, а на деле имеем то, что имеем - такой подарок писателям RTOS-ов под AVR :-)

Писателям RTOSов должно быть грубоко фиолетово как работает стек. Главное что работает.

Вероятно, Вам не доводилось писать участки переключения контекста, когда стеки процессов различны, и их нужно подменять. И ошибка по этой причине в неофициальной альфа-версии scmRTOS вылезла у меня очень даже быстро. Но это была неофициальная промежуточная версия, потому наружу она не вышла.

 

Нет, я, конечно, согласен, что сделать можно под любую схему. Но см. ниже.

 

Так что здесь Atmel'овцы молодцы, вопреки уже реализованной аппаратной схеме предекремента для адресных регистров X, Y, Z - со стеком они работают правильно через постдекремент.

Точно, молодцы - это чтобы разработчики компиляторов (типа gcc) не скучали :). Куча разных схем в одном процессоре для разных стеков - это, наверное, очень весело :). Имел в этом плане интересную беседу с Harry Zhurov'вым (автором вышеупомянутой RTOS), но переписка была личная, так что цитировать не имею полномочий.

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


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

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

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

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

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

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

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

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

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

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