Project

General

Profile

Обзор работы со стеком » History » Version 21

krufter_multiclet, 04/04/2013 11:44 AM

1 1 krufter_multiclet
h1. Обзор работы со стеком
2 1 krufter_multiclet
3 21 krufter_multiclet
*Стек вызовов* (от англ. call stack; применительно к процессорам — просто «стек») — в теории вычислительных систем, LIFO-стек, хранящий информацию для возврата управления из подпрограмм (процедур) в программу (или подпрограмму, при вложенных или рекурсивных вызовах) и/или для возврата в программу из обработчика прерывания (в том числе при переключении задач в многозадачной среде).
4 21 krufter_multiclet
5 21 krufter_multiclet
При вызове подпрограммы или возникновении прерывания, в стек заносится адрес возврата — адрес в памяти следующей инструкции (в нашем случае параграф) приостановленной программы и управление передается подпрограмме или подпрограмме-обработчику. При последующем вложенном или рекурсивном вызове, прерывании подпрограммы или обработчика прерывания, в стек заносится очередной адрес возврата и т. д.
6 21 krufter_multiclet
7 21 krufter_multiclet
При возврате из подпрограммы или обработчика прерывания, адрес возврата снимается со стека и управление передается на следующую инструкцию (в нашем случае параграф) приостановленной (под-)программы.
8 1 krufter_multiclet
9 1 krufter_multiclet
Стек в мультиклеточном процессоре организован при помощи индексных регистров 38,39.
10 17 krufter_multiclet
Регистр 38 имеет имя BP (база стека), регистр 39 называется SP (вершина стека).
11 1 krufter_multiclet
12 1 krufter_multiclet
Стек растёт от конца памяти данных и структурируется по кадрам. Один кадр состоит из группы элементов, находящихся
13 2 krufter_multiclet
между SP и BP (между вершиной и базой стека). Один элемент кадра является 32-х битной ячейкой памяти.
14 5 krufter_multiclet
Рассмотрим структуру стека при вызове на Си ассемблерной функции типа void, которая не возвращает результат и 
15 6 krufter_multiclet
имеет два аргумента, например *void MDIO_WR(int phy_addr, int reg_num)*:
16 3 krufter_multiclet
17 4 krufter_multiclet
!Stack_void.jpg!
18 5 krufter_multiclet
19 1 krufter_multiclet
Рис 1. Структура стека функции void
20 6 krufter_multiclet
21 6 krufter_multiclet
+Адрес возврата+ - адрес для возвращения обратно в Си программу
22 6 krufter_multiclet
+Аргумент1+ - значение переменной phy_addr
23 6 krufter_multiclet
+Аргумент2+ - значение переменной reg_num
24 6 krufter_multiclet
+Адрес BP+ - значение адреса, по которому располагалась база предыдущего кадра 
25 7 krufter_multiclet
26 7 krufter_multiclet
Вершина стека (SP) находится на 3 позиции выше базы стека (BP).
27 7 krufter_multiclet
28 10 krufter_multiclet
Для функции типа int, которая возвращает результат структура кадра немного изменится(появится поле для возвращаемого значения).
29 8 krufter_multiclet
Например, рассмотрим следующую функцию *int MDIO_RD(int phy_addr, int reg_num)*:
30 8 krufter_multiclet
31 8 krufter_multiclet
!Stack_int.jpg!
32 8 krufter_multiclet
33 12 krufter_multiclet
Рис 2. Структура стека функции int
34 9 krufter_multiclet
35 9 krufter_multiclet
+Адрес возврата+ - адрес для возвращения обратно в Си программу
36 9 krufter_multiclet
+Результат+ - значение возвращаемое функцией в Си
37 9 krufter_multiclet
+Аргумент1+ - значение переменной phy_addr
38 9 krufter_multiclet
+Аргумент2+ - значение переменной reg_num
39 9 krufter_multiclet
+Адрес BP+ - значение адреса, по которому располагалась база предыдущего кадра 
40 9 krufter_multiclet
41 1 krufter_multiclet
Вершина стека (SP) находится на 4 позиции выше базы стека (BP).
42 12 krufter_multiclet
43 12 krufter_multiclet
Стек разумеется можно использовать для своих нужд, но при этом следует учесть, что в ассемблерном файле в котором реализована функция Си
44 12 krufter_multiclet
должно быть сохранение исходных значений вершины и базы стека, а в конце ассемблерного файла их восстановление.
45 14 krufter_multiclet
Рассмотрим пример сохранения исходных значений SP,BP и выделение кадра в размерностью *56/4* (SP-BP), в котором можно разместить 14 своих
46 12 krufter_multiclet
ячеек по 4 байта:
47 12 krufter_multiclet
<pre>
48 12 krufter_multiclet
prologe:
49 12 krufter_multiclet
    getl #SP
50 12 krufter_multiclet
    getl #BP
51 12 krufter_multiclet
    subl @2, 60
52 12 krufter_multiclet
    wrl @2, #SP, -4
53 12 krufter_multiclet
    setl #SP, @2
54 12 krufter_multiclet
    subl @5, 4
55 12 krufter_multiclet
    setl #BP, @1
56 12 krufter_multiclet
    jmp get_put
57 12 krufter_multiclet
complete
58 12 krufter_multiclet
</pre>
59 12 krufter_multiclet
60 12 krufter_multiclet
Для восстановления вершины и базы стека можно использовать следующий универсальный параграф:
61 12 krufter_multiclet
62 12 krufter_multiclet
<pre>
63 12 krufter_multiclet
epiloge:
64 12 krufter_multiclet
    getl #BP
65 12 krufter_multiclet
    addl @1, 4 
66 12 krufter_multiclet
    setl #SP, @1
67 12 krufter_multiclet
    rdl #BP
68 12 krufter_multiclet
    setl #BP, @1
69 12 krufter_multiclet
    rdl RDATA
70 12 krufter_multiclet
    addl @6, 8
71 12 krufter_multiclet
    wrl @2, @1
72 12 krufter_multiclet
    jmp end_ret
73 12 krufter_multiclet
complete
74 12 krufter_multiclet
</pre>
75 12 krufter_multiclet
76 20 krufter_multiclet
Команды getl, setl записывают значение в индексный регистр, а команды wrl, rdl - в память данных по адресу, который записан в индексном регистре или получен в результате сложения.
77 13 krufter_multiclet
78 13 krufter_multiclet
!Stack_add.jpg!
79 13 krufter_multiclet
80 14 krufter_multiclet
Рис 3.Выделение кадра в размерностью *56/4*
81 15 krufter_multiclet
82 15 krufter_multiclet
Ознакомиться с примером работы со стеком можно в хранилище в папке LDM_MCP04->Test_time_delay