Для примера создадим функцию, которая будет получать два числа и возвращать их сумму. Определим три переменные в сегменте _DATA: две для получения входных параметров и одну для результата работы функции:
_DATA SEGMENT ExitCode dd 0 dwNum_1 dd 0 dwNub_2 dd 0 dwResult dd 0 _DATA ENDS
Первая переменная ExitCode используется для передачи в функцию выхода из программы ExitProcess, ноль означает корректное закрытые. Переменные dwNum_1 и dwNum_2 — это наши входные параметры, переменная dwResult — для хранения результата работы функции. dd — обозначает тип создаваемых переменных (double word) что соответствует 32 битам. Типы данных в masm32 рассмотрены в статье Двоичные числа в Assembler. Все 4 переменные, созданные в примере выше инициализированы значением 0, если начальное значение переменной не имеет значения, то можно инициализировать переменную значением ?.
Создание тела функции в Assembler masm32
Тело функции должно находиться после инструкции выхода из программы.
АССЕМБЛЕР в 2023? Что такое «Reverse Engineering» и «Cyber Security». Показываю как ломают софт.
Процедуры определяются с помощью директывы proc. Конец тела функции определяются с помощью директывы endp:
AddProc proc AddProc endp
В примере AddProc — это имя процедуры, которую мы создаем.
Передача параметров в функцию через стек
Параметры в функции в Assembler передаются через стек. Параметры помещаются в стек в обратном порядке (от последнего к первому), делается это потому, что получение значений из стека идет по принципу «первый пришел — последний ушел». После каждого помещения параметра в стек значение регистра ESP уменьшается на 4 байта (регистр ESP указывает на вершину стекa):
После каждого добавления параметра в стек происходит сдвиг регистра ESP на 4 байта, т.е. команду PUSH можно представить как совокупность двух команд:
sub ESP, 4 mov [ESP], arg
Первой командой значение регистра ESP уменьшается на 4 байта, а второй командой происходит помещение в стек (квадратные скобки означают помещение значения по указанному в скобках адресу) значения аргумента arg:
Как мы уже узнали, параметры функции помещаются в стек в обратном порядке. После команд push следует команда вызова функции call:
В отладчике этот кусочек кода будет выглядет так:
В первых двух командах push, как видно на скриншоте, отсутствуют имена переменных, зато вместо них есть адрес в памяти, по которому хранится значение этой переменной (DS означает сегмент данных). В отладчике можно наблюдать как меняется значение по указанному адресу.
Перед тем как вызвать процедуру AddProc, выполняется еще одно действие — в стек помещается адрес возврата. Адрес возврата — это адрес инструкции, которая следует сразу за вызовом процедуры call. Делается это для того, чтобы процессор знал, какую инструкцию выполнять после выхода из процедуры:
Пишем тетрис на ассемблере под DOS (x86)
Команду CALL можно представить как совокупность двух команд: сначала в стек помещается адрес возврата командой push, а после этого происходит переход на адрес вызванной процедуры.
Извлечение значений параметров в функции
Так как поверх параметров в стек было добавлено значение адреса возврата, то получить доступ к параметрам при помощи команды pop не получится. Использовать регистр ESP напрямую также не получится, т.к. это приведет к изменению его значения и соответственно к потере данных в стеке. Для этих целей используется регистр EBP. Для начала, чтобы не потерять текущее значение, значение регистра EBP помещается в стек. После чего в регистр EBP помещается значение регистра ESP, т.е. регистр EBP начинает указывать на вершину стека.
push ebp mov ebp, esp
Далее в стек могу помещаться значения локальных переменных для функции (что соответственно приведет к изменению значения регистра ESP), но с помощью значения регистра EBP мы сможем получить доступ как к параметрам функции, так и к значениям локальных переменных. Если к значению регистра EBP прибавить смещение 8, то мы получим указатель на первый параметр функции, если прибавить 12, то получим указатель на второй параметр функции и т.д. Если из значения регистра EBP вычесть 4, то получим указатель на первую локальную переменную функции, если вычесть 8, то получим указатель на вторую локальную переменную функции и т.д.:
Восстановление значений регистров ESP и EBP
После того, как функция завершит свою работу, необходимо восстановить значения регистров ESP и EBP к их значениям, до вызова процедуры, это делается с помощью двух команд:
mov esp, ebp pop ebp
С помощью первой команды восстанавливается значение регистра ESP и он начинает указывать на вершину стека, как на рисунке:
Команда pop ebp вытаскивает из стека значение регистра EBP до вызова процедуры и кладет его в регистр EBP, кроме этого происходит смещение значения регистра ESP на 4 байта и он начинает указывать на адрес возврата из функции:
Возврат из функции
После восстановления значения регистров необходимо осуществить возврат из функции, для этого предназначена команда RET:
Инструкция RET осуществляет переход на адрес возврата из стека и одновременно смещает значение регистра ESP на N*4 байт, где N — это количество параметров, переданных в функцию. После этого регистр ESP начинает вновь указывать на дно стека, как было до вызова функции.
В нашем случае инструкция RET будет выглядеть как ret 8 , т.к. мы передавали два параметра, по 4 байта каждый.
Наполнение тела функции
- Помимо регистров ESP и EBP необходимо следить за сохранностью значений еще трех регистров: EBX, ESI, EDI. Для этой цели значения этих регистров прячутся в стек, подобно регистру EBP и восстанавливаются из стека перед выходом из функции.
- По стандарту для возвращения значения из функции используется регистр EAX (это не является обязательным условием).
AddProc proc push ebp mov ebp, esp push ebx push esi push edi ;————————— mov eax, dword ptr[ebp+8] mov ebx, dword ptr[ebp+0ch] add eax, ebx ;————————— pop edi pop esi pop ebx mov esp, ebp pop ebp ret 8 AddProc endp
В теле функции в регистры EAX и EBX перемещаются значения параметров, полученные из стека с помощью смещений на 8 и 12 байт. После чего результат сложения этих двух значений помещается в регистр EAX. Заготовку тела функции (без сложения чисел) сразу добавляю в свой список сниппетов для файлов расширения .asm редактора vim.
Полный листинг программы
.586P .model flat, stdcall ;————————————- includelib C:masm32libkernel32.lib extern [email protected]:near ;————————————- _DATA SEGMENT ExitCode dd 0 dwNum_1 dd 0 dwNum_2 dd 0 dwResult dd 0 _DATA ENDS _TEXT SEGMENT START: mov dwNum_1, 5 mov dwNum_2, 10 push dwNum_2 push dwNum_1 call AddProc mov dwResult, eax push [ExitCode] call [email protected] ;————————————- AddProc proc push ebp mov ebp, esp push ebx push esi push edi ;—————————— mov eax, dword ptr[ebp+8] mov ebx, dword ptr[ebp+0ch] add eax, ebx ;—————————— pop edi pop esi pop ebx mov esp, ebp pop ebp ret 8 AddProc endp _TEXT ENDS END START
В отладчике программа будет выглядеть вот так:
Способ создания функций с использованием макро-команд рассмотрен в следующем посте.
Способы завуалированного вызова функций, затрудняющие дизассемблирование рассмотрены здесь.
Болтовня ничего не стоит. Покажите мне код.
Источник: rate1.site
19. Простые процедуры в ассемблер
Для работы с процедурами предназначены команды CALL и RET . С помощью команды CALL выполняется вызов процедуры. Эта команда работает почти также, как команда безусловного перехода (JMP), но с одним отличием — одновременно в стек сохраняется текущее значение регистра IP. Это позволяет потом вернуться к тому месту в коде, откуда была вызвана процедура.
В качестве операнда указывается адрес перехода, который может быть непосредственным значением (меткой), 16-разрядным регистром (кроме сегментных) или ячейкой памяти, содержащей адрес. Возврат из процедуры выполняется командой RET . Эта команда восстанавливает значение из вершины стека в регистр IP. Таким образом, выполнение программы продолжается с команды, следующей сразу после команды CALL. Обычно код процедуры заканчивается этой командой. Команды CALL и RET не изменяют значения флагов (кроме некоторых особых случаев в защищенном режиме). Небольшой пример разных способов вызова процедуры:
use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h mov ax,myproc mov bx,myproc_addr xor si,si call myproc ;Вызов процедуры (адрес перехода — myproc) call ax ;Вызов процедуры по адресу в AX call [myproc_addr] ;Вызов процедуры по адресу в переменной call word [bx+si] ;Более сложный способ задания адреса 😉 mov ax,4C00h ; int 21h ;/ Завершение программы ;———————————————————————- ;Процедура, которая ничего не делает myproc: nop ;Код процедуры ret ;Возврат из процедуры ;———————————————————————- myproc_addr dw myproc ;Переменная с адресом процедуры
Ближние и дальние вызовы процедур
Существует 2 типа вызовов процедур. Ближним называется вызов процедуры, которая находится в текущем сегменте кода. Дальний вызов — это вызов процедуры в другом сегменте. Соответственно существуют 2 вида команды RET — для ближнего и дальнего возврата. Компилятор FASM автоматически определяет нужный тип машинной команды, поэтому в большинстве случаев не нужно об этом беспокоиться.
В учебном курсе мы будем использовать только ближние вызовы процедур.
Передача параметров
Очень часто возникает необходимость передать процедуре какие-либо параметры. Например, если вы пишете процедуру для вычисления суммы элементов массива, удобно в качестве параметров передавать ей адрес массива и его размер. В таком случае одну и ту же процедуру можно будет использовать для разных массивов в вашей программе. Самый простой способ передать параметры — это поместить их в регистры перед вызовом процедуры.
Возвращаемое значение
Кроме передачи параметров часто нужно получить какое-то значение из процедуры. Например, если процедура что-то вычисляет, хотелось бы получить результат вычисления. А если процедура что-то делает, то полезно узнать, завершилось действие успешно или возникла ошибка.
Существуют разные способы возврата значения из процедуры, но самый часто используемый — это поместить значение в один из регистров. Обычно для этой цели используют регистры AL и AX. Хотя вы можете делать так, как вам больше нравится.
Сохранение регистров
Хорошим приёмом является сохранение регистров, которые процедура изменяет в ходе своего выполнения. Это позволяет вызывать процедуру из любой части кода и не беспокоиться, что значения в регистрах будут испорчены. Обычно регистры сохраняются в стеке с помощью команды PUSH, а перед возвратом из процедуры восстанавливаются командой POP. Естественно, восстанавливать их надо в обратном порядке. Примерно вот так:
myproc: push bx ;Сохранение регистров push cx push si . ;Код процедуры pop si ;Восстановление регистров pop cx pop bx ret ;Возврат из процедуры
Пример
Для примера напишем процедуру для вывода собщения в рамке и протестируем её работу, выведя несколько сообщений. В качестве параметра ей будет передаватся адрес строки в регистре BX.
Строка должна заканчиваться символом ‘$’ . Для упрощения процедуры можно разбить задачу на подзадачи и написать соответствующие процедуры. Прежде всего нужно вычислить длину строки, чтобы знать ширину рамки. Процедура get_length вычисляет длину строки (адрес передаётся также в BX) и возвращает её в регистре AX.
Для рисования горизонтальной линии из символов предназначена процедура draw_line. В DL передаётся код символа, а в CX — количество символов, которое необходимо вывести на экран. Эта процедура не возвращает никакого значения. Для вывода 2-х символов конца строки написана процедура print_endline. Она вызывается без параметров и тоже не возвращает никакого значения.
Коды символов для рисования рамок можно узнать с помощью таблицы символов кодировки 866 или можно воспользоваться стандартной программой Windows «Таблица символов», выбрав шрифт Terminal.
use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h jmp start ;Переход на метку start ;———————————————————————- msg1 db ‘Hello!$’ msg2 db ‘asmworld.ru$’ msg3 db ‘Press any key. $’ ;———————————————————————- start: mov bx,msg1 call print_message ;Вывод первого сообщения mov bx,msg2 call print_message ;Вывод второго сообщения mov bx,msg3 call print_message ;Вывод третьего сообщения mov ah,8 ;Ввод символа без эха int 21h mov ax,4C00h ; int 21h ;/ Завершение программы ;———————————————————————- ;Процедура вывода сообщения в рамке ;В BX передаётся адрес строки print_message: push ax ;Сохранение регистров push cx push dx call get_length ;Вызов процедуры вычисления длины строки mov cx,ax ;Копируем длину строки в CX mov ah,2 ;Функция DOS 02h — вывод символа mov dl,0xDA ;Левый верхний угол int 21h mov dl,0xC4 ;Горизонтальная линия call draw_line ;Вызов процедуры рисования линии mov dl,0xBF ;Правый верхний угол int 21h call print_endline ;Вызов процедуры вывода конца строки mov dl,0xB3 ;Вертикальная линия int 21h mov ah,9 ;Функция DOS 09h — вывод строки mov dx,bx ;Адрес строки в DX int 21h mov ah,2 ;Функция DOS 02h — вывод символа mov dl,0xB3 ;Вертикальная линия int 21h call print_endline ;Вызов процедуры вывода конца строки mov dl,0xC0 ;Левый нижний угол int 21h mov dl,0xC4 ;Горизонтальная линия call draw_line mov dl,0xD9 ;Правый нижний угол int 21h call print_endline ;Вызов процедуры вывода конца строки pop dx ;Восстановление регистров pop cx pop ax ret ;Возврат из процедуры ;———————————————————————- ;Процедура вычисления длины строки (конец строки — символ ‘$’). ;В BX передаётся адрес строки. ;Возвращает длину строки в регистре AX. get_length: push bx ;Сохранение регистра BX xor ax,ax ;Обнуление AX str_loop: cmp byte[bx],’$’ ;Проверка конца строки je str_end ;Если конец строки, то выход из процедуры inc ax ;Инкремент длины строки inc bx ;Инкремент адреса jmp str_loop ;Переход к началу цикла str_end: pop bx ;Восстановление регистра BX ret ;Возврат из процедуры ;———————————————————————- ;Процедура рисования линии из символов. ;В DL — символ, в CX — длина линии (кол-во символов) draw_line: push ax ;Сохранение регистров push cx mov ah,2 ;Функция DOS 02h — вывод символа drl_loop: int 21h ;Обращение к функции DOS loop drl_loop ;Команда цикла pop cx ;Восстановление регистров pop ax ret ;Возврат из процедуры ;———————————————————————- ;Процедура вывода конца строки (CR+LF) print_endline: push ax ;Сохранение регистров push dx mov ah,2 ;Функция DOS 02h — вывод символа mov dl,13 ;Символ CR int 21h mov dl,10 ;Символ LF int 21h pop dx ;Восстановление регистров pop ax ret ;Возврат из процедуры
Результат работы программы выглядит вот так:
Отладчик Turbo Debugger
Небольшое замечание по поводу использования отладчика. В Turbo Debugger нажимайте F7 («Trace into»), чтобы перейти к коду вызываемой процедуры. При нажатии F8(«Step over») процедура будет выполнена сразу целиком.
Упражнение
Объявите в программе 2-3 массива слов без знака. Количество элементов каждого массива должно быть разным и храниться в отдельной 16-битной переменной без знака. Напишите процедуру для вычисления среднего арифметического массива чисел. В качестве параметров ей будет передаваться адрес массива и количество элементов, а возвращать она будет вычисленное значение.
С помощью процедуры вычислите среднее арифметическое каждого массива и сохраните где-нибудь в памяти. Выводить числа на экран не нужно, этим мы займемся в следующей части.
Предыдущий урок | Список уроков | Следующий урок |
Источник: pro-prof.com
Справочник по командам ассемблера AVR
Справочник по системе команд микроконтроллеров AVR основан на переводе документации от Atmel. Помимо этого сюда добавлено больше примеров из практики, в частности, примеры для ассемблера AVR GCC.
Чтобы быстро перейти к нужной команде достаточно ввести её имя. Также можно выбрать команду из списка внизу.
Справочник будет дополняться по мере появления вопросов.
Введите имя команды в поле выше
Логические операции
AND Rd, Rr | Логическое «И» двух регистров | Rd ← Rd and Rr | Z, N, V |
ANDI Rd, K | Логическое «И регистра и константы | Rd ← Rd and K | Z, N, V |
EOR Rd, Rr | Исключающее «ИЛИ» двух регистров | Rd ← Rd xor Rr | Z, N, V |
OR Rd, Rr | Логическое «ИЛИ» двух регистров | Rd ← Rd or Rr | Z, N, V |
ORI Rd, K | Логическое «ИЛИ» регистра и константы | Rd ← Rd or K | Z, N, V |
COM Rd | Перевод в обратный код | Rd ← 0xFF — Rd | Z, C, N, V |
NEG Rd | Перевод в дополнительный код | Rd ← 0 — Rd | Z, C, N, V, H |
CLR Rd | Очистка регистра | Rd ← Rd xor Rd | Z, N, V |
SER Rd | Установка всех разрядов регистра | Rd ← 0xFF | — |
TST Rd | Проверка регистра на отрицательное (нулевое) значение | Rd ← Rd and Rd | Z, N, V |
Арифметические операции
ADD Rd, Rr | Сложение двух регистров | Rd ← Rd + Rr | Z, C, N, V, H |
ADC Rd, Rr | Сложение двух регистров с переносом | Rd ← Rd + Rr + С | Z, C, N, V, H |
SUB Rd, Rr | Вычитание двух регистров | Rd ← Rd — Rr | Z, C, N, V, H |
SBC Rd, Rr | Вычитание двух регистров с заёмом | Rd ← Rd — Rr — С | Z, C, N, V, H |
ADIW Rd, K | Сложение регистровой пары с константой | R(d+1):Rd ← R(d+1):Rd + K | Z, C, N, V, S |
SBIW Rd, K | Вычитание константы из регистровой пары | R(d+1):Rdl ← R(d+1):Rd — K | Z, C, N, V, S |
SUBI Rd, K | Вычитание константы из регистра | Rd ← Rd — K | Z, C, N, V, H |
SBCI Rd, K | Вычитание константы из регистра с заёмом | Rd ← Rd — K — С | Z, C, N, V, H |
INC Rd | Инкремент регистра | Rd ← Rd + 1 | Z, N, V |
DEC Rd | Декремент регистра | Rd ← Rd – 1 | Z, N, V |
MUL Rd, Rr | Умножение чисел без знака | R1:R0 ← Rd * Rr | Z, C |
MULS Rd, Rr | Умножение чисел со знаком | R1:R0 ← Rd * Rr | Z, C |
MULSU Rd, Rr | Умножение числа со знаком с числом без знака | R1:R0 ← Rd * Rr | Z, C |
FMUL Rd, Rr | Умножение дробных чисел без знака | R1:R0 ← (Rd * Rr) | Z, C |
FMULS Rd, Rr | Умножение дробных чисел со знаком | R1:R0 ← (Rd * Rr) | Z, C |
FMULSU Rd, Rr | Умножение дробного числа со знаком с числом без знака | R1:R0 ← (Rd * Rr) | Z, C |
Битовые операции
CBR Rd, K | Очистка разрядов регистра | Rd ← Rd and (0FFH – K) | Z, N, V |
SBR Rd, K | Установка разрядов регистра | Rd ← Rd or K | Z, N, V |
CBI P, b | Сброс разряда I/O-регистра | P.b ← 0 | — |
SBI P, b | Установка разряда I/O-регистра | P.b ← 1 | — |
BCLR s | Сброс флага SREG | SREG.s ← 0 | SREG.s |
BSET s | Установка флага SREG | SREG.s ← 1 | SREG.s |
BLD Rd, b | Загрузка разряда регистра из флага T | Rd.b ← T | — |
BST Rr, b | Запись разряда регистра во флаг T | T ← Rd.b | T |
CLC | Сброс флага переноса | C ← 0 | C |
SEC | Установка флага переноса | C ← 1 | C |
CLN | Сброс флага отрицательного числа | N ← 0 | N |
SEN | Установка флага отрицательного числа | N ← 1 | N |
CLZ | Сброс флага нуля | Z ← 0 | Z |
SEZ | Установка флага нуля | Z ← 1 | Z |
CLI | Общий запрет прерываний | I ← 0 | I |
SEI | Общее разрешение прерываний | I ← 1 | I |
CLS | Сброс флага знака | S ← 0 | S |
SES | Установка флага знака | S ← 1 | S |
CLV | Сброс флага переполнения дополнительного кода | V ← 0 | V |
SEV | Установка флага переполнения дополнительного кода | V ← 1 | V |
CLT | Сброс пользовательского флага T | T ← 0 | T |
SET | Установка пользовательского флага T | T ← 1 | T |
CLH | Сброс флага половинного переноса | H ← 0 | H |
SEH | Установка флага половинного переноса | H ← 1 | H |
Операции сравнения
CP Rd, Rr | Сравнение двух регистров | Если (Rd – Rr) | Z, N, V, C, H |
CPC Rd, Rr | Сравнение регистров с учётом переноса | Если (Rd – Rr — C) | Z, N, V, C, H |
CPI Rd, K | Сравнение регистра с константой | Если (Rd – K) | Z, N, V, C, H |
CPSE Rd, Rr | Сравнение регистров и пропуск следующей команды если они равны | Если (Rd = Rr) PC ← PC + 2 (или 3) | — |
Операции сдвига
ASR Rd | Арифметический сдвиг вправо | Rd(i) ← Rd(i+1) (n=0..6), C ← Rd(0) | Z, C, N, V |
LSL Rd | Логический сдвиг влево | Rd(i+1) ← Rd(i), Rd(0) ← 0, C ← Rd(7) | Z, C, N, V |
LSR Rd | Логический сдвиг вправо | Rd(i) ← Rd(i+1), Rd(7) ← 0, C ← Rd(0) | Z, C, N, V |
ROL Rd | Сдвиг влево через перенос | Rd(i+1) ← Rd(i), Rd(0) ← C, C ← Rd(7) | Z, C, N, V |
ROR Rd | Сдвиг вправо через перенос | Rd(i) ← Rd(i+1), Rd(7) ← C, C ← Rd(0) | Z, C, N, V |
SWAP Rd | Обмен местами тетрад | Rd(3..0) ↔ Rd(7..4) | — |
Операции пересылки данных
MOV Rd, Rr | Пересылка между регистрами | Rd ← Rr | — |
MOVW Rd, Rr | Пересылка между парами регистров | R(d +1):Rd ← R(r+1):Rr | — |
LDI Rd, K | Загрузка константы в регистр | Rd ← K | — |
LD Rd, X | Косвенное чтение | Rd ← [X] | — |
LD Rd, X+ | Косвенное чтение с пост-инкрементом | Rd ← [X], X ← X + 1 | — |
LD Rd, -X | Косвенное чтение с пред-декрементом | X ← X — 1, Rd ← [X] | — |
LD Rd, Y | Косвенное чтение | Rd ← [Y] | — |
LD Rd, Y+ | Косвенное чтение с пост-инкрементом | Rd ← [Y], Y ← Y + 1 | — |
LD Rd, -Y | Косвенное чтение с пред-декрементом | Y ← Y — 1, Rd ← [Y] | — |
LDD Rd, Y+q | Косвенное чтение со смещением | Rd ← [Y+q] | — |
LD Rd, Z | Косвенное чтение | Rd ← [Z] | — |
LD Rd, Z+ | Косвенное чтение с пост-инкрементом | Rd ← [Z], Z ← Z + 1 | — |
LD Rd, -Z | Косвенное чтение с пред-декрементом | Z ← Z — 1, Rd ← [Z] | — |
LDD Rd, Z+q | Косвенное чтение со смещением | Rd ← [Z+q] | — |
LDS Rd, A | Непосредственное чтение из ОЗУ | Rd ← [A] | — |
ST X, Rr | Косвенная запись | [X] ← Rr | — |
ST X+, Rr | Косвенная запись с пост-инкрементом | [X] ← Rr, X ← X + 1 | — |
ST -X, Rr | Косвенная запись с пред-декрементом | X ← X — 1, [X] ← Rr | — |
ST Y, Rr | Косвенная запись | [Y] ← Rr | — |
ST Y+, Rr | Косвенная запись с пост-инкрементом | [Y] ← Rr, Y ← Y + 1 | — |
ST -Y, Rr | Косвенная запись с пред-декрементом | Y ← Y — 1, [Y] ← Rr | — |
STD Y+q, Rr | Косвенная запись со смещением | [Y+q] ← Rr | — |
ST Z, Rr | Косвенная запись | [Z] ← Rr | — |
ST Z+, Rr | Косвенная запись с пост-инкрементом | [Z] ← Rr, Z ← Z + 1 | — |
ST -Z, Rr | Косвенная запись с пред-декрементом | Z ← Z — 1, [Z] ← Rr | — |
STD Z+q, Rr | Косвенная запись со смещением | [Z+q] ← Rr | — |
STS A, Rr | Непосредственная запись в ОЗУ | [A] ← Rr | — |
LPM | Загрузка данных из памяти программы | R0 ← | — |
LPM Rd, Z | Загрузка данных из памяти программы в регистр | Rd ← | — |
LPM Rd, Z+ | Загрузка данных из памяти программы с пост-инкрементом Z | Rd ← , Z ← Z + 1 | — |
ELPM | Расширенная загрузка данных из памяти программы | R0 ← | — |
ELPM Rd, Z | Расширенная загрузка данных из памяти программы в регистр | Rd ← | — |
ELPM Rd, Z+ | Расширенная загрузка данных из памяти программы с пост-инкрементом Z | Rd ← , Z ← Z + 1 | — |
SPM | Запись в программную память | ← R1:R0 | — |
IN Rd, P | Пересылка из I/O-регистра в регистр | Rd ← P | — |
OUT P, Rr | Пересылка из регистра в I/O-регистр | P ← Rr | — |
PUSH Rr | Сохранение регистра в стеке | STACK ← Rr | — |
POP Rd | Извлечение регистра из стека | Rd ← STACK | — |
Безусловные переходы
RJMP A | Относительный безусловный переход | PC ← PC + A + 1 | — |
JMP A | Длинный безусловный переход | PC ← A | — |
IJMP | Непрямой безусловный переход | PC ← Z | — |
EIJMP | Расширенный непрямой безусловный переход | PC ← Z:EIND | — |
RCALL A | Относительный вызов подпрограммы | PC ← PC + A + 1 | — |
CALL A | Длинный вызов подпрограммы | PC ← A | — |
ICALL | Непрямой вызов подпрограммы | PC ← Z | — |
EICALL | Расширенный непрямой вызов подпрограммы | PC ← Z:EIND | — |
RET | Возврат из подпрограммы | PC ← STACK | — |
RETI | Возврат из подпрограммы обработки прерываний | PC ← STACK | I |
Условные переходы
Все команды этой группы выполняют переход (PC ← PC + A + 1) при разных условиях.
BRBC s, A | Переход если флаг S сброшен | Если SREG(S) = 0 | — |
BRBS s, A | Переход если флаг S установлен | Если SREG(S) = 1 | — |
BRCS A | Переход по переносу | Если C = 1 | — |
BRCC A | Переход если нет переноса | Если C = 0 | — |
BREQ A | Переход если равно | Если Z = 1 | — |
BRNE A | Переход если не равно | Если Z = 0 | — |
BRSH A | Переход если больше или равно | Если C = 0 | — |
BRLO A | Переход если меньше | Если C = 1 | — |
BRMI A | Переход если отрицательное значение | Если N = 1 | — |
BRPL A | Переход если положительное значение | Если N = 0 | — |
BRGE A | Переход если больше или равно (со знаком) | Если (N и V) = 0 | — |
BRLT A | Переход если меньше (со знаком) | Если (N или V) = 1 | — |
BRHS A | Переход по половинному переносу | Если H = 1 | — |
BRHC A | Переход если нет половинного переноса | Если H = 0 | — |
BRTS A | Переход если флаг T установлен | Если T = 1 | — |
BRTC A | Переход если флаг T сброшен | Если T = 0 | — |
BRVS A | Переход по переполнению дополнительного кода | Если V = 1 | — |
BRVC A | Переход если нет переполнения дополнительного кода | Если V = 0 | — |
BRID A | Переход если прерывания запрещены | Если I = 0 | — |
BRIE A | Переход если прерывания разрешены | Если I = 1 | — |
SBRC Rd, K | Пропустить следующую команду если бит в регистре очищен | Если Rd[K] = 0 | — |
SBRS Rd, K | Пропустить следующую команду если бит в регистре установлен | Если Rd[K] = 1 | — |
SBIC A, b | Пропустить следующую команду если бит в регистре ввода/вывода очищен | Если I/O(A, b) = 0 | — |
SBIS A, b | Пропустить следующую команду если бит в регистре ввода/вывода установлен | Если I/O(A, b) = 1 | — |
Управление устройством
NOP | Нет операции | — | — |
SLEEP | Переход в «спящий» режим | — | — |
WDR | Сброс сторожевого таймера | — | — |
BREAK | Приостановка программы (используется отладчиком) | — | — |
Источник: trolsoft.ru