Вызов программы ASM из Си¶
Вызов программы, написанной на ассемблере из Си организован при помощи стека. Подробнее о стеке можно прочитать в Обзор работы со стеком.
Рассмотрим пример вызова процедуры, написанной на ассемблере, из Си функцией типа void.
Для функции типа void¶
Пусть программа на ассемблере принимает два аргумента и выполняет их сложение, а также выдает результат через UART на ассемблере.
На Си вызов функции может выглядеть так:
#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); }
На ассемблере будет следующее:
.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
Параграфы function_add и return составляют всю работы со стеком, т.е. работа со стеком заняла 4 команды.
Для функции типа int¶
Пусть программа на ассемблере принимает два аргумента и выполняет их сложение, а также выдает результат в Си, где
происходит его умножение и вместе с ещё одним аргументом функция на ассемблере вызывается ещё раз, результаты выводятся
по UART на Си.
На Си вызов функции может выглядеть так:
#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); }
На ассемблере будет следующее:
.global function_add .text function_add: rdl #SP, 8 ;получаем первый аргумент rdl #SP, 12 ;получаем второй аргумент addl @1, @2 ;складываем аргументы wrl @1, #SP, 4 ;записываем возвращаемое функцией значение jmp return complete return: rdl #SP jmp @1 ;осуществляем переход обратно в Си complete
Примечание: при использовании стека сборку проекта необходимо осуществлять вместе с файлом crt0.o, в разделе
Сборка проекта в примере на Си данный файл подключается, если по каким-то причинам необходимо собрать
проект только на ассемблере с использованием стека(например использование математической библиотеки), то этап
линковки должен осуществляться вместе с файлом crt0.o
Проект под ОС Windows можно собрать при помощи PSPad, просто добавив в проект файл на Си и файл на ассемблере.
Также возникают ситуации, когда необходимо использовать стек в самой программе на ассемблере:
- сохранить текущее значение РОНов
- использовать стек для своих переменных
Пример использования стека в программе на ассемблере, вызываемой из Си.