Project

General

Profile

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

Version 18 (krufter_multiclet, 07/19/2013 07:16 PM) → Version 19/20 (krufter_multiclet, 07/19/2013 07:18 PM)

h1. Вызов программы ASM из Си

Вызов программы, написанной на ассемблере из Си организован при помощи стека. Подробнее о стеке можно прочитать в [[Обзор работы со стеком]].

Рассмотрим пример вызова процедуры, написанной на ассемблере, из Си функцией типа *void*.

h2. Для функции типа void

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

На Си вызов функции может выглядеть так:

<pre>
#include <HDL51001_ccf.h>

void function_add(int arg1, int arg2);

void main()
{
int a,b;

a = 19;
b = 7;
function_add(a,b);
a = 20;
b = 13;
function_add(a,b);
}

</pre>

На ассемблере будет следующее:

<pre>
.alias ron2 4 ; в реальной программе мы должны сохранить текущие значения РОНов в стеке и только потом их использовать и
.alias ron3 5 ; перед возвратом в Си восстановить их первоначальные значения, но для простоты примера мы это не сделаем.

;настриваем UART для платы HW1-MCp04
.alias UART_DATA UART0_DATA
.alias UART_BDR UART0_BDR
.alias UART_ST UART0_ST
.alias UART_CR UART0_CR

.alias UART_PORT_PIN 0x300
.alias UART_PORT_BPS GPIOB_BPS

.global function_add

.text

function_add:
rdl #SP, 4 ;получаем первый аргумент
rdl #SP, 8 ;получаем второй аргумент
addl @1, @2 ;складываем аргументы
setl #ron3, @1
jmp initUART
complete

initUART:
getl 0x00000300
wrl @1, UART_PORT_BPS
getl 0x00000104
wrl @1, UART_BDR
getl 0x00000003
wrl @1, UART_CR
jmp send_byte_UART
setl #ron2, 7
complete

send_byte_UART:
getl #ron2
jne @1, send_byte_UART
je @2, buf_TXD
getq #ron3
slrq @1, 8
setq #ron3, @1
wrl @3, UART_DATA
subl @7, 1
setl #ron2, @1
complete

buf_TXD:
rdl UART_ST
getl 0x00000004
and @1, @2
je @1, buf_TXD
jne @2, return
complete

return:
rdl #SP ;считываем адрес возврата
jmp @1 ;осуществляем переход обратно в Си
complete

</pre>

Параграфы function_add и return составляют всю работы со стеком, т.е. работа со стеком заняла 4 команды.

h2. Для функции типа int

Пусть программа на ассемблере принимает два аргумента и выполняет их сложение, а также выдает результат в Си, где
происходит его умножение и вместе с ещё одним аргументом функция на ассемблере вызывается ещё раз, результаты выводятся
по UART на Си.

На Си вызов функции может выглядеть так:

<pre>
#include <HDL51001_ccf.h>

int function_add(int arg1, int arg2);

void main()
{
int a,b,c,d,e;
UART_InitTypeDef UART_InitStructure;
//настройка UART для отладочной платы HW1-MCp04
UART_InitStructure.BaudRate = 38400; //скорость
UART_InitStructure.TypeParity = 0x00000000; //тип контроля четности
UART_InitStructure.Parity = 0x00000000; //разрешение контроля четности
UART_InitStructure.FlowControl = 0x00000000; //разрешение аппаратного контроля
UART_InitStructure.Mode = 0x00000003; //разрешение работы на приём и передачу

GPIOB->BPS = 0x00000F00; //разрешение альтернативных функций порта для uart0
uart_init(UART0, &UART_InitStructure); //инициализация

a = 19;
b = 7;
c = function_add(a,b); //получаем результат работы функции на ассемблере
uart_send_int(c, UART0); //посылаем результат через uart0
c = c*2;
d = 20;
e = function_add(c,d);
uart_send_int(e, UART0);
}

</pre>

На ассемблере будет следующее:

<pre>
.global function_add function_ex

.text

function_add: function_ex:
rdl #SP, 8 ;получаем первый аргумент
rdl #SP, 12 ;получаем второй аргумент
addl @1, @2 ;складываем аргументы
wrl @1, #SP, 4 ;записываем возвращаемое функцией значение
jmp return
complete

return:
rdl #SP
jmp @1 ;осуществляем переход обратно в Си
complete

</pre>

+Примечание:+ при использовании стека сборку проекта необходимо осуществлять вместе с файлом crt0.o, в разделе
[[Сборка проекта]] в примере на Си данный файл подключается, если по каким-то причинам необходимо собрать
проект только на ассемблере с использованием стека(например использование математической библиотеки), то этап
линковки должен осуществляться вместе с файлом crt0.o

Также возникают ситуации, когда необходимо использовать стек в самой программе на ассемблере:
- сохранить текущее значение РОНов
- использовать стек для своих переменных

[[Пример использования стека в программе на ассемблере]], вызываемой из Си.