|
Что такое СТЕК и с чем его едят?, Знающим просьба пояснить простые истины...... |
|
|
|
Feb 23 2007, 03:08
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

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

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(rezident @ Feb 23 2007, 00:08)  Стек (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 Кто бы мне объяснил, почему так не делают? Инерция мышления?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Feb 23 2007, 03:37
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Если быть более точным, то направление куда "ползёт" стек определяется схемотехникой CPU. Действительно чаще он ползёт вниз и это очень удобно. В то же время, например в 8051 он ползёт вверх и устанавливается аппаратно. То есть приведённых вами команд инициализации можно и не делать.
Куча (Heap) в Си или другом языке программирования - напротив вещь не аппаратная и приведение каких-нибудь сравнений, аналогий и примеров, как мне кажется неуместно. Тем более если правильно ей пользоваться. Хотя указание, что нарушение стека ведёт к трудно находимым ошибкам совершенно правильно!
Причина неверной работы с подпрограммами и прерываниями при отсутствии инициализации стека не при входе в прерывание, а при выходе из него. Так как подставляется не тот адрес возврата.
Отмечу ещё одно место, где стек совершенно необходим! Без него просто нельзя (не аппаратный так программный). Это рекурсия. То есть вызов процедурой самой себя (при правильном написании).
В завершение скажу что компилятор СИ от IAR использует два стека. Аппаратный и программный. На сколько я понял программный используется для удобства работы с переменными расположенными на стеке. (чаще всего это параметры процедур).
|
|
|
|
|
Feb 23 2007, 09:39
|

Частый гость
 
Группа: Участник
Сообщений: 151
Регистрация: 27-05-06
Из: Харьков
Пользователь №: 17 508

|
Цитата(Alex B._ @ Feb 23 2007, 02:43)  успешно??? Я программировал в иаре. И никода не задумывался что это такое. Об этом за меня думал компилятор... За ответы большое спасибо... Я хоть сообразил что такое инициализация стека и как стек вообще работает и где храниться и зачем он нужен....
|
|
|
|
|
Feb 23 2007, 09:54
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(Potter @ Feb 23 2007, 10:39)  Я программировал в иаре. И никода не задумывался что это такое. Об этом за меня думал компилятор... За ответы большое спасибо... Я хоть сообразил что такое инициализация стека и как стек вообще работает и где храниться и зачем он нужен.... Смотрю, как ваяют мои студенты... Нет, что такое стек, их учили. Но не задумываются ни о длительности выполнения функций прерывания, ни о частоте запросов, ни о вложенности прерываний, ни об обьеме памяти. Фсетки современные компьютеры (да и компиляторы, черт бы их побрал) развращают программиста
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Feb 23 2007, 12:02
|
Местный
  
Группа: Свой
Сообщений: 437
Регистрация: 23-04-05
Из: Таганрог
Пользователь №: 4 425

|
Цитата(=GM= @ Feb 23 2007, 03:35)  Цитата(rezident @ Feb 23 2007, 00:08)  Стек (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
|
|
|
|
|
Feb 23 2007, 12:28
|
Частый гость
 
Группа: Свой
Сообщений: 151
Регистрация: 11-01-06
Из: Украина Ровно
Пользователь №: 13 066

|
Цитата(Potter @ Feb 23 2007, 08:39)  Я программировал в иаре. И никода не задумывался что это такое. Об этом за меня думал компилятор... За ответы большое спасибо... Я хоть сообразил что такое инициализация стека и как стек вообще работает и где храниться и зачем он нужен.... А зря. Об CSTACK & RSTACK неплохо бы подумать самому. Во избежание выражений типа "Глюки компилятора"
|
|
|
|
|
Feb 23 2007, 13:56
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(Dopler @ Feb 23 2007, 09:02)  Господин GM, зачем вводите в заблуждение и так не окрепшие умы инженеров. Прошу прощения, что невольно ввёл всех аврщиков в заблуждение, не хотел. Вообще, если честно, я и не предлагал так делать, просто просил объяснить мне, почему так не делают. Вот, кстати, посмотрел старые проекты с авр на борту, там исходный указатель указывает на последнюю ячейку памяти. А пошло это, скорее всего, вот откуда. Недавно интенсивно работал с TMS320C5402, надо было реанимировать старый проект, а там для push как раз предекремент стека, вот видимо и отложилось в голове, другого объяснения нет. Ну и, с праздником всех!
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Feb 23 2007, 16:56
|

Частый гость
 
Группа: Свой
Сообщений: 175
Регистрация: 26-01-06
Из: Sevastopol
Пользователь №: 13 664

|
Цитата(=GM= @ Feb 23 2007, 12:56)  А пошло это, скорее всего, вот откуда. Недавно интенсивно работал с TMS320C5402, надо было реанимировать старый проект, а там для push как раз предекремент стека, вот видимо и отложилось в голове, другого объяснения нет. В большинстве архитектур, с которыми мне приходилось сталкиваться, действительно используется предекрементная схема (в классической системе команд PDP-11 применяемая как MOV R1, -(SP) для push, MOV (SP)+, R1 для pop. AVR в этом плане действительно извращенно реализован. Видимо, к тому были какие-то аппаратные предпосылки. Например, проще поместить в память по адресу указателя байт, а потом параллельно с выборкой следующей инструкции уже декрементировать указатель стека. Но это только версия, а на деле имеем то, что имеем - такой подарок писателям RTOS-ов под AVR :-)
|
|
|
|
|
Feb 23 2007, 17:15
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(osnwt @ Feb 23 2007, 15:56)  Но это только версия, а на деле имеем то, что имеем - такой подарок писателям RTOS-ов под AVR :-) Писателям RTOSов должно быть грубоко фиолетово как работает стек. Главное что работает. А вот по логике работы схема в AVR куда более прозрачная и правильная чем у процессоров с пре-декрементом. Указатель стека всегда указывает на адрес действительной ячейки памяти а не на no-memory cell. Ведь физически нет такого адреса как RAMEND+1. Каков смысл в предекременте, кроме как чтобы специально добавить дополнительный риск в программы. Так что здесь Atmel'овцы молодцы, вопреки уже реализованной аппаратной схеме предекремента для адресных регистров X, Y, Z - со стеком они работают правильно через постдекремент.
|
|
|
|
|
Feb 23 2007, 17:50
|

Частый гость
 
Группа: Свой
Сообщений: 175
Регистрация: 26-01-06
Из: Sevastopol
Пользователь №: 13 664

|
Цитата(defunct @ Feb 23 2007, 16:15)  Цитата(osnwt @ Feb 23 2007, 15:56)  Но это только версия, а на деле имеем то, что имеем - такой подарок писателям RTOS-ов под AVR :-)
Писателям RTOSов должно быть грубоко фиолетово как работает стек. Главное что работает. Вероятно, Вам не доводилось писать участки переключения контекста, когда стеки процессов различны, и их нужно подменять. И ошибка по этой причине в неофициальной альфа-версии scmRTOS вылезла у меня очень даже быстро. Но это была неофициальная промежуточная версия, потому наружу она не вышла. Нет, я, конечно, согласен, что сделать можно под любую схему. Но см. ниже. Цитата Так что здесь Atmel'овцы молодцы, вопреки уже реализованной аппаратной схеме предекремента для адресных регистров X, Y, Z - со стеком они работают правильно через постдекремент. Точно, молодцы - это чтобы разработчики компиляторов (типа gcc) не скучали  . Куча разных схем в одном процессоре для разных стеков - это, наверное, очень весело  . Имел в этом плане интересную беседу с Harry Zhurov'вым (автором вышеупомянутой RTOS), но переписка была личная, так что цитировать не имею полномочий.
|
|
|
|
|
Feb 23 2007, 18:39
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(osnwt @ Feb 23 2007, 16:50)  участки переключения контекста, когда стеки процессов различны, и их нужно подменять. Какие сложности с постдекрементом SP? Не смешите тапочки. Цитата Точно, молодцы - это чтобы разработчики компиляторов (типа gcc) не скучали  . Куча разных схем в одном процессоре для разных стеков - это, наверное, очень весело  . Имел в этом плане интересную беседу с Harry Zhurov'вым (автором вышеупомянутой RTOS), но переписка была личная, так что цитировать не имею полномочий. Плохому танцору... все мы знаем что мешает.
|
|
|
|
|
Feb 23 2007, 22:20
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Соглашусь с defunct.
Ошибки в компиляторах и операционных системах были есть и будут. Это слабо зависит от реализации кристалла. К тому же сие вообще не показатель. Компиляторов для AVR - десяток, а программ миллионы.
А вот иногда, то что годами тащится по "совместимости" - это конкретная беда. То есть сначала - это разумный и единственно правильный шаг. Но время идёт, а человек не идеален и не может предусмотреть на годы вперёд. И вот с какого то момента самая прогрессивная архитектура, ОС, протокол или схемное решение является самым мощным тормозом.
Пример у всех на виду. ОС от WIN. Вместе с железом конечно и вместе с переферией. Только построение видюхи - медаль давать. На видюху выделено столько же памяти в адресном пространстве, сколько AT91SAM7S64 отводит на RS232.
Вот и получается, что достаточно слабый наладонник моего сына ACER n311 запускает эмуляцию MSDOS (!!!) из под неё запускает вторую кирандию и она вполне прилично работает!
|
|
|
|
|
Feb 23 2007, 23:06
|
Местный
  
Группа: Свой
Сообщений: 437
Регистрация: 23-04-05
Из: Таганрог
Пользователь №: 4 425

|
Цитата(=GM= @ Feb 23 2007, 13:56)  Прошу прощения, что невольно ввёл всех аврщиков в заблуждение, не хотел. Ну, если обещаете, что больше так не будете То, конечно, прощаем!!! С Праздником всех!!!
|
|
|
|
|
Feb 24 2007, 00:04
|

Частый гость
 
Группа: Свой
Сообщений: 175
Регистрация: 26-01-06
Из: Sevastopol
Пользователь №: 13 664

|
Цитата(defunct @ Feb 23 2007, 17:39)  Плохому танцору... все мы знаем что мешает. Я всего лишь привел пример того, что необоснованное отклонение от принятой в большинстве других популярных процессоров логики способно привести к применению "правила" по привычке, когда делаешь порт некоей системы под множество различных процессоров одновременно. Названная OS существует для процессоров от AVR до ARM7 и Blackfin, и не удивительно, что можно допустить механическую ошибку при внесении изменений в несколько портов параллельно. В этом контексте процитированное высказывание выглядит просто неуважительно к человеку, будучи высказанным при незнании деталей ситуации. Я лично такое себе не позволяю. Цитата Какие сложности с постдекрементом SP? Не смешите тапочки. А Вы читать умеете? Я разве говорил о сложности? Я говорил о том, что механизм работы со стеком имеет существенное значение при работе с его указателем явно, а не посредством push/pop. Я не утверждал, что это как-то осложняет написание чего-либо. Я просто указал, что это вовсе не безразлично. Цитата(SasaVitebsk @ Feb 23 2007, 21:20)  Соглашусь с defunct. Все с чем-то соглашаются. Осталось еще определиться, с чем именно  Про ошибки повторяться не буду - уже было сказано. Цитата А вот иногда, то что годами тащится по "совместимости" - это конкретная беда. То есть сначала - это разумный и единственно правильный шаг. Но время идёт, а человек не идеален и не может предусмотреть на годы вперёд. И вот с какого то момента самая прогрессивная архитектура, ОС, протокол или схемное решение является самым мощным тормозом. Неужели я где-то высказался за то, что нужно тащить принятую архитектуру все время только из соображений совместимости? Если говорить "в общем", то совместимость можно нарушить в тех случаях, если это дает реальный прогресс хоть в чем-то. В данном же конкретном случае я этого не вижу вообще. Цитата А вот по логике работы схема в AVR куда более прозрачная и правильная чем у процессоров с пре-декрементом. Указатель стека всегда указывает на адрес действительной ячейки памяти а не на no-memory cell. Ведь физически нет такого адреса как RAMEND+1. Каков смысл в предекременте, кроме как чтобы специально добавить дополнительный риск в программы. Я не вижу никакой логики в приведенном высказывании. Во первых, стек не обязан находиться в конце памяти до RAMEND, и выражение SP+1 может иметь физический смысл. Во вторых, никого из программистов не смущает конструкция языка C *p++ при работе с массивом в цикле. При последней итерации значение указателя точно также выходит за пределы блока памяти, выделенного массиву, и не гарантируется физическое существование чего-либо за пределами этого блока. Что при этом не мешает использовать эту конструкцию программистам, ибо, пока мы не применяем операцию разименования к полученному p, проблем не будет. В третьих, ситуация с постдекрементной схемой ничуть не лучше в плане "дополнительного риска в программах". Если область стека находится с нуля, то при постдекрементной схеме мы вообще вылезем на адрес -1 после заполнения нулевой ячейки. Чем это лучше или безопаснее преддекрементной схемы - я лично не понимаю. Итого, выходит, что изменив "стандартную de-facto" логику, мы не получаем никаких видимых плюсов. Зато получаем в пределах одного процессора две различных системы организации стеков (SP и X/Y/Z), да еще и в пределах единого адресного пространства. Вот тут я вообще не вижу никакой внешней логики (про возможные внутренние оптимизации я говорил исходно, но это знают только разработчики архитектуры). В целом, не имея желания кому-то что-то доказывать, я, тем не менее, свои соображения всегда аргументирую. Было бы интересно услышать конструктивную критику с фактами по пунктам, приведенным мною. Пока же я так и не увидел того, что положительного было внесено имплементацией двух схем работы со стеком в AVR. Ваши высказывания, уважаемые собеседники, пока лично меня не убедили в прогрессивности этого шага (что я аргументировал по пунктам). Потому пока остаюсь при своем мнении.
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|