Project

General

Profile

Обзор работы со стеком

Стек вызовов (от англ. call stack; применительно к процессорам — просто «стек») — в теории вычислительных систем, LIFO-стек, хранящий информацию для возврата управления из подпрограмм (процедур) в программу (или подпрограмму, при вложенных или рекурсивных вызовах) и/или для возврата в программу из обработчика прерывания (в том числе при переключении задач в многозадачной среде).

При вызове подпрограммы или возникновении прерывания, в стек заносится адрес возврата — адрес в памяти следующей инструкции (в нашем случае параграф) приостановленной программы и управление передается подпрограмме или подпрограмме-обработчику. При последующем вложенном или рекурсивном вызове, прерывании подпрограммы или обработчика прерывания, в стек заносится очередной адрес возврата и т. д.

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

Стек в мультиклеточном процессоре организован при помощи индексных регистров 38,39.
Регистр 38 имеет имя BP (база стека), регистр 39 называется SP (вершина стека).

Стек растёт от конца памяти данных и структурируется по кадрам. Один кадр состоит из группы элементов, находящихся
между SP и BP (между вершиной и базой стека). Один элемент кадра является 32-х битной ячейкой памяти.
Рассмотрим структуру стека при вызове на Си ассемблерной функции типа void, которая не возвращает результат и
имеет два аргумента, например void MDIO_WR(int phy_addr, int reg_num):

Рис 1. Структура стека функции void

Адрес возврата - адрес для возвращения обратно в Си программу
Аргумент1 - значение переменной phy_addr
Аргумент2 - значение переменной reg_num
Адрес BP - значение адреса, по которому располагалась база предыдущего кадра

Вершина стека (SP) находится на 3 позиции выше базы стека (BP).

Для функции типа int, которая возвращает результат структура кадра немного изменится(появится поле для возвращаемого значения).
Например, рассмотрим следующую функцию int MDIO_RD(int phy_addr, int reg_num):

Рис 2. Структура стека функции int

Адрес возврата - адрес для возвращения обратно в Си программу
Результат - значение возвращаемое функцией в Си
Аргумент1 - значение переменной phy_addr
Аргумент2 - значение переменной reg_num
Адрес BP - значение адреса, по которому располагалась база предыдущего кадра

Вершина стека (SP) находится на 4 позиции выше базы стека (BP).

Стек разумеется можно использовать для своих нужд, но при этом следует учесть, что в ассемблерном файле в котором реализована функция Си
должно быть сохранение исходных значений вершины и базы стека, а в конце ассемблерного файла их восстановление.
Рассмотрим пример сохранения исходных значений SP,BP и выделение кадра в размерностью 56/4 (SP-BP), в котором можно разместить 14 своих
ячеек по 4 байта:

prologe:
    getl #SP
    getl #BP
    subl @2, 60
    wrl @2, #SP, -4
    setl #SP, @2
    subl @5, 4
    setl #BP, @1
    jmp get_put
complete

Для восстановления вершины и базы стека можно использовать следующий универсальный параграф:

epiloge:
    getl #BP
    addl @1, 4 
    setl #SP, @1
    rdl #BP
    setl #BP, @1
    rdl RDATA
    addl @6, 8
    wrl @2, @1
    jmp end_ret
complete

Команды getl, setl записывают значение в индексный регистр, а команды wrl, rdl - в память данных по адресу, который записан в индексном регистре или получен в результате сложения.

Рис 3.Выделение кадра в размерностью 56/4

Ознакомиться с примером работы со стеком можно в хранилище в папке LDM_MCP04->Test_time_delay