Табл 2. Команды пересылки данных:
Команда |
Описание |
Действие |
Циклы |
Код операции |
Флаги |
ATtiny |
ATmega |
mov Rd,Rr |
Move Between Registers |
Rd←Rr |
1 |
0010 11rd dddd rrrr |
None |
+ |
+ |
movw Rd,Rr |
Copy Register Word |
Rd+1:Rd←Rr+1:Rr |
1 |
0000 0001 dddd rrrr |
None |
± |
+ |
ldi Rd,K |
Load Immediate |
Rd←K |
1 |
1110 KKKK dddd KKKK |
None |
+ |
+ |
ld Rd,X |
Load Indirect |
Rd←(X) |
2 |
1001 000d dddd 1100 |
None |
± |
+ |
ld Rd,X+ |
Load Indirect and |
Rd←(X), X←X+1 |
2 |
1001 000d dddd 1101 |
None |
± |
+ |
ld Rd,-X |
Load Indirect and |
X←X-1, Rd←(X) |
2 |
1001 000d dddd 1110 |
None |
± |
+ |
ld Rd,Y |
Load Indirect |
Rd←(Y) |
2 |
1000 000d dddd 1000 |
None |
± |
+ |
ld Rd,Y+ |
Load Indirect and |
Rd←(Y), Y←Y+1 |
2 |
1001 000d dddd 1001 |
None |
± |
+ |
ld Rd,-Y |
Load Indirect and |
Y←Y-1, Rd←(Y) |
2 |
1001 000d dddd 1010 |
None |
± |
+ |
ldd Rd,Y+q |
Load Indirect with Displacement |
Rd←(Y+q) |
2 |
10q0 qq0d dddd 1qqq |
None |
± |
+ |
ld Rd,Z |
Load Indirect |
Rd←(Z) |
2 |
1000 000d dddd 0000 |
None |
+ |
+ |
ld Rd,Z+ |
Load Indirect and |
Rd←(Z), Z←Z+1 |
2 |
1001 000d dddd 0001 |
None |
± |
+ |
ld Rd,-Z |
Load Indirect and |
Z←Z-1, Rd←(Z) |
2 |
1001 000d dddd 0010 |
None |
± |
+ |
ldd Rd,Z+q |
Load Indirect with Displacement |
Rd←(Z+q) |
2 |
10q0 qq0d dddd 0qqq |
None |
± |
+ |
lds Rd,k |
Load Direct from SRAM |
Rd←(k) |
2 |
1001 000d dddd 0000 |
None |
± |
+ |
st X,Rr |
Store Indirect |
(X)←Rr |
2 |
1001 001r rrrr 1100 |
None |
± |
+ |
st X+,Rr |
Store Indirect and |
(X)←Rr, X←X+1 |
2 |
1001 001r rrrr 1101 |
None |
± |
+ |
st -X,Rr |
Store Indirect and |
X←X-1, (X)←Rr |
2 |
1001 001r rrrr 1110 |
None |
± |
+ |
st Y,Rr |
Store Indirect |
(Y)←Rr |
2 |
1000 001r rrrr 1000 |
None |
± |
+ |
st Y+,Rr |
Store Indirect and |
(Y)←Rr, Y←Y+1 |
2 |
1001 001r rrrr 1001 |
None |
± |
+ |
st -Y,Rr |
Store Indirect and |
Y←Y-1, (Y)←Rr |
2 |
1001 001r rrrr 1010 |
None |
± |
+ |
std Y+q,Rr |
Store Indirect with Displacement |
(Y+q)← Rr |
2 |
10q0 qq1r rrrr 1qqq |
None |
± |
+ |
st Z,Rr |
Store Indirect |
(Z)←Rr |
2 |
1000 001r rrrr 0000 |
None |
+ |
+ |
st Z+,Rr |
Store Indirect and |
(Z)←Rr, Z←Z+1 |
2 |
1001 001r rrrr 0001 |
None |
± |
+ |
st -Z,Rr |
Store Indirect and |
Z←Z-1, (Z)←Rr |
2 |
1001 001r rrrr 0010 |
None |
± |
+ |
std Z+q,Rr |
Store Indirect with Displacement |
(Z+q)← Rr |
2 |
10q0 qq1r rrrr 0qqq |
None |
± |
+ |
sts k,Rr |
Store Direct to SRAM |
(k)←Rr |
2 |
1001 001r rrrr 0000 |
None |
± |
+ |
lpm |
Load Program Memory |
R0←(Z) |
3 |
1001 0101 1100 1000 |
None |
+ |
+ |
lpm Rd,Z |
Load Program Memory |
Rd←(Z) |
3 |
1001 000d dddd 0100 |
None |
± |
+ |
lpm Rd,Z+ |
Load Program Memory |
Rd←(Z), Z←Z+1 |
3 |
1001 000d dddd 0101 |
None |
± |
+ |
elpm |
Extended Load |
R0←(RAMPZ:Z) |
3 |
1001 0101 1101 1000 |
None |
- |
± |
elpm Rd,Z |
Extended Load |
Rd←(RAMPZ:Z) |
3 |
1001 000d dddd 0110 |
None |
- |
± |
elpm Rd,Z+ |
Extended Load Program Memory and Post-Inc. |
Rd←(RAMPZ:Z), |
3 |
1001 000d dddd 0111 |
None |
- |
± |
spm |
Store Program Memory |
(Z)←R1:R0 |
- |
1001 0101 1110 1000 |
None |
± |
+ |
in Rd,P |
In Port |
Rd←P |
1 |
1011 0PPd dddd PPPP |
None |
+ |
+ |
out P,Rr |
Out Port |
P←Rr |
1 |
1011 1PPr rrrr PPPP |
None |
+ |
+ |
push Rr |
Push Register in Stack |
STACK←Rr, SP←SP-1 |
2 |
1001 001r rrrr 1111 |
None |
± |
+ |
pop Rd |
Pop Register from Stack |
SP←SP+1, Rd←STACK |
2 |
1001 000d dddd 1111 |
None |
± |
+ |
Группа команд пересылки данных сведена в табл.2. Под определением пересылки (перемещения) в данном случае понимается копирование содержимого источника без его изменения в приёмник. При этом ни одна из инструкций пересылок не влияет ни на какие флаги регистра состояния SREG. Множество возможностей адресации позволяют с одинаковым успехом обрабатывать как отдельные байты так и массивы данных. При этом часто существует несколько путей для реализации той или иной операции.
В пределах РОН пересылка производится с помощью команды mov Rd,Rr (Пересылка между регистрами). Кроме этого, имеется возможность перемещения двухбайтовых чисел (регистровых пар R1:R0, R3:R2,…, R29:R28, R31:R30) с помощью команды movw Rd,Rr (Пересылка между регистровыми парами), где на месте операндов Rd и Rr должны стоять младшие регистры в обозначениях регистровых парах приёмника и источника соответственно (например, movw R0, R30 для пересылки R1:R0 ← R31:R30). Обе эти команды выполняются за один машинный цикл:
mov R17,R16 ; возведение в квадрат R16 mul R17,R16 ; с помещением двухбайтового результата movw R16,R0 ; в регистровую пару R17:R16
Для загрузки константы в регистр служит команда с непосредственной адресацией ldi Rd,K (Загрузка константы в регистр). Она работает только со старшими РОНами (R16…R31).
Команды для работы с SRAM микроконтроллера используют, в основном, косвенную адресацию. Для этих целей применяются три 16-разрядных индексных регистра X,Y,Z, которые находятся в адресном пространстве РОН и по совместительству также являются регистровыми парами R27:R26, R29:R28, R31:R30.
Копировать байт из памяти ОЗУ в РОН можно любой из команд: ld Rd,X, ld Rd,Y, ld Rd,Z (Косвенное чтение из памяти данных). В этом случае в регистре приёмнике окажется содержимое ячейки памяти данных, адрес которой находится в одном из индексных регистров. Кроме этого, существует ещё две вариации данного действия. В одной из них после копирования производится инкрементирование регистров X,Y,Z, на что указывает знак “+” в командах: ld Rd,X+, ld Rd,Y+, ld Rd,Z+ (Косвенное чтение из памяти данных с постинкрементом). Во втором случае, перед пересылкой, содержимое индексного регистра сначала уменьшается на 1 (знак “-” в команде): ld Rd,-X, ld Rd,-Y, ld Rd,-Z (Косвенное чтение из памяти данных с преддекрементом).
Команды косвенного чтения с постинкрементом/преддекрементом очень эффективны при работе с массивами однотипных данных. Для обращения же к элементам структуры (набору данных разного типа) удобно использовать ld Rd,Y+q, ld Rd,Z+q (Косвенное относительное чтение из памяти данных), в которых в качестве указателей используется Y,Z со смещением q (адрес ячейки памяти определяет сумма (Y)+q или (Z)+q). Смещение q в командах -фиксированная величина, лежащая в пределах 0…63.
Пересылка данных из РОН в ОЗУ посредством косвенной адресации реализуется с помощью команд: st X,Rr, st Y,Rr, st Z,Rr (Косвенная запись в память данных). Содержимое регистра в них копируется в ячейку памяти, адрес которой определяется указателями X,Y и Z соответственно. Точно также существуют команды загрузки с постинкрементом st X+,Rr, st Y+,Rr, st Z+,Rr (Косвенная запись в память данных с постинкрементом) и с преддекрементом индексного регистра st -X,Rr, st -Y,Rr, st -Z, Rr (Косвенная запись в память данных с преддекрементом). Ещё две команды этой группы используют косвенную адресацию со смещением: st Y+q,Rr, st Z+q,Rr (Косвенная относительная запись в память данных). Здесь смещение q может находится в пределах 0…63.
Как видно между командами выгрузки из памяти и загрузки в память существует полная симметрия. У каждой операции пересылки существует аналогичная, для пересылки в обратном направлении, причём с использованием трёх равноправных индексных регистров. Кроме того все они выполняются за один промежуток времени в 2 машинных цикла. Типичный пример их совместного использования может выглядеть следующим образом:
ldi YL, low(buffer1) ; копирование SIZE байт из ldi YH, high(buffer1) ; буфера buffer1 в буфер buffer2 ldi ZL, low(buffer2) ; перед копированием в индексные ldi ZH, high(buffer2) ; регистры Y и Z заносятся адреса ldi R16,SIZE ; буферов buffer1 и buffer2 copy: ld R17,Y+ st Z+,R17 dec R16 brne copy .
Копирование данных из ОЗУ в РОН и обратно может быть произведено и с использованием прямой адресации по командам lds Rd,k (Прямое чтение из памяти данных) и sts k,Rr (Прямая запись в память данных) соответственно. В этом случае двухбайтовый адрес k ячейки памяти находится в коде операции, а сами команды занимают 2 слова (4 байта) памяти программ.
Все вышеуказанные команды пересылок работают в едином адресном пространстве где под РОН отведены адреса 0x00…0x1F, под РВВ от 0x20…0x5F, остальное под ячейки ОЗУ. Поэтому, например, копирование R16←R17 может быть произведено разными путями: mov R16,R17, lds R16,0x0011, ld R16,X (в регистре X адрес 0x0011) и т.д. Первый способ здесь, конечно, более предпочтительный (использует пересылку типа регистр-регистр и выполняется быстрее), но остальные команды позволяют получить доступ к произвольному элементу любой области памяти и поэтому очень универсальны.
Для обращения к РВВ служат команды: in Rd,P (Ввод из порта), out P,Rr (Вывод в порт). Первая считывает значение РВВ в один из РОНов, а вторая производит пересылку РОН в РВВ.
Поскольку напрямую модифицировать РВВ невозможно, приходится сначала копировать их содержимое в рабочие РОН, производить необходимые изменения, а потом заносить обратно:
in R16,PORTC ; запись и модификация РВВ, andi R16,0b00001111 ; отвечающего за содержимое порта out PORTC,R16
Тоже самое относится и к данным, расположенным в ОЗУ:
lds R16,0x0200 ; запись и модификация байта из ОЗУ, inc R16 ; находящегося по абсолютному адресу 0x0200 sts 0x0200,R16
В группе команд пересылки данных имеются две, специально разработанные для работы со стеком. Это push Rr (Сохранение в стеке) и pop Rd (Извлечение из стека). Не смотря на то, что основное назначение стека это сохранение адресов возврата при вызове подпрограмм, эти инструкции позволяют использовать его и для оперативного сохранения данных, находящихся в РОН. Командой push Rr содержимое регистра копируется в ячейку памяти (вершину стека), адрес которой содержится в указателе стека SP, после чего значение SP уменьшается на 1. По команде pop Rd указатель стека возвращается на предыдущий элемент (SP+1), а значение, байта записанное по этому адресу копируется в регистр.
Таким образом реализуется память магазинного типа, где вообще не надо заботиться о задании адресов сохраняемых и восстанавливаемых из в памяти ОЗУ данных. Единственное, про что всегда необходимо помнить, - это порядок доступа к элементам стека Last In First Out (Последний Вошел Первый Вышел). Очередность, в которой регистры восстанавливаются из стека, должна быть обратной по отношению к очередности сохранения регистров:
ldi R16, low(RAMEND) ;установка вершины стека out SPL,R16 ldi R16, high(RAMEND) out SPH,R16 . push R16 ;сохранение регистров в стеке push R17 push R18 . pop R18 ;восстановление регистров из стека pop R17 pop R16
Имеется и другая возможность программно реализовать стек данных. Команды ld Rd,X+, ld Rd,Y+, ld Rd,Z+ по сути являются иной реализацией действия push Rr, а st -X,Rd, st -Y,Rd, st -Z, Rd подобны pop Rd. Разница состоит лишь в том, что в качестве индексного регистра выступает не SP, а один из регистров–указателей (X,Y,Z) и вершина стека перемещается в сторону увеличения адресов ОЗУ:
ldi ZL, low(stack) ;установка вершины стека ldi ZH, high(stack) . ld R16, Z+ ;сохранение регистров в стеке ld R17, Z+ ld R18, Z+ . st -Z, R18 ;восстановление регистров из стека st -Z, R17 st -Z, R16
Учитывая то, что SP расположен в пространстве РВВ, а X,Y,Z в РОН, использование эмуляции стека может быть даже более предпочтительной. Регистры X,Y,Z могут быть быстрей модифицированы и кроме того отсутствует опасность повредить их содержимое при вызове подпрограмм и возникновении прерываний.
Подобно большинству микроконтроллеров, у AVR имеется возможность хранения таблиц констант в памяти программ. Для их чтения разработаны команды lpm (Загрузка памяти программ), lpm Rd,Z (Загрузка памяти программ), lpm Rd,Z+ (Загрузка памяти программ с постинкрементом). Все они переписывают содержимое байта из FLASH памяти программ (адрес байта находится в Z) в один из РОН. С помощью первой инструкции, не имеющей параметров, копирование производится в R0. Вторая и третья модификации команды используют в качестве приёмника любой РОН. Команда lpm Rd,Z+ при этом осуществляет ещё и инкрементирование индексного регистра Z после считывания. Типичный пример копирования строки из памяти программ в ОЗУ может выглядеть следующим образом:
ldi ZL,low(2*string) ;копирование строки "Hello World" ldi ZH,high(2*string);длиной 11 байт из памяти программ ldi YL,low(buffer) ;в ОЗУ микроконтроллера по ldi YH,high(buffer) ;адресу buffer ldi R16,11 cycle: lpm R17,Z+ st Y+,R17 dec R16 brne cycle . .org 0x1000 string: .db "Hello World", 0
Здесь последовательно осуществляется считывание строки "Hello World !" (13 байт в кодировке ASCII) расположенной в памяти программ начиная с адреса 0x1000 (задан директивой .org 0x1000). Для резервирования FLASH памяти используется директива ассемблера .db, после которой непосредственно следуют данные. Строка переписывается в ОЗУ по адресу buffer.
Есть два важных момента при использовании операций такого типа. В приведённом выше фрагменте программы в качестве указателя на строку в индексный регистр Z заносится удвоенный адрес метки 2*string и это не случайность. Дело в том, что метке string соответствует адрес слова программ 0x1000. Но слово программ у AVR имеет блину 2 байта, а в указатель Z необходимо занести именно адрес байта т.е. 2*0x1000 = 0x2000. По той же причине в памяти программ необходимо выделять только чётное (кратное двум) количество байтов и если это не так, то надо добавлять незначащий байт 0 в самом конце, как это и случилось в нашем примере (строка "Hello World !" содержит 13 байт). Попутно заметим, что строки символов ASCII, как правило, и хранят в таком формате (добавляют в конце 0). Это позволяет автоматически распознавать конец строки и считывать, не зная заранее её длины.
Использование 2-байтового регистра Z позволяет адресовать только 64 кб при считывании памяти программ. Этого явно недостаточно для тех моделей AVR, которые имеют 128 и 256 кб FLASH-памяти. Для того чтобы работать во всём диапазоне адресов к указателю Z в этом случае добавляется регистр RAMPZ из пространства РВВ, в котором используются 1 или 2 младших бита. Этот 3-байтовый индексный регистр RAMPZ:ZH:ZL используют инструкции elpm (Расширенная загрузка памяти программ), elpm Rd, Z (Расширенная загрузка памяти программ), elpm Rd,Z+ (Расширенная загрузка памяти программ с постинкрементом).
Последняя инструкция в группы команд пересылки spm (Запись памяти программ). Она реализует возможность самопрограммирования микроконтроллеров AVR. Конкретное действие, которое выполняет эта команда, зависит от установок в управляющем РВВ SPMCSR. Это может быть стирание страницы памяти программ, занесение данных для записи во временный буфер или копирование буфера в память программ, а также чтение ячеек идентификаторов и защиты. В любом случае для задания адреса области используется указатель Z, а данные, если они необходимы, передаются в регистровой паре R1:R0. Так как действие данной инструкции связано с модификацией программного кода, для ее корректного применения предпринят ряд мер предосторожности, о чём подробно будет сказано в разделе “Самопрограммирование микроконтроллеров AVR”.
Перейти к следующей части: Команды передачи управления
Комментарии (0) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация