Project

General

Profile

Вызов программы ASM из Си » History » Version 19

krufter_multiclet, 07/19/2013 07:18 PM

1 1 krufter_multiclet
h1. Вызов программы ASM из Си
2 1 krufter_multiclet
3 15 krufter_multiclet
Вызов программы, написанной на ассемблере из Си организован при помощи стека. Подробнее о стеке можно прочитать в [[Обзор работы со стеком]].
4 2 krufter_multiclet
5 2 krufter_multiclet
Рассмотрим пример вызова процедуры, написанной на ассемблере, из Си функцией типа *void*.
6 2 krufter_multiclet
7 9 krufter_multiclet
h2. Для функции типа void
8 9 krufter_multiclet
9 11 krufter_multiclet
Пусть программа на ассемблере принимает два аргумента и выполняет их сложение, а также выдает результат через UART на ассемблере.
10 2 krufter_multiclet
11 11 krufter_multiclet
На Си вызов функции может выглядеть так:
12 2 krufter_multiclet
13 2 krufter_multiclet
<pre>
14 2 krufter_multiclet
#include <HDL51001_ccf.h>
15 2 krufter_multiclet
16 2 krufter_multiclet
void function_add(int arg1, int arg2);
17 2 krufter_multiclet
18 2 krufter_multiclet
void main()
19 2 krufter_multiclet
{
20 2 krufter_multiclet
    int a,b;
21 2 krufter_multiclet
22 2 krufter_multiclet
    a = 19;
23 2 krufter_multiclet
    b = 7;
24 2 krufter_multiclet
    function_add(a,b);
25 2 krufter_multiclet
    a = 20;
26 2 krufter_multiclet
    b = 13;
27 2 krufter_multiclet
    function_add(a,b);
28 2 krufter_multiclet
}
29 2 krufter_multiclet
30 2 krufter_multiclet
</pre>
31 3 krufter_multiclet
32 3 krufter_multiclet
На ассемблере будет следующее:
33 3 krufter_multiclet
34 3 krufter_multiclet
<pre>
35 4 krufter_multiclet
.alias ron2 4 ; в реальной программе мы должны сохранить текущие значения РОНов в стеке и только потом их использовать и 
36 4 krufter_multiclet
.alias ron3 5 ; перед возвратом в Си восстановить их первоначальные значения, но для простоты примера мы это не сделаем.
37 3 krufter_multiclet
38 5 krufter_multiclet
;настриваем UART для платы HW1-MCp04
39 3 krufter_multiclet
.alias UART_DATA    UART0_DATA
40 3 krufter_multiclet
.alias UART_BDR     UART0_BDR
41 3 krufter_multiclet
.alias UART_ST      UART0_ST
42 3 krufter_multiclet
.alias UART_CR      UART0_CR
43 3 krufter_multiclet
44 3 krufter_multiclet
.alias UART_PORT_PIN  0x300
45 3 krufter_multiclet
.alias UART_PORT_BPS  GPIOB_BPS
46 3 krufter_multiclet
47 17 krufter_multiclet
.global function_add
48 3 krufter_multiclet
49 3 krufter_multiclet
.text
50 3 krufter_multiclet
51 17 krufter_multiclet
function_add:
52 3 krufter_multiclet
   rdl #SP, 4 ;получаем первый аргумент
53 3 krufter_multiclet
   rdl #SP, 8 ;получаем второй аргумент
54 3 krufter_multiclet
   addl @1, @2 ;складываем аргументы
55 3 krufter_multiclet
   setl #ron3, @1
56 3 krufter_multiclet
   jmp initUART
57 3 krufter_multiclet
complete
58 3 krufter_multiclet
59 3 krufter_multiclet
initUART:
60 3 krufter_multiclet
    getl 0x00000300
61 3 krufter_multiclet
    wrl @1, UART_PORT_BPS
62 3 krufter_multiclet
    getl 0x00000104
63 3 krufter_multiclet
    wrl @1, UART_BDR
64 3 krufter_multiclet
    getl 0x00000003
65 3 krufter_multiclet
    wrl @1, UART_CR
66 3 krufter_multiclet
    jmp send_byte_UART
67 3 krufter_multiclet
    setl #ron2, 7
68 3 krufter_multiclet
 complete
69 3 krufter_multiclet
70 3 krufter_multiclet
send_byte_UART:
71 3 krufter_multiclet
    getl #ron2
72 3 krufter_multiclet
    jne @1, send_byte_UART
73 3 krufter_multiclet
    je @2, buf_TXD
74 3 krufter_multiclet
    getq #ron3
75 3 krufter_multiclet
    slrq @1, 8
76 3 krufter_multiclet
    setq #ron3, @1
77 3 krufter_multiclet
    wrl @3, UART_DATA
78 3 krufter_multiclet
    subl @7, 1
79 3 krufter_multiclet
    setl #ron2, @1
80 3 krufter_multiclet
 complete
81 3 krufter_multiclet
82 3 krufter_multiclet
buf_TXD:
83 3 krufter_multiclet
    rdl UART_ST
84 3 krufter_multiclet
    getl 0x00000004
85 3 krufter_multiclet
    and @1, @2
86 3 krufter_multiclet
    je @1, buf_TXD
87 3 krufter_multiclet
    jne @2, return
88 3 krufter_multiclet
complete
89 3 krufter_multiclet
90 3 krufter_multiclet
return:
91 18 krufter_multiclet
    rdl #SP ;считываем адрес возврата
92 18 krufter_multiclet
    jmp @1 ;осуществляем переход обратно в Си
93 3 krufter_multiclet
complete
94 3 krufter_multiclet
95 3 krufter_multiclet
</pre>
96 6 krufter_multiclet
97 17 krufter_multiclet
Параграфы function_add и return составляют всю работы со стеком, т.е. работа со стеком заняла 4 команды.
98 1 krufter_multiclet
99 1 krufter_multiclet
h2. Для функции типа int
100 11 krufter_multiclet
101 11 krufter_multiclet
Пусть программа на ассемблере принимает два аргумента и выполняет их сложение, а также выдает результат в Си, где
102 11 krufter_multiclet
происходит его умножение и вместе с ещё одним аргументом функция на ассемблере вызывается ещё раз, результаты выводятся
103 11 krufter_multiclet
по UART на Си.
104 11 krufter_multiclet
105 11 krufter_multiclet
На Си вызов функции может выглядеть так:
106 11 krufter_multiclet
107 11 krufter_multiclet
<pre>
108 11 krufter_multiclet
#include <HDL51001_ccf.h>
109 11 krufter_multiclet
110 11 krufter_multiclet
int function_add(int arg1, int arg2);
111 11 krufter_multiclet
112 11 krufter_multiclet
void main()
113 11 krufter_multiclet
{
114 11 krufter_multiclet
    int a,b,c,d,e;
115 11 krufter_multiclet
    UART_InitTypeDef UART_InitStructure;
116 11 krufter_multiclet
    //настройка UART для отладочной платы HW1-MCp04
117 11 krufter_multiclet
    UART_InitStructure.BaudRate = 38400; //скорость
118 11 krufter_multiclet
    UART_InitStructure.TypeParity = 0x00000000; //тип контроля четности
119 11 krufter_multiclet
    UART_InitStructure.Parity = 0x00000000; //разрешение контроля четности
120 11 krufter_multiclet
    UART_InitStructure.FlowControl = 0x00000000; //разрешение аппаратного контроля
121 11 krufter_multiclet
    UART_InitStructure.Mode = 0x00000003; //разрешение работы на приём и передачу
122 11 krufter_multiclet
    
123 11 krufter_multiclet
    GPIOB->BPS = 0x00000F00;		 //разрешение альтернативных функций порта для uart0
124 11 krufter_multiclet
    uart_init(UART0, &UART_InitStructure); //инициализация
125 11 krufter_multiclet
126 11 krufter_multiclet
    a = 19;
127 11 krufter_multiclet
    b = 7;
128 11 krufter_multiclet
    c = function_add(a,b); //получаем результат работы функции на ассемблере
129 11 krufter_multiclet
    uart_send_int(c, UART0); //посылаем результат через uart0
130 11 krufter_multiclet
    c = c*2;
131 11 krufter_multiclet
    d = 20;
132 11 krufter_multiclet
    e = function_add(c,d);
133 12 krufter_multiclet
    uart_send_int(e, UART0);
134 11 krufter_multiclet
}
135 11 krufter_multiclet
136 11 krufter_multiclet
</pre>
137 13 krufter_multiclet
138 13 krufter_multiclet
На ассемблере будет следующее:
139 13 krufter_multiclet
140 13 krufter_multiclet
<pre>
141 19 krufter_multiclet
.global function_add
142 13 krufter_multiclet
143 13 krufter_multiclet
.text
144 13 krufter_multiclet
145 19 krufter_multiclet
function_add:
146 13 krufter_multiclet
    rdl #SP, 8 ;получаем первый аргумент
147 13 krufter_multiclet
    rdl #SP, 12 ;получаем второй аргумент
148 13 krufter_multiclet
    addl @1, @2 ;складываем аргументы
149 19 krufter_multiclet
    wrl @1, #SP, 4 ;записываем возвращаемое функцией значение
150 13 krufter_multiclet
    jmp return
151 13 krufter_multiclet
complete
152 13 krufter_multiclet
153 13 krufter_multiclet
return:
154 13 krufter_multiclet
    rdl #SP
155 19 krufter_multiclet
    jmp @1 ;осуществляем переход обратно в Си
156 13 krufter_multiclet
complete
157 13 krufter_multiclet
158 13 krufter_multiclet
</pre>
159 14 krufter_multiclet
160 16 krufter_multiclet
+Примечание:+ при использовании стека сборку проекта необходимо осуществлять вместе с файлом crt0.o, в разделе
161 16 krufter_multiclet
[[Сборка проекта]] в примере на Си данный файл подключается, если по каким-то причинам необходимо собрать
162 16 krufter_multiclet
проект только на ассемблере с использованием стека(например использование математической библиотеки), то этап 
163 16 krufter_multiclet
линковки должен осуществляться вместе с файлом crt0.o 
164 16 krufter_multiclet
165 14 krufter_multiclet
Также возникают ситуации, когда необходимо использовать стек в самой программе на ассемблере:
166 14 krufter_multiclet
- сохранить текущее значение РОНов
167 14 krufter_multiclet
- использовать стек для своих переменных
168 14 krufter_multiclet
169 14 krufter_multiclet
[[Пример использования стека в программе на ассемблере]], вызываемой из Си.