Табл 3. Команды передачи управления:
Команда |
Описание |
Действие |
Циклы |
Код операции |
Флаги |
ATtiny |
ATmega |
rjmp k |
Relative Jump |
PC←PC+k+1 |
2 |
1100 kkkk kkkk kkkk |
None |
+ |
+ |
ijmp |
Indirect Jump to (Z) |
PC←(Z) |
2 |
1001 0100 0000 1001 |
None |
± |
+ |
eijmp |
Extended Indirect |
PC←(EIND:Z) |
2 |
1001 0100 0001 1001 |
None |
- |
± |
jmp k |
Direct Jump |
PC←k |
3 |
1001 010k kkkk 110k |
None |
- |
± |
rcall k |
Relative Subroutine Call |
STACK←PC+1, |
3/4 |
1101 kkkk kkkk kkkk |
None |
+ |
+ |
icall |
Indirect Call to (Z) |
STACK←PC+1, PC←(Z), |
3/4 |
1001 0101 0000 1001 |
None |
± |
+ |
eicall |
Extended Indirect |
STACK←PC+1, |
4 |
1001 0101 0001 1001 |
None |
- |
± |
call k |
Direct Subroutine Call |
STACK←PC+1, PC←k, |
4/5 |
1001 010k kkkk 111k |
None |
- |
± |
ret |
Subroutine Return |
PC←STACK, |
4/5 |
1001 0101 0000 1000 |
None |
+ |
+ |
reti |
Interrupt Return |
PC←STACK, |
4/5 |
1001 0101 0001 1000 |
I |
+ |
+ |
cpse Rd,Rr |
Compare, Skip if Equal |
if(Rd=Rr) |
1/2/3 |
0001 00rd dddd rrrr |
None |
+ |
+ |
cp Rd,Rr |
Compare |
Rd-Rr |
1 |
0001 01rd dddd rrrr |
Z,C,S, |
+ |
+ |
cpc Rd,Rr |
Compare with Carry |
Rd-Rr-C |
1 |
0000 01rd dddd rrrr |
Z,C,S, |
+ |
+ |
cpi Rd,K |
Compare Register with Immediate |
Rd-Rr-K |
1 |
0011 KKKK dddd KKKK |
Z,C,S, |
+ |
+ |
sbrc Rr,b |
Skip if Bit in |
if(Rr(b)=0) |
1/2/3 |
1111 110r rrrr obbb |
None |
+ |
+ |
sbrs Rr,b |
Skip if Bit in |
if(Rr(b)=1) |
1/2/3 |
1111 111r rrrr obbb |
None |
+ |
+ |
sbic P,b |
Skip if Bit in IO |
if(P(b)=0) |
1/2/3 |
1001 1001 PPPP Pbbb |
None |
+ |
+ |
sbis P,b |
Skip if Bit in IO |
if(P(b)=1) |
1/2/3 |
1001 1011 PPPP Pbbb |
None |
+ |
+ |
brbc s,k |
Branch if Status |
if(SREG(s)=0) |
1/2 |
1111 01kk kkkk ksss |
None |
+ |
+ |
brbs s,k |
Branch if Status |
if(SREG(s)=1) |
1/2 |
1111 00kk kkkk ksss |
None |
+ |
+ |
brcc k |
Branch if Carry |
if(C=0) PC←PC+k+1 |
1/2 |
1111 01kk kkkk k000 |
None |
+ |
+ |
brcs k |
Branch if Carry |
if(C=1) PC←PC+k+1 |
1/2 |
1111 00kk kkkk k000 |
None |
+ |
+ |
brsh k |
Branch if Same |
if(C=0) PC←PC+k+1 |
1/2 |
1111 01kk kkkk k000 |
None |
+ |
+ |
brlo k |
Branch if Lower |
if(C=1) PC←PC+k+1 |
1/2 |
1111 00kk kkkk k000 |
None |
+ |
+ |
brne k |
Branch if Not Equal |
if(Z=0) PC←PC+k+1 |
1/2 |
1111 01kk kkkk k001 |
None |
+ |
+ |
breq k |
Branch if Equal |
if(Z=1) PC←PC+k+1 |
1/2 |
1111 00kk kkkk k001 |
None |
+ |
+ |
brpl k |
Branch if Plus |
if(N=0) PC←PC+k+1 |
1/2 |
1111 01kk kkkk k010 |
None |
+ |
+ |
brmi k |
Branch if Minus |
if(N=1) PC←PC+k+1 |
1/2 |
1111 00kk kkkk k010 |
None |
+ |
+ |
brvc k |
Bruach if Overflow |
if(V=0) PC←PC+k+1 |
1/2 |
1111 01kk kkkk k011 |
None |
+ |
+ |
brvs k |
Branch if Overflow |
if(V=1) PC←PC+k+1 |
1/2 |
1111 00kk kkkk k011 |
None |
+ |
+ |
brge k |
Branch if Greate or |
if(S=0) PC←PC+k+1 |
1/2 |
1111 01kk kkkk k100 |
None |
+ |
+ |
brlt k |
Branch if Less than |
if(S=1) PC←PC+k+1 |
1/2 |
1111 00kk kkkk k100 |
None |
+ |
+ |
brhc k |
Branch if Half Carry |
if(H=0) PC←PC+k+1 |
1/2 |
1111 01kk kkkk k101 |
None |
+ |
+ |
brhs k |
Branch if Half Carry |
if(H=1) PC←PC+k+1 |
1/2 |
1111 00kk kkkk k101 |
None |
+ |
+ |
brtc k |
Branch if Transfer |
if(T=0) PC←PC+k+1 |
1/2 |
1111 01kk kkkk k110 |
None |
+ |
+ |
brts k |
Branch if Transfer |
if(T=1) PC←PC+k+1 |
1/2 |
1111 00kk kkkk k110 |
None |
+ |
+ |
brid k |
Branch if Interrupt |
if(T=0) PC←PC+k+1 |
1/2 |
1111 01kk kkkk k111 |
None |
+ |
+ |
brie k |
Branch if Interrupt |
if(T=1) PC←PC+k+1 |
1/2 |
1111 00kk kkkk k111 |
None |
+ |
+ |
Все команды группы передачи управления приведены в табл.3. Микроконтроллеры AVR могут содержать до 4-х разновидностей команды безусловного перехода. Команды такого типа модифицируют
содержимое программного счётчика, после чего программа продолжает выполняться с нового места (адреса перехода). Безусловный переход в памяти программ происходит не зависимо от каких либо условий, флагов программы и т.д.
Инструкция rjmp k (Относительный безусловный переход) позволяет осуществить переход в диапазоне +2047…-2047 слов в памяти программ от места где она расположена. Адрес перехода при этом зависит от текущего значения программного счётчика и вычисляется как смещение PC+1+k.
Команда ijmp (Косвенный безусловный переход) производит переход в памяти программ в пределах 0…65535 слов по адресу, находящемуся в индексном регистре Z. В этом случае адрес перехода является переменной величиной доступной из программы. Это даёт возможность легко реализовать процедуру ветвления, когда в зависимости от условий должен быть выполнен тот или иной фрагмент кода.
В моделях с объёмом памяти программ 256 кб доступна также команда eijmp (Расширенный безусловный косвенный переход). Она использует 3-байтовый указатель адреса EIND:ZH:ZL. В регистре EIND из пространства РВВ находится 17-тый бит адреса, а переход осуществляется в пределах 0…131071 слов.
Команда jmp k (Абсолютный безусловный переход) - переход по адресу k в любую точку из любого места программы. Абсолютный адрес перехода находится в коде операции, а команда занимает 2 слова (4 байта) и выполняется в течении 3-х машинных циклов.
При использовании команд передачи управления в качестве параметров обычно используют метки, в место которых после компоновки программы будут подставлены реальные адреса (смещения относительно адреса):
ldi ZL,low(label) ;косвенный переход на метку label ldi ZH,high(label) ijmp . jmp label ;абсолютный переход на метку label . rjmp label ;относительный переход на метку label . .org 0x0200 label:. ;метка в программе по адресу 0x0200
Другим типом команд являются вызовы подпрограмм. Существуют следующие их разновидности: rcall k (Относительный вызов подпрограммы), icall (Косвенный вызов подпрограммы), eicall (Расширенный косвенный вызов подпрограммы) и call k (Абсолютный вызов подпрограммы). Функционируют такие инструкции аналогично командам безусловного перехода, но с одним существенным отличием. Перед переходом в памяти программ, адрес следующей команды предварительно сохраняется в специально отведённой для этих целей области памяти (стеке). Таким образом, находясь в любой точке программы, сохраняется возможность вернутся в то место, из которого был осуществлен вызов. Это действие осуществляет команда ret (Возврат из подпрограммы). Она загружает в PC сохранённый в стеке адрес возврата, после чего программа продолжает выполняться со следующей команды после rcall k, icall, eicall, call k:
ldi ZL,low(func1);косвенный вызов подпрограммы func1 ldi ZH,high(func1) icall . call func1 ;абсолютный вызов подпрограммы func1 . rcall func1 ;относительный вызов подпрограммы func1 . func1:. ;подпрограмма func1 call func2 ;абсолютный вызов подпрограммы func2 . ret ;возврат из подпрограммы func1 func2:. ;подпрограмма func2 ret ;возврат из подпрограммы func2
В приведенном примере подпрограмма func1 может вызываться много раз из различных мест программы. Кроме того, в теле самой подпрограммы func1 могут содержаться вызовы различных подпрограмм (вызов func2 и т.д.). Такая организация программы позволяет максимально эффективно использовать ресурсы процессора, делает код более наглядным и позволяет многократно использовать разработанные подпрограммы в дальнейших проектах.
Еще одним скрытым механизмом вызова подпрограмм являются аппаратные прерывания. При их возникновении происходит вызов подпрограммы (обработчика прерывания) по фиксированному адресу (вектору прерывания), при этом адрес возврата также запоминается в стеке. Но в отличии от вызова по командам rcall k, icall, eicall, call k ещё и автоматически сбрасывается флаг глобального разрешения прерываний I в регистре SREG, т.е. запрещаются прерывания во время прерывания. Для выхода из прерывания используется команда reti (Возврат из прерывания) которая, загружает в PC адрес возврата и восстанавливает флаг I (разрешает прерывания при выходе из прерывания):
.org 0x0002 rjmp service_INT0 ;вектор внешнего прерывания INT0 .org 0x0100 service_ INT0: ̣̣̣̣̣̣̣̣ ;обработчик прерывания INT0 reti ;возврат в основную программу
Иногда командой reti удобно завершить и обычную подпрограмму. Так бывает, когда, например, при выходе необходимо разрешить прерывания. В этом случае она фактически заменяет собой две инструкции sei (Разрешение прерываний) и ret:
func: cli ;глобальный запрет прерываний (I=0) . reti ;выход из подпрограммы и разрешение прерываний
Время выполнения rcall k, icall, call k, ret, reti зависит от величины программного счётчика конкретной модели. Если его разрядность более 16 бит (≥ 128 кб FLASH памяти), то для сохранения 3-байтового адреса возврата требуется на один машинный цикл больше.
В данную группу команд включены также 4 инструкции сравнения: cp Rd,Rr (Сравнить регистры), cpс Rd,Rr (Сравнить регистры с учётом переноса), cpi Rd,K (Сравнить регистр c константой), cpse Rd,Rr (Сравнить регистры и пропустить команду если они равны). Строго говоря первые три из них не являются командами передачи управления, так как не могут оказать влияние на счётчик программ. Единственным их предназначением является сравнение числовых величин, находящихся в РОН. Как видно из описания, команда cp Rd,Rr аналогична sub Rd,Rr, вместо cpc Rd,Rr фактически выполняется sbc Rd,Rr, а вместо cpi Rd,K - cubi Rd,K. Разница заключается только лишь в том, что содержимое регистра Rd остаётся неизменным. При этом переопределяется значение флагов Z,C,S, N,V,H регистра SREG по которым и можно судить о соотношении между числовыми величинами. В частности, сравнение двухбайтовых чисел находящихся в регистровых парах R19:R18 R17:R16 можно выполнить следующим образом:
cp R18, R16 ; сравнение 2-байтовых чисел cpc R19, R17 ; R19:R18 - R17:R16
В этом примере флага C окажется установленным, когда R19:R18< R17:R16 (сброшенным, когда R19:R18>R17:R16). Что касается флага Z, то в данном случае он не может быть критерием проверки на нуль (Z=1 будет свидетельствовать только о равенстве R19=R17+C).
Стоит заметить также, что, подобно всем остальным командам, использующим непосредственную адресацию, cpi Rd,K может работать только с регистрами R16…R31.
Инструкция cpse Rd,Rr выполняется иначе. Она относится к типу Test and Skip (Проверка и пропуск). По логике работы команды такого рода выполняют проверку определённого условия и если оно истинно (в данном случае если Rd=Rr), то следующая в тексте команда пропускается. При этом все флаги программы остаются неизменными.
Помимо этого существуют ещё 4 команды Test and Skip ориентированных на проверку состояния определённого бита в регистрах. Две из них работают с РОН: sbrc Rr,b (Пропуск команды, если бит регистра сброшен), sbrs Rr,b (Пропуск команды, если бит регистра установлен). Ещё две с РВВ: sbic P,b (Пропуск команды, если бит регистра ввода-вывода сброшен), sbis P,b (Пропуск команды, если бит регистра ввода-вывода установлен). Если бит b(0…7) установлен при выполнении команд sbrs Rr,b и sbis P,b или сброшен для sbrc Rr,b, sbic P,b, то производится пропуск следующей команды. Нижеприведённый код демонстрирует программную задержку до тех пор пока не будет нажата кнопка подключённая к линии 1 порта B (пока бит 1 РВВ PINB не будет сброшен):
button_press: sbic PINB,1 ; задержка пока на выводе 1 порта B rjmp button_press ; не появится низкий уровень .
В отличии от команд sbrs Rr,b, sbrc Rr,b, которые работают со всеми без исключения РОН, инструкции sbis P,b, sbic P,b могут использовать только первые 32 РВВ. Если учесть, что число управляющих РВВ на много больше то, это довольно существенное ограничение. Конечно те РВВ, доступ к битам которых наиболее важен, разработчики постарались разместить именно в этой области. К ним относятся все регистры управления портами A,B,C,D,E,F, а также ряд других, отвечающих за работу EEPROM, USART, SPI т.д. Во всех остальных случаях необходимо cкопировать содержимое РВВ в один из РОН и уже дальше анализировать состояние соответствующего бита. Программное ожидание сброса бита 2 порта J должно выглядеть следующим образом:
button_press: lds R16,PINJ ; задержка пока на выводе 2 порта J sbrc R16,2 ; не появится низкий уровень rjmp button_press .
Время выполнения инструкций Test and Skip может быть различным в зависимости от того пропускается следующая команда или нет. В первом случае необходимо 2 машинных цикла, во втором 1. Если же производится пропуск “длинной” команды состоящей из двух слов (lds Rd,k, jmp k и т.д.) на выполнение операции уйдёт 3 цикла.
Флаги программы регистра состояния также не доступны инструкциям sbis P,b, sbic P,b, но из-за важности их значения предусмотрены две команды условного перехода разработанных специально для работы с SREG: brbs s,k (Переход, если бит регистра SREG установлен), brbc s,k (Переход, если бит регистра SREG сброшен). Когда соответствующий бит s в SREG установлен для brbs s,k или сброшен для brbс s,k производится относительный переход в пределах +63…-63 слов (PC+k+1).
Ассемблер AVR поддерживает по 9 различных форм написания инструкций brbs s,k, brbc s,k для разных значений флагов программы (табл.4).
Табл 4. Команды условных переходов по состоянию флагов SREG:
Проверка |
Команда условного |
Альтернативная |
Условие перехода |
C |
brbc 0,k |
brcc k |
Переход если флаг переноса установлен |
brsh k |
Переход если больше или равно |
||
brbs 0,k |
brcs k |
Переход если флаг переноса сброшен |
|
brlo k |
Переход если меньше |
||
Z |
brbc 1,k |
breq k |
Переход если равно |
brbs 1,k |
brne k |
Переход если не равно |
|
N |
brbc 2,k |
brpl k |
Переход если плюс |
brbs 2,k |
brmi k |
Переход если минус |
|
V |
brbc 3,k |
brvc k |
Переход если флаг дополнительного кода сброшен |
brbs 3,k |
brvs k |
Переход если флаг дополнительного кода установлен |
|
S |
brbc 4,k |
brge k |
Переход если больше или равно нулю (знаковое) |
brbs 4,k |
brlt k |
Переход если меньше нуля (знаковое) |
|
H |
brbc 5,k |
brhc k |
Переход если флаг половинного переноса сброшен |
brbs 5,k |
brhs k |
Переход если флаг половинного переноса установлен |
|
T |
brbc 6,k |
brtc k |
Переход если флаг хранения бита сброшен |
brbs 6,k |
brts k |
Переход если флаг хранения бита установлен |
|
I |
brbc 7,k |
brid k |
Переход если прерывания запрещены |
brbs 7,k |
brie k |
Переход если прерывания разрешены |
В ходе программы, как правило, наиболее часто производится проверка флагов Z и C. Если установка флага Z однозначно свидетельствует о нулевом результате операции, то установка флага переноса C может иметь разный смысл в зависимости от того, какая команда оказывает на него влияние.
Следующая подпрограмма осуществляет инкрементирование 4-байтового счётчика R27:R26:R25:R24, а проверка флага C производится с целью установить, происходит ли переполнение младшего слова R25:R24, и если да, то к старшей регистровой паре R27:R26 добавляется 1:
inc_cnt: adiw R24,1 ; добавление 1 к регистровой паре R25:R24 brcc PC+2 ; и если возникает перенос, то adiw R26,1 ; увеличение на 1 регистровой пары R27:R26 ret
Другим примером, где необходимо знать состояние флага C, может служить сравнение чисел:
cpi R16,0x40 ; сравнить содержимое R16 с числом 0x40 brlo ulo ; перейти наметку ulo если R16 < 0x40 . ulo: .
Вместо brcc k, здесь используется более подходящая по смыслу форма написания инструкции brlo k (переход если R16 меньше 0x40).
Подобный понятный символический вид имеют и остальные команды условных относительных переходов: breq k(Переход если равно 0), brne k(Переход если не равно 0), brie k (Переход если прерывания разрешены), brid k (Переход если прерывания запрещены) и т.д.
Перейти к следующей части: Группа команд операций с битами
Комментарии (0) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация