Вызов программы ASM из Си » History » Version 16
krufter_multiclet, 07/19/2013 06:55 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 | 3 | krufter_multiclet | .global function_ex |
48 | 3 | krufter_multiclet | |
49 | 3 | krufter_multiclet | .text |
50 | 3 | krufter_multiclet | |
51 | 3 | krufter_multiclet | function_ex: |
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 | 3 | krufter_multiclet | rdl #SP |
92 | 3 | krufter_multiclet | jmp @1 |
93 | 3 | krufter_multiclet | complete |
94 | 3 | krufter_multiclet | |
95 | 3 | krufter_multiclet | </pre> |
96 | 6 | krufter_multiclet | |
97 | 8 | krufter_multiclet | Параграфы function_ex и 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 | 13 | krufter_multiclet | .global function_ex |
142 | 13 | krufter_multiclet | |
143 | 13 | krufter_multiclet | .text |
144 | 13 | krufter_multiclet | |
145 | 13 | krufter_multiclet | function_ex: |
146 | 13 | krufter_multiclet | rdl #SP, 8 ;получаем первый аргумент |
147 | 13 | krufter_multiclet | rdl #SP, 12 ;получаем второй аргумент |
148 | 13 | krufter_multiclet | addl @1, @2 ;складываем аргументы |
149 | 13 | 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 | 13 | 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 | [[Пример использования стека в программе на ассемблере]], вызываемой из Си. |