Микроконтроллеры, АЦП, память и т.д Темы касающиеся микроконтроллеров разных производителей, памяти, АЦП/ЦАП, периферийных модулей... |
27.06.2011, 10:57
|
|
Почётный гражданин KAZUS.RU
Регистрация: 08.05.2008
Адрес: регион 63
Сообщений: 1,827
Сказал спасибо: 739
Сказали Спасибо 683 раз(а) в 386 сообщении(ях)
|
Ассемблерная вставка в CodeVisionAVR вопросы
Тема вроде избитая, но переворошив кучу форумов ответов на простые вопросы я не нашел.
Первое , вот строки из Helpa CodeVision:
Цитата:
|
The registers R0, R1, R22, R23, R24, R25, R26, R27, R30 and R31 can be freely used in assembly routines.
However when using them in an interrupt service routine the programmer must save, respectively restore, them on entry, respectively on exit, of this routine.
|
Интересует выделенное место - Однако при их использовании в прерываниях программист должен сохранять, соответственно восстановливая их при входе, соответственно, при выходе.
То есть вроде бы должно быть так
Код:
|
#asm
PUSH R27
PUSH R30
PUSH R31
// тут сам код , в котором что либо с R27 R30 R31 происходит//
POP R31
POP R30
POP R27
#endasm |
но в той же справке по кодевижен есть пример использования ассемблерной функции
Код:
|
// function in assembler declaration
// this function will return a+b+c
#pragma warn- // this will prevent warnings
int sum_abc(int a, int b, unsigned char c) {
#asm
ldd r30,y+3 ;R30=LSB a
ldd r31,y+4 ;R31=MSB a
ldd r26,y+1 ;R26=LSB b
ldd r27,y+2 ;R27=MSB b
add r30,r26 ;(R31,R30)=a+b
adc r31,r27
ld r26,y ;R26=c
clr r27 ;promote unsigned char c to int
add r30,r26 ;(R31,R30)=(R31,R30)+c
adc r31,r27
#endasm
}
#pragma warn+ // enable warnings
void main(void) {
int r;
// now we call the function and store the result in r
r=sum_abc(2,4,6);
} |
здесь нет никакого сохранения регистров. зато далее написано :
Цитата:
|
After the return from the function the compiler automatically generates code to reclaim the Data Stack space used by the function parameters.
|
Так надо или нет производить сохранение используемых регистров в стек ?
Второй вопрос на который я тоже не нашел ответа - например объявляется регистровая переменная А register int А = 0b001
можно ли использовать её напрямую в операторах MOV INC DEC OUT ? или нужно предварительно произвести LDI Rd,А и после работать с Rd ? Опять же int занимает 2 байта , нужно учитывать это и обрабатывать Rd и Rd+1 ? или компилятор будет передавать в регистры не само значение а только указатель .
__________________
Да здравствует Разум,да сгинет Маразм!
Последний раз редактировалось E_C_C; 27.06.2011 в 11:06.
|
|
|
|
27.06.2011, 14:24
|
|
Гражданин KAZUS.RU
Регистрация: 04.08.2006
Сообщений: 911
Сказал спасибо: 28
Сказали Спасибо 180 раз(а) в 139 сообщении(ях)
|
Re: Ассемблерная вставка в CodeVisionAVR вопросы
Не работал с CodeVision, но в общем ваши вопросы скорее общие для всех компиляторов. Точнее ответы.
1. Совершенно очевидно, что в прерывании вы должны сохранить используемые регистры, о чём и пишет производитель. Иначе их нельзя использовать, так как они будут портится в прерывании. Указание на то, что вы их можете использовать - не противоречит. Смысл прост - это рабочие регистры и они могут использоваться для промежуточных вычислений. Например r0-r1 может использоваться при умножении. То есть надо разделять, что вы их можете использовать, но не хранить в них данные. Для хранения вы должны объявить регистровую переменную и разместить её в нужном регистре.
Приведенный пример, тоже абсолютно корректный. Там же не указано, что это прерывание. Просто обычная п/п. Так что вам непонятно?
2. Надо рассматривать переменную как переменную. Соответственно операция с ней в качестве регистра вызывет ошибку скорее всего. Загрузить её с пом. LD тоже не получится - не те адреса. Как это реализовано в конкретном компиляторе - я не знаю. Скорее всего вы должны объявить переменную а работать либо с регистрами либо с макросом. Я бы сделал так. Ну и в любом случае использование двухбайтовой переменной в ассемблерных инструкциях должно учитывать их двухбайтовость. Здесь надо понимать, что Си программу компилятор сгенерит в ASM, а потом ASM вместе с вашим куском прогонит ч/з ассемблер. И здесь никаких преобразований не будет. КАЖДАЯ инстукция ассемлера станет командой. Соответственно и надо поступать.
|
|
|
Эти 2 пользователя(ей) сказали Спасибо SasaVitebsk за это сообщение:
|
|
|
27.06.2011, 17:49
|
|
Частый гость
Регистрация: 23.05.2009
Сообщений: 46
Сказал спасибо: 1
Сказали Спасибо 4 раз(а) в 2 сообщении(ях)
|
Re: Ассемблерная вставка в CodeVisionAVR вопросы
Сообщение от E_C_C
|
...здесь нет никакого сохранения регистров. зато далее написано :
|
а там его и не должно быть - параметры в функцию передаются через регистры, а результат также возвращается через R31:R30, так зачем их сохранять , ну а прерывание это другое дело - сохраняешь те регистры которые используются.
|
|
|
Эти 2 пользователя(ей) сказали Спасибо kazusdoc за это сообщение:
|
|
|
29.06.2011, 00:57
|
|
Прохожий
Регистрация: 23.03.2011
Сообщений: 5
Сказал спасибо: 1
Сказали Спасибо 3 раз(а) в 2 сообщении(ях)
|
Re: Ассемблерная вставка в CodeVisionAVR вопросы
чтобы использовать регистровую переменную в ассемблерной вставке, необходимо, чтобы компилятор разместил эту переменную в определенном регистре (может и не разместить, поэтому весьма желательно отключить автоматическое размещение переменных в регистрах либо объявлять эту переменную первой). номер регистра указывается после символа @, стоящего после названия переменной:
Цитата:
|
If the automatic register allocation is disabled, you can use the register keyword to specify which global variable to be allocated to registers.
Example:
/* disable automatic register allocation */
#pragma regalloc-
/* allocate the variable ‘alfa’ to a register */
register int alfa;
/* allocate the variable ‘beta’ to the register pair R10, R11 */
register int beta @10;
|
глобальные переменные должны размещаться в регистрах R1-R15. локальные переменные должны размещаться в регистрах с R16 по R21. детали - в хелпе "Allocation of Variables to Registers"
|
|
|
Эти 2 пользователя(ей) сказали Спасибо justej за это сообщение:
|
|
|
29.06.2011, 17:14
|
|
Частый гость
Регистрация: 23.05.2009
Сообщений: 46
Сказал спасибо: 1
Сказали Спасибо 4 раз(а) в 2 сообщении(ях)
|
Re: Ассемблерная вставка в CodeVisionAVR вопросы
E_C_C вот рабочий пример. Чтоб компилятор не ругался, на то что функция не получает параметра пишем #pragma warn-
Код:
|
#pragma warn-
// вывод символа на LCD-индикатор через 74HC164
OutLed(unsigned char led_sym){
#asm
ld r31,Y ; r31=led_sym
ldi r30,8
loop:
sbrc r31,0 ;
sbi PORTB,PinData ; вывод 1
sbrs r31,0 ;
cbi PORTB,PinData ; вывод 0
sbi PORTD,PinClk ; выдаем clock
cbi PORTD,PinClk ;
lsr r31 ; сдвиг
dec r30 ; повторяем 8 раз (1 байт)
brne loop
#endasm
}
#pragma warn+ |
|
|
|
Эти 2 пользователя(ей) сказали Спасибо kazusdoc за это сообщение:
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 11:53.
|
|