Что такое стек? Как он работает?

Стек – это память для хранения адресов возврата. Обычно для его объяснения, приводят пример с книжной полкой. По сути, так и есть, и даже проще. Стек может быть реализован программно или аппаратно, что быстрее. У данного МК, он реализован аппаратно, имеет разрядность 13 бит, и 8 уровней вложенности. Это значит, что функция может вызвать сама себя 8 раз. На 9 – новый адрес – запишется на место 1, и после этого ваша программа зациклится, потому что стек будет переполнен, а адрес возврата утерян.

Чтобы разобраться, как он работает, и что делают команды call и return, наберите эту небольшую программу.

;---------------------------------- ;

#include<p17С756А.inc>

;---------------------------------- ;

org 0x00

goto main

org 0x05

;---------------------------------- ;

; Функции программы

;---------------------------------- ;

Call_1:

nop

nop

return

;--------------------------------- ;

Call_2:

nop

nop

return

;---------------------------------- ;

main:

call Call_1 ;

call Call_2 ;

goto main

END

В пункте меню View, активируйте подпункт Hardware Stack (рис.4.2).

Что такое стек? Как он работает? - student2.ru

Рис.4.2 - Стек

Запустите программу в отладчике, используя ручной режим. Нажимая клавишу <F7>, последовательно доберитесь до строки:

call Call_1 ; вызов функции Call_1

Ниже представлена упрощённая версия, файла листинга программы, созданного компилятором. Просто взгляните, а потом продолжите чтение.

Address:

0000 org 0x00

0000 goto main

0005 org 0x05

;--------------------

0005 Call_1:

0005 nop

0006 nop

0007 return

;--------------------

0008 Call_2:

0008 nop

0009 nop

000A return

;--------------------

000B main:

000B call Call_1 ;

000C call Call_2 ;

000D goto main

END

Имя функций Call_1 указывает на адрес 0х05, по которому размещена первая команда в памяти программ – nop. За ней ещё одна в ячейке памяти под номером - 0х06, и оканчивается функция командой возврата return, расположившейся в ячейке - 0х07.

0005 Call_1:

0005 nop

0006 nop

0007 return

Вспомните, когда мы рассматривали метки, упоминалось, что они являются средством организации программы на уровне пользователя. Как видите, так и есть, потому, что по адресу 0х05 располагается команда nop.

Теперь взгляните на адрес 0х0B (D‘11’), с которого начинается метка ‘main’, и следует команда вызова функции Call_1.

000B main:

000B call Call_1 ;

000C call Call_2 ;

000D goto main

END

При выполнении команды call – произойдёт следующее: текущий адрес 0x0B, на который указывает счётчик команд - PC, будет увеличен на 1 – PC + 1, то есть: 0x0B + 0x01 = 0x0C, после чего, тем самым начнёт указывать на следующую команду в памяти программ, и будет загружен в вершину стека (рис.4.3.). Произойдёт неявное выполнение команды goto на адрес 0х05, с которым ассоциирована метка подпрограммы Call_1.

Что такое стек? Как он работает? - student2.ru

Рис.4.3 - Стек после вызова функции

Когда все команды в теле функции Call_1 будут выполнены, и дело дойдёт до команды возврата return, произойдёт обращение к стеку, и выполниться переход по адресу, в нашем случае - это 0х0C, на который обращён указатель, и который был загружен в вершину стека командой вызова функции call. Это тем самым вернёт управление основной программе, и начнёт выполнение следующей команды, расположенной по адресу 0х0С. Если подобное описание автора показалось вам сложным, обратитесь к описанию системы команд, где данная информация представлена в более сжатой форме.

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

Соглашения об именовании

Выполнив уже две лабораторные работы, пришло время ознакомиться, с некоторыми правилами об именовании переменных и остальных членов программ. Имя – это уникальный идентификатор объекта, характеризующий его основные качества. Как было сказано в лабораторной работе № 2 – ячейка памяти, которая с чем-то ассоциирована, считается переменной. Чем больше информации способно нести имя, тем понятнее назначение члена в программе. Для удобства, автор использует один и тот же стиль во всех примерах, когда наделяет именами функции, метки и переменные. Если вы уже имели опыт программирования, и выработали для себя определённый стиль, тогда, конечно же, вам следует придерживаться его. В целях повышения читабельности кода, ознакомьтесь с соглашениями об именовании членов программ.

Переменные

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

value EQU 0x20 ;

array EQU 0x21 ;

X1 EQU 0x22 ;

X2 EQU 0x23 ;

X3 EQU 0x24 ;

Переменные, которые состоят из нескольких слов – оба пишутся с маленькой буквы, и разделены знаком нижнего пробельного символа ‘_’. Если имена слишком длинные, сокращение происходит по согласным. В противном случае, слова остаются в том же виде. Также это правило нарушается для логических выражений.

arr_size EQU 0x21 ;

n_X1 EQU 0x22 ; инвертированный Х1

Функции и Макросы

Одиночные имена функций состоят из одного слова с заглавной буквы.

Calc: ;

return

Составные имена – оба слова начинаются с заглавных букв, разделенных знаком нижнего пробельного символа ‘_’. В случае длинного названия, сокращение идёт по согласным.

Calc_Array: ;

.

.

return

Init_Vars: ;

.

.

return

Strt_Tmr1: ;

ENDM

Метки

Главная метка программы ‘main’ всегда начинается со строчной.

main:

.

.

END

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

main:

A2:

goto A2 ;

.

.

.

AT2:

goto AT2

END

Команды

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

movwl D‘10’ ;

bsf value,2 ;

Директивы

Директивы #include, #define, а также имена подключаемых файлов состоят из строчных букв. Остальные состоят только из заглавных.

#include<source_file> ;

#define true 0x01 ;

.

.

#include”source­_file”

#define false 0x00 ;

.

.

BANKSEL label ;

.

.

label EQU address ;

Наши рекомендации