Professor
May 16 2006, 18:07
Суть вопроса состоит в том чтоб в асемблерной вставке обратится к масиву чисел и одно из чисел извлечь.... Массив должен быть описан как unsigned char... Как его правильно описать и как его вызывать в асемблерной вставке....
Вставка организованна таким образом:
В main.c:
extern void set_int(void);
void main(void){
set_int();
}
В Text file.asm:
NAME set_int
#include <iom16.h>
PUBLIC set_int
RSEG CODE
set_int:
; (в этом месте и надо обратится и извлеч число из масива)
ret
END set_int
Заранее благодарю за помощь.....
rezident
May 16 2006, 18:15
А где обозначен сам массив из которого нужно извлекать число? И какой смысл для такой простой операции вызывать функию, да еще и ассемблерную?
Professor
May 16 2006, 18:21
Цитата(rezident @ May 16 2006, 21:15)

А где обозначен сам массив из которого нужно извлекать число? И какой смысл для такой простой операции вызывать функию, да еще и ассемблерную?
Суть вопроса в том что етот кусочек кода надо сделать максимально оптимизированным по скорости....
В самой функции будьт еще другой код... но это уже не важно... с остальным кодом вопросов нет...
А где именно обозначить этот массив для решени проблеммы не имет никакого значения...
GetSmart
May 16 2006, 18:31
Ух как давно я не писал для AVR!
NAME set_int
#include <iom16.h>
PUBLIC set_int
RSEG CODE
EXTERN chartabl
set_int:
; (в этом месте и надо обратится и извлечЬ число из масива)
ldi ZL,LOW(chartabl)
ldi ZH,HIGH(chartabl)
ld r0,Y ; или ld r0,Y+ если нужно с инкрементом
ret
END set_int
_______________________
Это если массив расположен в RAM. А если во флэше, то так:
NAME set_int
#include <iom16.h>
PUBLIC set_int
RSEG CODE
EXTERN chartabl
set_int:
; (в этом месте и надо обратится и извлечЬ число из масива)
ldi ZL,LOW(chartabl*2)
ldi ZH,HIGH(chartabl*2)
lpm ; или lpm rx,z+ , где rx - любой регистр, и можно z, z+, y, y+
ret
END set_int
хотя могу ошибаться на счёт умножения на 2. Я это делал когда метка находилась в этом же ASM-файле. Глобальный адрес может уже быть умножен на 2.
Professor
May 16 2006, 18:37
Цитата(GetSmart @ May 16 2006, 21:31)

Ух как давно я не писал для AVR!
NAME set_int
#include <iom16.h>
PUBLIC set_int
RSEG CODE
EXTERN chartabl
set_int:
; (в этом месте и надо обратится и извлечЬ число из масива)
ldi ZL,LOW(chartabl)
ldi ZH,HIGH(chartabl)
ld r0,Y ; или ld r0,Y+ если нужно с инкрементом
ret
END set_int
_______________________
Это если массив расположен в RAM. А если во флэше, то так:
NAME set_int
#include <iom16.h>
PUBLIC set_int
RSEG CODE
EXTERN chartabl
set_int:
; (в этом месте и надо обратится и извлечЬ число из масива)
ldi ZL,LOW(chartabl*2)
ldi ZH,HIGH(chartabl*2)
lpm ; или lpm rx,z+ , где rx - любой регистр, и можно z, z+, y, y+
ret
END set_int
хотя могу ошибаться на счёт умножения на 2. Я это делал когда метка находилась в этом же ASM-файле. Глобальный адрес может уже быть умножен на 2.
А где и как описать сам масив если массив расположен во флеше???
GetSmart
May 16 2006, 18:38
Чё-то я намудрил немного. Вобщем так. Если указатель загружается в пару ZH:ZL то далее указывается ld Rx,Z или ld Rx,Z+. А если пара YH:YL то ld Rx,Y или ld Rx,Y+. А ещё можно через пару XH:XL и команду ld Rx,X или ld Rx,X+.
Professor
May 16 2006, 18:40
Цитата(GetSmart @ May 16 2006, 21:38)

Чё-то я намудрил немного. Вобщем так. Если указатель загружается в пару ZH:ZL то далее указывается ld Rx,Z или ld Rx,Z+. А если пара YH:YL то ld Rx,Y или ld Rx,Y+. А ещё можно через пару XH:XL и команду ld Rx,X или ld Rx,X+.
А где и как описать сам масив если массив расположен во флеше???
GetSmart
May 16 2006, 18:46
Ну блин так и писали бы в начале. Я-то думал, что у вас сишный проект с асмовской вставкой и массив уже описан в си-файле. Значит так:
NAME set_int
#include <iom16.h>
PUBLIC set_int
RSEG CODE
set_int:
; (в этом месте и надо обратится и извлечЬ число из масива)
ldi ZL,LOW(LightTabl*2)
ldi ZH,HIGH(LightTabl*2)
; тут добавляете к паре ZH:ZL нужное смещение
lpm ; или lpm Rx,Z+ , где Rx - любой регистр, и можно Z, Z+
ret ; возвращаемый результат в регистре Rx
LightTabl:
.db 255,250,245,240,234,229,225,220,215,210,206,201,197,193,188,184
.db 180,176,172,169,165,161,158,154,151,147,144,141,138,134,131,128
.db 125,123,120,117,114,111,109,106,104,101,99,96,94,92,90,87
END set_int
Professor
May 16 2006, 19:14
set_int:
; (в этом месте и надо обратится и извлечЬ число из масива)
ldi ZL,LOW(LightTabl*2)
ldi ZH,HIGH(LightTabl*2)
; тут добавляете к паре ZH:ZL нужное смещение
lpm ; или lpm Rx,Z+ , где Rx - любой регистр, и можно Z, Z+
END set_int
[/quote]
А если надо извлечь не один из эелементов массива а один раз к примеру нулевой а вдругой раз первый как вызывать элемент массива в таком случае(когда номер извлекаемого элемента массива всегда меняется)?
GetSmart
May 16 2006, 19:28
Цитата
А если надо извлечь не один из эелементов массива а один раз к примеру нулевой а вдругой раз первый как вызывать элемент массива в таком случае(когда номер извлекаемого элемента массива всегда меняется)?
Я же написал ремарку - "тут добавляете к паре ZH:ZL нужное смещение". Вы можете добавить к паре ZH,ZL любое нужное число - смещение в байтах от начала таблицы. Откуда вы его будете брать - ваши дела. А после того, как добавите, выполняете команду LPM. Ну и с результатом делаете что хотите. Судя по прототипу процедуры, возвращать его не нужно. Можете извлекать хоть десять чисел подряд.
Если ещё не понятно, то уточните заодно тип проца.
Professor
May 16 2006, 19:50
Цитата(GetSmart @ May 16 2006, 22:28)

"тут добавляете к паре ZH:ZL нужное смещение"
А добавлять смещение таким образом:
add ZL, rx
add ZH, rx
где rx регистр в котором храниться номер извлекаемого эелемента....
????
ПРОЦ ATmega16
GetSmart
May 16 2006, 20:21
Блин, да вы вообще в асме ни бум-бум.
Во-первых, добавлять надо так:
add ZL, r0
adc ZH, r1
то есть с переносом.
Откуда взять r1:r0 ? Зависит от вас. Можете передавать из си-шного кода в качестве параметра процедуры. Можете объявить глобальную переменную WORD в RAM, в сишном коде её менять, а в асмовом читать и использовать в качестве индекса. Можете и читать и изменять только в асмовом файле. Вариантов до кучи.
Пока вы не опишите в одном посте сразу все требования к логике работы процедуры общаться так отрывками смысла нет.
Хинт: вместо add/adc оптимальнее применять subi/sbci, чтобы обойтись без лишних загрузок.
Цитата(Professor @ May 16 2006, 21:07)

Суть вопроса состоит в том чтоб в асемблерной вставке обратится к масиву чисел и одно из чисел извлечь.... Массив должен быть описан как unsigned char... Как его правильно описать и как его вызывать в асемблерной вставке....
Выдумываете себе проблемы, чтобы потом с успехом их преодолевать? Зачем вообще нужны ассемблерные вставки? Это и некрасиво, и неэффективно.
Сергей Борщ
May 19 2006, 13:23
самый эффективный способ:
main.c
Код
#include <stdint.h>
uint8_t const __flash Array[8] = {1,2,3,4,5,6,7,8};
extern void AsmFunc(void);
void main (void) {
AsmFunc();
}
Asm_fish.c:
Код
#include <stdint.h>
extern uint8_t const __flash Array[8];
uint8_t Tmp;
void AsmFunc(void) {
uint8_t i;
for(i = 0; i < 3; i++) {
Tmp = Array[i*2];
}
}
Ставишь галочку "генерить ассемблерный файл" в опцияк компилятора на вкладке листинг, компилишь, внимательно изучаешь полученную "рыбу". Или пишешь нужную функцию полностью на С, компилишь, получаешь ассемблерный исходник и его оптимизируешь. Только не забудь прочитать в документации какие регистры функция может портить, а какие должна сохранять.
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.