Табл.1. Арифметические и логические команды:
Команда |
Описание |
Действие |
Циклы |
Код операции |
Флаги |
ATtiny |
ATmega |
add Rd,Rr |
Add two Registers |
Rd←Rd+Rr |
1 |
0000 11rd dddd rrrr |
Z,C,S, |
+ |
+ |
adc Rd,Rr |
Add with Carry two Registers |
Rd←Rd+Rr+C |
1 |
0001 11rd dddd rrrr |
Z,C,S, |
+ |
+ |
adiw Rdl,K |
Add Immediate to Word |
Rdh:Rdl←Rdh:Rdl+K |
2 |
1001 0110 KKdd KKKK |
Z,C,S, |
± |
+ |
sub Rd,Rr |
Subtract two Registers |
Rd←Rd-Rr |
1 |
0001 10rd dddd rrrr |
Z,C,S, |
+ |
+ |
sbc Rd,Rr |
Subtract with Carry two Registers |
Rd←Rd-Rr-C |
1 |
0000 10rd dddd rrrr |
Z,C,S, |
+ |
+ |
subi Rd,K |
Subtract Constant from Register |
Rd←Rd-K |
1 |
1010 KKKK dddd KKKK |
Z,C,S, |
+ |
+ |
sbci Rd,K |
Subtract with Carry Constant from Register |
Rd←Rd-K-C |
1 |
0100 KKKK dddd KKKK |
Z,C,S, |
+ |
+ |
sbiw Rdl,K |
Subtract Immediate from Word |
Rdh:Rdl←Rdh:Rdl-K |
2 |
1001 0111 KKdd KKKK |
Z,C,S, |
± |
+ |
and Rd,Rr |
Logical AND Registers |
Rd←Rd AND Rr |
1 |
0010 00rd dddd rrrr |
Z,S,N |
+ |
+ |
andi Rd,K |
Logical AND Register and Constant |
Rd←Rd AND K |
1 |
0111 KKKK dddd KKKK |
Z,S,N |
+ |
+ |
or Rd,Rr |
Logical OR Registers |
Rd←Rd OR Rr |
1 |
0010 10rd dddd rrrr |
Z,S,N |
+ |
+ |
ori Rd,K |
Logical OR Register and Constant |
Rd←Rd OR K |
1 |
0110 KKKK dddd KKKK |
Z,S,N |
+ |
+ |
eor Rd,Rr |
Exclusive OR Registers |
Rd←Rd EOR Rr |
1 |
0010 01rd dddd rrrr |
Z,S,N |
+ |
+ |
com Rd |
One’s complement |
Rd←0xFF-Rd |
1 |
1001 010d dddd 0000 |
Z,S,N |
+ |
+ |
neg Rd |
Two’s complement |
Rd←0x00-Rd |
1 |
1001 010d dddd 0001 |
Z,C,S, |
+ |
+ |
sbr Rd,K |
Set Bit(s) in Register |
Rd←Rd OR K |
1 |
0110 KKKK dddd KKKK |
Z,S,N |
+ |
+ |
cbr Rd,K |
Clear Bit(s) in Register |
Rd←Rd AND (0xFF- K) |
1 |
0111 KKKK dddd KKKK |
Z,S,N |
+ |
+ |
inc Rd |
Increment |
Rd←Rd+1 |
1 |
1001 010d dddd 0011 |
Z,S, |
+ |
+ |
dec Rd |
Decrement |
Rd←Rd-1 |
1 |
1001 010d dddd 1010 |
Z,S, |
+ |
+ |
tst Rd |
Test for Zero or Minus |
Rd←Rd AND Rd |
1 |
0010 00dd dddd dddd |
Z,S,N |
+ |
+ |
clr Rd |
Clear Register |
Rd←Rd EOR Rd |
1 |
0010 01dd dddd dddd |
Z,S,N |
+ |
+ |
ser Rd |
Set Register |
Rd←0xFF |
1 |
1110 1111 dddd 1111 |
None |
+ |
+ |
mul Rd,Rr |
Multiply Unsigned |
R1:R0←Rd*Rr |
2 |
1001 11rd dddd rrrr |
Z,C |
- |
+ |
muls Rd,Rr |
Multiply Signed |
R1:R0←Rd*Rr |
2 |
0000 0010 dddd rrrr |
Z,C |
- |
+ |
mulsu Rd,Rr |
Multiply Signed with Unsigned |
R1:R0←Rd*Rr |
2 |
0000 0011 0ddd 0rrr |
Z,C |
- |
+ |
fmul Rd,Rr |
Fractional Multiply |
R1:R0←(Rd*Rr)<<1 |
2 |
0000 0011 0ddd 1rrr |
Z,C |
- |
+ |
fmuls Rd,Rr |
Fractional Multiply |
R1:R0←(Rd*Rr)<<1 |
2 |
0000 0011 1ddd 0rrr |
Z,C |
- |
+ |
fmulsu Rd,Rr |
Fractional Multiply |
R1:R0←(Rd*Rr)<<1 |
2 |
0000 0011 1ddd 1rrr |
Z,C |
- |
+ |
Как видно из табл.1, AVR имеют всего 3 разновидности команды сложения. Инструкции add Rd,Rr (Сложение двух регистров), adc Rd,Rr (Сложение двух регистров с учётом переноса), позволяют складывать как однобайтовые числа, так числа произвольной разрядности. В последнем случае для связи байтов используется флаг переноса C в регистре SREG, который устанавливается всякий раз, когда разрядность суммы превысит 8 бит. Этот перенос должен быть добавлен к сумме старших байтов командой adc Rd,Rr:
add R18,R16 ; сложение двухбайтовых чисел adc R19,R17 ; R19:R18 = R19:R18 + R17:R16
Сложение регистра с константой, к сожалению, отсутствует. И это приносит некоторые неудобства, так как приходится использовать две команды, одна из которых занесение числа во вспомогательный регистр, а уже вторая - сложение регистров:
ldi R17,0x30 ; заносим в R17 константу 0x30 add R16,R17 ; R16 = R17 + 0x30
Во многих случаях вышеуказанную проблему можно решить, используя команду adiw Rdl,K (Сложение константы со словом). Она позволяет прибавить 6-разрядную константу, лежащую в диапазоне 0…63, к одной из 4х регистровых пар Rdh:Rdl (R25:R24, R27:R26, R29:R28, R31:R30). С её помощью также удобно реализовать 16-разрядный счётчик событий:
key_press: adiw R24,1 ; инкрементируем счётчик R25:R24 sbis PINB,0 ; пока на линии 0 порта PORTB низкий rjmp key_press ; логический уровень
Из всех арифметических операций, вычитание в AVR - наиболее разнообразно по способам адресации.
Имеется две команды с прямой адресацией РОН: sub Rd,Rr (Вычитание двух регистров), sbc Rd,Rr (Вычитание двух регистров с учётом заема). При совместном использовании они позволяют получить разность чисел любой разрядности. Для связи байт, при этом, и здесь служит флаг C. Но в отличие от сложения он устанавливается, когда разность оказалась отрицательной(Rd < Rr) и имеет в этом случае смысл заема, который должен быть вычтен из разности старших байт командой sbc Rd,Rr:
sub R18,R16 ; вычитание двухбайтовых чисел sbc R19,R17 ; R19:R18 = R19:R18 - R17:R16
Ещё две команды с непосредственной адресацией используются для тех же целей: subi Rd,K (Вычитание константы из регистра) и sbсi Rd,K (Вычитание константы из регистра c учётом заёма). Эти инструкции очень универсальны. Их с одинаковым успехом можно применять как в целях вычитания, так и сложения. В последнем случае необходимо использовать представление числа K в дополнительном коде (т.е. изменить знак числа –K = 0xFF+1-K):
subi R16,-0x30 ; R16 = R16 + 0x30 = R16 – (-0x30)
Существует также инструкция, работающая в двухбайтовом формате, sbiw Rdl,K (Вычитание константы из слова). Подобно сложению adiw Rdl,K, с её помощью можно вычесть 6-разрядную K (0…63) из тех же самых регистровых пар (R25:R24, R27:R26, R29:R28, R31:R30). Главная область применения команды – реализация счётчика циклов:
delay: sbiw R24,1 ; декрементируем счётчик R25:R24 пока brne delay ; его содержимое не станет 0, формируя . ; задержку времени 4*R25:R24 циклов
Группа логических инструкций представлена 6-ю командами.
Операция “НЕ” производится по команде com Rd (Дополнение до одного). При этом фактически производится действие Rd←0xFF-Rd, при котором инвертируются все биты регистра. Команды and Rd,Rr (“Логическое И” регистров), andi Rd,K (“Логическое И” регистра и константы) и or Rd,Rr (“Логическое ИЛИ” регистров), ori Rd,K (“Логическое ИЛИ” регистра и константы) производят соответствующие логические операции как с регистрами, так и регистра с константой. Операция же “Исключающее ИЛИ” возможна только между регистрами. Для этих целей служит команда eor Rd,Rr (“Исключающее ИЛИ” регистров). Если провести операцию “Исключающее ИЛИ” регистра с самим собой (eor Rd,Rd), то будет получен нулевой результат (Rd←Rd EOR Rd = 0). Это свойство часто применяется, когда необходимо отчистить регистр, а команда eor Rd,Rd может иметь при этом альтернативную форму записи clr Rd (Очистить регистр). Кроме того, с помощью последовательности всего трех команд eor Rd,Rr можно обменять содержимое двух регистров (команда обмена РОНов у AVR отсутствует) местами не используя ни одной дополнительной ячейки памяти:
eor R16,R17 ; R16 = R16 XOR R17 eor R17,R16 ; R17 = R17 XOR (R16 XOR R17) = R16 eor R16,R17 ; R16 = (R16 XOR R17) XOR R16 = R17
Все описанные логические операции могут использоваться, например, в следующем контексте:
in R16,PORTB ;заносим для изменения РВВ PORTB в РОН R16 ori R16,(1«PB0)|(1«PB5) ;устанавливаем биты 0,5 в R16 andi R16,~((1«PB1)|(1«PB2));сбрасываем биты 1,2 в R16 out PORTB,R16 ;выводим изменённое значение R16 в PORTB eor R16,R16 ;обнуляем R16 out PORTC,R16 ;заносим 0 в PORTC
Как во многих других случаях, у инструкции ori Rd,K существует другая форма написания sbr Rd,K (Установка бита(ов) в регистре), числящаяся, однако, как самостоятельная команда. Применяя её необходимо помнить, что, несмотря на аббревиатуру, на самом деле производится именно операция “Логическое ИЛИ” регистра и битовой маски, а не установка битов в регистре. Так, например, для установки бита n в регистре Rd правильно писать sbr Rd,1<
in R16,PORTB ; заносим для изменения РВВ PORTB в РОН R16 sbr R16,(1«PB0)|(1«PB5) ; устанавливаем биты 0,5 в R16 cbr R16,(1«PB1)|(1«PB2) ; сбрасываем биты 1,2 в R16 out PORTB,R16 ; выводим изменённое значение R16 в PORTB clr R16 ; обнуляем R16 out PORTC,R16 ; заносим 0 в PORTC
Когда надо установить все биты регистра, то можно воспользоваться инструкцией ser Rd (Установка регистра), которая заносит константу 0xFF в регистр Rd. Она является частной формой написания команды ldi Rd,K (Загрузка константы в регистр), относящейся к группе команд пересылки. Подобное действие можно осуществить и другими способами. Например, в результате команды ori R16,0xFF все биты регистра R16 также будут установленными.
Но в отличие от ser R16 или, что тоже самое, ldi R16,0xFF - будут изменены значения флагов N и Z, что может повлиять на правильный ход выполнение программы. По той же причине в ряде случаев для обнуления регистра лучше использовать ldi R16,0 вместо clr R16 (eor R16,R16); все флаги в регистре SREG останутся неизменными. Единственное, что мешает повсеместному применению команды ldi Rd,K, это ограниченный набор РОН с которыми она работает. Только регистры R16…R31 могут использоваться с этой инструкцией. Это существенное ограничение наложено и на все арифметические и логические команды, которые используют непосредственную адресацию (действие над регистром и константой).
На практике часто необходимо осуществить проверку регистра на нуль. Проще всего это сделать если произвести операцию “Логическое И” регистра самим с собой (and Rd,Rd). При этом содержимое Rd останется неизменным, а в регистре SREG будет установлен флаг нулевого результата Z если Rd = 0. Параллельно с ним будет переопределён и флаг N, который в случае использования знаковых чисел будет свидетельствовать об отрицательном содержимом регистра. Для инструкции and Rd,Rn где Rd = Rn, может быть использована другая форма записи в виде псевдокоманды tst Rd (Проверка на нуль и минус).
В тех случаях, когда необходимо изменить знак однобайтового числа используют команду neg Rd (Дополнение до двух). Она осуществляет действие Rd←0x00-Rd и используется только для чисел представленных дополнительном коде.
У AVR имеются также команды прямого и обратного счёта. Первая из них inc Rd (Инкремент) увеличивает на единицу содержимое регистра, а вторая dec Rd (Декремент), соответственно, уменьшает. Конечно, действия инкрементирования и декрементирования могут быть заменены, например, на прибавление 1 и вычитание 1 из регистра Rd (subi R16,-1 эквивалентно inc R16, а subi R16,1 тоже, что и dec Rd). Но, несмотря на это обе команды имеют большое самостоятельное значение. Главная их особенность в том, что они не влияют на флаг переноса C и тем самым оптимизированы для формирования циклов, в которых он может использоваться:
ldi R16,SIZE ; производим сдвиг числа, clc ; находящегося в ОЗУ и состоящего из rleft: ld R17,X ; SIZE байт на один разряд влево rol R17 st X+,R18 dec R16 brne rleft .
Дополняет группу арифметических команд умножение однобайтовых чисел. В зависимости от формата представления множителя и множимого, существует 6 вариаций данной операции. Произведение, полученное по команде умножения (2-байтовая величина) заносится в регистровую пару R1:R0. Эта интересная аппаратная особенность AVR позволяет очень быстро обработать результат, так как он размещается в РОН и может быть перемещён в любое место всего одной командой пересылки. Следует, однако, предварительно позаботится о сохранении содержимого регистров R1, R0 если они используются в программе.
Для умножения целых чисел разработаны три команды: mul Rd,Rr (Умножение беззнаковых чисел), muls Rd,Rr (Умножение знаковых чисел), mulsu Rd,Rr (Умножение знакового числа на беззнаковое).
Знаковые числами должны быть представлены в дополнительном коде. При этом для первых двух команд безразлично на месте каких операндов будут находиться множитель и множимое. К одному и тому же результату приведут, например, mul R16,R17 и mul R17,R16 (muls R16,R17 и muls R17,R16). В случае mulsu Rd,Rr на месте Rd обязательно должно стоять знаковое число. Помимо флага Z (один из операндов 0), умножение оказывает влияние и на флаг переноса C. В него заносится старший бит регистра R1. Таким образом, в командах muls Rd,Rr, mulsu Rd,Rr он фактически является флагом знака и устанавливается когда произведение отрицательное. Необходимо также помнить, что инструкция muls Rd, Rr может использоваться только с регистрами R16…R31. Ещё меньше поддерживает команда mulsu Rd,Rr, только R16…R23.
Существует ряд специфических приложений, в которых может понадобиться умножения дробных чисел с фиксированной запятой. Главная задача, где это может быть необходимо, - цифровая обработка сигналов. Для дробного умножения имеются команды: fmul Rd,Rr (Умножение дробных беззнаковых чисел), fmuls Rd,Rr (Умножение дробных знаковых чисел), fmulsu Rd,Rr (Умножение дробного знакового числа на беззнаковое). Все команды работают с числами в формате (1.7). Старший бит регистра является целой частью числа, а младшие 7 битов отведены под дробную. Произведение приводится к формату (2.14). Для этого производится сдвиг результата на один разряд влево так, что старший разряд оказывается во флаге C. Все инструкции дробного умножения работают только с регистрами R16…R23.
Перейти к следующей части: Команды пересылки данных
Комментарии (0) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация