Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Keil и thumb ассемблер ARM
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
drum1987
Создал си проект программы имеющую асм подрограмму, при этом абсолютно не могу понять каким образом передавать данные подпрограмме и извлекать результат(что в какие регистры попадает и по каким правилам).

Еще один момент это использование asm вставок в режиме Thumb (ни в какую не компилируется и не могу понять в чем загвоздка). Пробовал:

asm("MOV R1, R0");
__asm("MOV R1, R0");


Ошибка: использование inline ассемблера не возможно в режиме Thumb.


main файл:

#include <stdio.h>
extern void strcopy(int d, int s);
int main()
{ int srcstr = 3;
int dststr = 1;
/* dststr is an array since we’re going to change it */
strcopy(dststr,srcstr);
return (0);
}


Функция strcopy находится в файле scopy.s с содержанием:

PRESERVE8
AREA SCopy, CODE, READONLY
EXPORT strcopy
THUMB
strcopy ; R0 points to destination string.
; R1 points to source string.
MOV R1,#2 ; Load byte and update address.
MOV R2,#5 ; Store byte and update address.
BX lr ; Return.
END


Компилируется, работает, однако значение srcstr не возвращается.


Только начинаю работать со связкой асм+си пожэтому сильно не пинайте(или пните в сторону туда где чего почитать).

Проект прилагаю.
aaarrr
Цитата(drum1987 @ Mar 16 2011, 12:52) *
Создал си проект программы имеющую асм подрограмму, при этом абсолютно не могу понять каким образом передавать данные подпрограмме и извлекать результат(что в какие регистры попадает и по каким правилам).

Правила описаны в стандарте AAPCS.

Цитата(drum1987 @ Mar 16 2011, 12:52) *
Еще один момент это использование asm вставок в режиме Thumb (ни в какую не компилируется и не могу понять в чем загвоздка).

Так сами же себе и ответили ведь:
Цитата(drum1987 @ Mar 16 2011, 12:52) *
Ошибка: использование inline ассемблера не возможно в режиме Thumb.

scifi
Цитата(drum1987 @ Mar 16 2011, 12:52) *
Только начинаю работать со связкой асм+си пожэтому сильно не пинайте(или пните в сторону туда где чего почитать).

Почитать, как обычно, в руководстве пользователя:
RealView Compiler User Guide
RealView Compiler Reference Guide

Цитата(drum1987 @ Mar 16 2011, 12:52) *
Ошибка: использование inline ассемблера не возможно в режиме Thumb.

Если Вы почитаете руководство, то обнаружите, что этот компилятор не поддерживает функцию inline assembler при генерации кода Thumb:
Differences from previous versions of the ARM C/C++ compilers

Цитата(drum1987 @ Mar 16 2011, 12:52) *
Компилируется, работает, однако значение srcstr не возвращается.

Поясните. Работает, но не работает? Что должно было произойти, и что на самом деле произошло?
drum1987
Цитата(scifi @ Mar 16 2011, 17:16) *
Поясните. Работает, но не работает? Что должно было произойти, и что на самом деле произошло?

Работает, но возвращаемую переменную я не знаю как словитьsm.gif я хотел бы знать как в соответствие регистру поставить указатель на переменную передаваемую или возвращаемую подпрограмме.

Доки щас прочитаю. На счет inline ассемблера понял.
scifi
Цитата(drum1987 @ Mar 16 2011, 13:37) *
Работает, но возвращаемую переменную я не знаю как словитьsm.gif

Ну ё-маё. У Вас же эта функция объявлена с типом возвращаемого значения void. И Вы ещё хотите словить возвращаемое значение? Пора обратно за парту. Срочно штудируйте учебник языка Си.
RabidRabbit
Вот например, что работает в Keil у меня:
CODE
// 24c32.h

#ifndef _24C32_H_
#define _24C32_H_


#define EEPROM_PAGE_SIZE 32

//
int readBytesFrom24C32( unsigned int eepromStartAddr, unsigned char * dest, unsigned int bytesToRead );
//
int i2cSavePagesTo24C32( unsigned int eepromStartPageAddr, unsigned char * src, unsigned int pagesToWrite );

#endif

CODE
; 24c32.s

AREA TEXT, CODE, READONLY
ARM


EXPORT readBytesFrom24C32

; read bytes from 24C32
; IN
; r0 - start address in 24C32
; r1 - target buffer address in memory
; r2 - bytes count
; OUT
; r0 - error state, == 0 if no errors
readBytesFrom24C32
stmfd SP!, {r1,r2,r5-r11,LR}
; prepare transfer address and work constants
bl i2cSetTransferAddress
; check result
tst r8, r8
movne r0, r8
bne readBytesFrom24C32_exit
; set another start condition
bl i2cMakeStart
; check result
tst r8, r8
movne r0, r8
bne readBytesFrom24C32_exit
; send address with /WR=1
ldr r9, =0xA1
bl i2cSendByte
; get ACK
bl i2cReadAckState
bne readBytesFrom24C32_deviceNotFound
; read one byte
readBytesFrom24C32_loop
bl i2cRecvByte
; store byte to buffer
strb r9, [r1], #1
; send ACK or NACK
cmp r2, #1
; drop SDA to 0 if need receive more bytes
strne r6, [r7, #PIO_OER]
; rise SDA to 1 if it was last byte
streq r6, [r7, #PIO_ODR]
; pulse SCL
str r5, [r7, #PIO_ODR] ; SCL = 1
bl i2cDelay
str r5, [r7, #PIO_OER] ; SCL = 0
bl i2cDelay
; loop
subs r2, r2, #1
bne readBytesFrom24C32_loop
; make stop
; rise SCL up
str r5, [r7, #PIO_ODR] ; SCL = 1
bl i2cDelay
; rise SDA up
str r6, [r7, #PIO_ODR] ; SDA = 1
bl i2cDelay
ldr r0, =0
readBytesFrom24C32_exit
ldmfd SP!, {r1,r2,r5-r11,PC}
readBytesFrom24C32_deviceNotFound
ldr r0, =ERR_I2C_DEVICE_NOT_FOUND
b readBytesFrom24C32_exit


EXPORT i2cSavePagesTo24C32

; save 1 or more pages (32 bytes per page) to EEPROM
; IN
; r0 - start address in EEPROM (32 bytes aligned!)
; r1 - source buffer in local memory
; r2 - pages count
; OUT
; r0 - error state, = 0 if no errors
i2cSavePagesTo24C32
stmfd SP!, {r1,r2,r5-r12,LR}
i2cSavePagesTo24C32_loop
; tries count
ldr r12, =120
i2cSavePagesTo24C32_waitLoop
; prepare transfer address and work constants
bl i2cSetTransferAddress
; check result
tst r8, r8
beq i2cSavePagesTo24C32_sendPage
subs r12, r12, #1
bne i2cSavePagesTo24C32_waitLoop
;ldr r0, =ERR_WRITE_PAGE_TIMEOUT
mov r0, r8
b i2cSavePagesTo24C32_exit
i2cSavePagesTo24C32_sendPage
; send page
ldr r12, =EEPROM_24C32_PAGE_SIZE
i2cSavePagesTo24C32_pageLoop
ldrb r9, [r1], #1
bl i2cSendByte
; get ACK
bl i2cReadAckState
ldrne r0, =ERR_I2C_ACK_NOT_RECEIVED
bne i2cSavePagesTo24C32_exit
; next byte
subs r12, r12, #1
bne i2cSavePagesTo24C32_pageLoop
; make stop
; drop SDA down
str r6, [r7, #PIO_OER] ; SDA = 0
bl i2cDelay
; rise SCL up
str r5, [r7, #PIO_ODR] ; SCL = 1
bl i2cDelay
; rise SDA up
str r6, [r7, #PIO_ODR] ; SDA = 1
bl i2cDelay
; next page addr
add r0, r0, #EEPROM_24C32_PAGE_SIZE
; next page loop
subs r2, r2, #1
bne i2cSavePagesTo24C32_loop
; delay after last page write
ldr r12, =71000
i2cSavePagesTo24C32_delayLoop
subs r12, r12, #1
bne i2cSavePagesTo24C32_delayLoop
ldr r0, =0
i2cSavePagesTo24C32_exit
ldmfd SP!, {r1,r2,r5-r12,PC}
drum1987
Цитата(scifi @ Mar 16 2011, 18:03) *
Ну ё-маё. У Вас же эта функция объявлена с типом возвращаемого значения void. И Вы ещё хотите словить возвращаемое значение? Пора обратно за парту. Срочно штудируйте учебник языка Си.

прошу прощенья, но эту функцию драл с примера...действия она делала немного другие, но строку возвращала smile3046.gif


вот например пример 6.1 по адресу http://www.keil.com/support/man/docs/armcc...cc_caciddae.htm тоже void
yashok
Цитата
вот например пример 6.1 по адресу http://www.keil.com/support/man/docs/armcc...cc_caciddae.htm тоже void

Функция в примере никакого значения не возвращает.
Просто копирует содержимое памяти с одного адреса в место с другим адресом, пока не встретиться ноль.
drum1987
Цитата(yashok @ Mar 16 2011, 19:50) *
Функция в примере никакого значения не возвращает.
Просто копирует содержимое памяти с одного адреса в место с другим адресом, пока не встретиться ноль.

С этим разобрался. Спасибо.

У меня вопрос немного иной(наверное я его плохо сформулировал):

У меня есть функция к примеру int MULT(int A, int B )
но при этом в самой асм функции я могу оперировать лишь r0,r1....
Так вот по какому правилу у меня распределятся A,B и результат в регистры?

Цитата(aaarrr @ Mar 16 2011, 17:00) *
Правила описаны в стандарте AAPCS.


Пропустил...Это то, что мне нужно
aaarrr
Цитата(drum1987 @ Mar 16 2011, 16:57) *
Так вот по какому правилу у меня распределятся A,B и результат в регистры?

Тыц
drum1987
изучил вопрос, но одна деталь осталась открытой:
как быть если необходимо передать функции больше чем 4 переменных, и как поступись в случае если требуется фунции передавать данные так:

mult(out, out, in, in, param, param, param)
yashok
Попробуйте написать функции с требуемым количеством аргументов на си. Запустите все это дело в симуляторе и посмотрите в дисассемблере как с это сделал компилятор.
aaarrr
Цитата(drum1987 @ Mar 18 2011, 11:36) *
как быть если необходимо передать функции больше чем 4 переменных

В этом случае используется стек.

Цитата(drum1987 @ Mar 18 2011, 11:36) *
как поступись в случае если требуется фунции передавать данные так:

mult(out, out, in, in, param, param, param)

Поясните, чем этот случай отличается от "более четырех параметров"?
drum1987
Цитата(aaarrr @ Mar 18 2011, 19:16) *
Поясните, чем этот случай отличается от "более четырех параметров"?

Это был один и тот же вопрос...

Код
#include <stdio.h>

static __asm int MUL_F1(int rezult, int x, int y)
{
     smull r5, r0, r2, r1;
     BX   lr          ; Return.
}

static __inline int MUL_F2(int x, int y)
{
    volatile int rezult;
    MUL_F1(rezult, x, y);
    return rezult;
}

int main(void)
{
volatile int x=0xfffff, y=0xffff;
volatile int z;

z=MUL_F2(x, y);
}


Наваял прогу, после выполнения асм функции MUL_F1 в R0 как и положено кладется нужный мне результат, но перевенная rezult не меняется.

Понимаю что косяк детский и скорее всего я просто чтото не понимаю, поэтому прошу сильно не пинать...
yashok
Цитата
Наваял прогу, после выполнения асм функции MUL_F1 в R0 как и положено кладется нужный мне результат, но перевенная rezult не меняется

А почему она должна меняться?? Вы предаете параметры по значению.
aaarrr
По порядку:
1. В своей подпрограмме вы не имеете права портить R5. Можно портить только R0-R3 и R12.
2. Результат должен возвращается в R0.

Код
static __asm int MUL_F1(int x, int y)
{
    smull r0, r0, r1;
    BX   lr         ; Return.
}

int main(void)
{
    int x=0xfffff, y=0xffff;
    int z;

    z=MUL_F1(x, y);
}


3. Вы передаете rezult как параметр, получить что-либо обратно в него нельзя.
Чтобы иметь возможность что-то вернуть, можно использовать указатель:

Код
static __asm void MUL_F1(int *res, int x, int y)
{
    smull r1, r1, r2;
    str r1, [r0]
    BX   lr         ; Return.
}

int main(void)
{
    int x=0xfffff, y=0xffff;
    int z;

    MUL_F1(&z, x, y);
}

drum1987
Спасибо. Сделал как написали все заработало cheers.gif
Но еще остался один вопрос:
Собственно в асм я полез в надежде ускорить выполнение программы, и попытался "ускорить" простые функции например функция умножения 32 на 32 бит и результат 32 бит:

#define MUL_F(A,B ) (real_t)(((int64_t)(A)*(int64_t)(B )+(1 << (31))) >> 32) // так она была сделана до меня

я сделал функцию:

static INLINE __asm real_t MUL_F(real_t x, real_t y)
{
smull r0, r1, r0, r1;
lsr r1, #31;
add r0, r0, r1;
lsl r0, #1;
mul r0, r1, #2;
BX lr ; Return.
}


в итоге проиграл 30 процентов(естественно при включении оптимизации по времени выполнения программы). Получается действительно компилятор в данном случае царь и бог или я чтото не так делаю?
aaarrr
Цитата(drum1987 @ Mar 21 2011, 15:34) *
Получается действительно компилятор в данном случае царь и бог или я чтото не так делаю?

С умножением компилятору точно не следует "помогать". Посмотрите и сравните дизассемблированный текст в обоих случаях.
scifi
Цитата(drum1987 @ Mar 21 2011, 15:34) *
в итоге проиграл 30 процентов(естественно при включении оптимизации по времени выполнения программы). Получается действительно компилятор в данном случае царь и бог или я чтото не так делаю?

Оптимизацию делают не так. Вот правильная методология:
1) Испытываем программу. Смотрим, хватает ли скорости.
2) Если не хватает, ищем медленные куски кода, собирая объективную информацию (время выполнения кусков кода).
3) Возможно, применение другого алгоритма позволит вписаться в требования по скорости выполнения.
4) Если ясно, что переписывание небольшого куска кода на ассемблере по-видимому позволит вписаться в требования по скорости выполнения, то так и делаем.

Если пропустите шаги 1-3, то рискуете потратить кучу времени на оптимизацию, которая не даст никакого полезного результата.
В данном случае потраченное время можно списать на изучение средств разработки.
Ну и, как заметил aaarrr, не нужно соревноваться с компилятором в умножении, от это и так хорошо умеет делать.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.