Выполняется командой PUSH. У этой команды один операнд, который может быть непосредственным значением, 16-битным регистром (в том числе сегментым) или 16-битной переменной в памяти. Команда работает следующим образом:
1. значение в регистре SP уменьшается на 2 (так как ширина стека — 16 бит или 2 байта);
2. операнд помещается в память по адресу в SP.
Выполняется командой POP. У этой команды также один операнд, который может быть 16-битным регистром (в том числе сегментым, но кроме CS) или 16-битной переменной в памяти. Команда работает следующим образом:
1. операнд читается из памяти по адресу в SP;
2. значение в регистре SP увеличивается на 2.
6.Упакованные и неупакованные BSD числа
Суть упакованных чисел состоит в том, что в одном байте можно хранить два десятичных числа, например число 12345678 может хранитьс в 4 байтах (от неупакованных чисел отличаются упакованные тем, что здесь, в одном байте хранится два числа, то есть число 51 в неупакованном формате выглядит как 05h 01h, а у упакованном формате оно выглядит как 51h. Для неупакованного числа на каждую цифру отводится байт, чтобы можно было быстро переводить в формат ANSII, просто заменяя старшие 4 бита в числе на 0011) A dd 12345678h
Упакованный формат чисел имеет следующие преимущества:
• Количество значащих цифр может быть практически любым, это позволяет проводить расчеты с очень высокой точностью (хз что это)
• Конвертировать упакованное десятичное число в формат ANSI достаточно просто Для конвертирования результата сложения и вычитания в формат упакованного числа, для сложения (ADD, ADC) это DAA, для вычитания (SUB,SBB) это DAS
Команды DAA и DAS конвертируют число, находящееся в регистре AL.
7.Сложение двоичных чисел без знака
Процессор выполняет сложение операндов по правилам сложения двоичных чисел. Проблем не возникает до тех пор, пока значение результата не превышает размерности поля операнда т.е. 8 бит.
254 + + 5 = 259 в двоичном виде:
11111110 + 0000101 - 1 00000011.
Так, для фиксации ситуации выхода за разрядную сетку результата, как в данном случае, предназначен флаг переноса CF. Он располагается в бите 0 регистра флагов EFLAGS/FLAGS
8.Сложение двоичных чисел со знаком
Для сложения двух чисел предназначена команда ADD. Она работает как с числами со знаком, так и с числами без знака (это особенность дополнительного кода).
Операнды должны иметь одинаковый размер (нельзя складывать 16- и 8-битное значение). Результат помещается на место первого операнда. В общем, эти правила справедливы для большинства команд.
После выполнения команды изменяются флаги, по которым можно определить характеристики результата:
· Флаг CF устанавливается, если при сложении произошёл перенос из старшего разряда. Для беззнаковых чисел это будет означать, что произошло переполнение и результат получился некорректным.
· Флаг OF обозначает переполнение для чисел со знаком.
· Флаг SF равен знаковому биту результата (естественно, для чисел со знаком, а для беззнаковых он равен старшему биту и особо смысла не имеет).
· Флаг ZF устанавливается, если результат равен 0.
· Флаг PF — признак чётности, равен 1, если результат содержит нечётное число единиц.
9. Вычитание двоичных чисел без знака
после команды вычитания чисел без знака нужно анализировать состояние флага CF. Если он установлен в 1, это говорит о том, что произошел заем из старшего разряда и результат получился в дополнительном коде.
Аналогично командам сложения группа команд вычитания состоит из минимально возможного набора. Эти команды выполняют вычитание по алгоритмам, которые мы сейчас рассматриваем, а учет особых ситуаций должен производиться самим программистом.
«Команда декремента выполняеуменьшения значения операнда на 1: dec операнд
• Команда вычитания (операнд_1 = операнд_1 - операнд_2):
sub операнд_1,операнд_2 8 Команда вычитания с учетом заема, то есть флага CF (операнд_1 = операнд_1 -операнд_2 - значение_СР): Sbb операнд_1.операнд_2 Как видите, среди команд вычитания есть команда SBB, учитывающая флаг переноса CF. Эта команда подобна ADC, но теперь уже флаг CF играет роль индикатора заема 1 из старшего разряда при вычитании чисел.
10.Вычитание двоичных числе со знаком
Вычитание выполняется с помощью команды SUB. Результат также помещается на место первого операнда и опять же выставляются флаги. Единственная разница в том, что происходит вычитание, а не сложение.
На самом деле вычитание в процессоре реализовано с помощью сложения. Процессор меняет знак второго операнда на противоположный, а затем складывает два числа. Если вам необходимо в программе поменять знак числа на противоположный, можно использовать команду NEG. У этой команды всего один операнд.
Примеры:
sub si,dx ;SI = SI - DX neg ax ;AX = -AX |
11. Умножение двоичных чисел без знака
Для умножения чисел без знака предназначена команда MUL. У этой команды только один операнд — второй множитель, который должен находиться в регистре или в памяти. Местоположение первого множителя и результата задаётся неявно и зависит от размера операнда:
Размер операнда | Множитель | Результат |
Байт | AL | AX |
Слово | AX | DX:AX |
Отличие умножения от сложения и вычитания в том, что разрядность результата получается в 2 раза больше, чем разрядность сомножителей. Также и в десятичной системе — например, умножая двухзначное число на двухзначное, мы можем получить в результате максимум четырёхзначное. Запись «DX:AX» означает, что старшее слово результата будет находиться в DX, а младшее — в AX. Примеры:
mul bl ;AX = AL * BL mul ax ;DX:AX = AX * AX |
Если старшая часть результата равна нулю, то флаги CF и ОF будут иметь нулевое значение. В этом случае старшую часть результата можно отбросить. Это свойство можно использовать в программе, если результат должен быть такого же размера, как множители.
12. Деление двоичных чисел без знака
Деление целых двоичных чисел — это всегда деление с остатком! По аналогии с умножением, размер делителя, частного и остатка должен быть в 2 раза меньше размера делимого. Деление чисел без знака осуществляется с помощью команды DIV. У этой команды один операнд — делитель, который должен находиться в регистре или в памяти. Местоположение делимого, частного и остатка задаётся неявно и зависит от размера операнда:
Размер операнда (делителя) | Делимое | Частное | Остаток |
Байт | AX | AL | AH |
Слово | DX:AX | AX | DX |
При выполнении команды DIV может возникнуть прерывание (о прерываниях я подробно расскажу потом, пока старайтесь избегать таких случаев):
· если делитель равен нулю;
· если частное не помещается в отведённую под него разрядную сетку (например, если при делении слова на байт частное больше 255).
Примеры:
div cl ;AL = AX / CL, остаток в AH div di ;AX = DX:AX / DI, остаток в D |
13.Умножение двоичных чисел со знаком
Для умножения чисел со знаком предназначена команда IMUL. Эта команда имеет три формы, различающиеся количеством операндов:
· С одним операндом — форма, аналогичная команде MUL. В качестве операнда указывается множитель. Местоположение другого множителя и результата определяется по таблице.
· С двумя операндами — указываются два множителя. Результат записывается на место первого множителя. Старшая часть результата в этом случае игнорируется. Кстати, эта форма команды не работает с операндами размером 1 байт.
· С тремя операндами — указывается положение результата, первого и второго множителя. Второй множитель должен быть непосредственным значением. Результат имеет такой же размер, как первый множитель, старшая часть результата игнорируется. Это форма тоже не работает с однобайтными множителями.
Примеры:
imul cl ;AX = AL * CL imul si ;DX:AX = AX * SI imul bx,ax ;BX = BX * AX imul cx,-5 ;CX = CX * (-5) imul dx,bx,134h ;DX = BX * 134h |
CF = OF = 0, если произведение помещается в младшей половине результата, иначе CF = OF = 1. Для второй и третьей формы команды CF = OF = 1 означает, что произошло переполнение.
14.Деление двоичных чисел со знаком
Для деления чисел со знаком предназначена команда IDIV. Единственным операндом является делитель. Местоположение делимого и частного определяется также, как для команды DIV. Эта команда тоже генерирует прерывание при делении на ноль или слишком большом частном.
Пример программы
Допустим, в программе требуется вычислять координату какого-то движущегося объекта по формуле:
x = x0 + v0t + at2/2
Все числа в правой части — 8-битные целые без знака, а x — 16-битное целое и тоже без знака. Здесь нужно внимательно следить за размерами операндов.
15.Логические команды
Логические операции с битами - OR, XOR, AND, NOT. Эти команды работают с приемником и источником, исключение команда 'NOT'. Каждый бит в приемнике сравнивается с тем же самым битом в источнике, и в зависимости от команды, 0 или 1 помещается в бит приемника:
AND (логическое И) устанавливает бит результата в 1, если оба бита, бит источника и бит приемника установлены в 1.
OR (логическое ИЛИ) устанавливает бит результата в 1, если один из битов, бит источника или бит приемника установлен в 1.
XOR (НЕ ИЛИ) устанавливает бит результата в 1, если бит источника отличается от бита приемника.
NOT инвертирует бит источника.
Пример:
mov ax, 3406d
mov dx, 13EAh
xor ax, dx
16.Метки
1. Имя метки, после которого ставится двоеточие. Это самый простой способ. Обычно так объявляются метки в коде.
exit_app: mov ax,4C00h int 21h |
17.Безусловные переходы
Безусловные переходы
Безусловный переход — это переход, который выполняется всегда. Безусловный переход осуществляется с помощью команды JMP. У этой команды один операнд, который может быть непосредственным адресом (меткой), регистром или ячейкой памяти, содержащей адрес. Существуют также «дальние» переходы — между сегментами, однако здесь мы их рассматривать не будем. Примеры безусловных переходов:
jmp metka ;Переход на метку jmp bx ;Переход по адресу в BX jmp word[bx] ;Переход по адресу, содержащемуся в памяти по адресу в BX |
18.Процедуры
Процедура представляет собой группу команд для решения конкретной подзадачи и обладает средствами получения управления из точки вызова задачи более высокого приоритета и возврата управления в эту точку. В простейшем случае программа может состоять из одной процедуры. Процедуру можно определить и как правильным образом оформленную совокупность команд, которая, будучи однократно описана, при необходимости может быть вызвана в любом месте программы.
Синтаксис описания процедуры:
ИмяПроцедуры PROC расстояние
; тело процедуры
ИмяПроцедуры ENDP
Атрибут расстояние может принимать значения near или far и характеризует возможность обращения к процедуре из другого сегмента кода.
Процедура может размещаться в любом месте программы, но так, чтобы на нее случайным образом не попало управление. Если процедуру просто вставить в общий поток команд, то микропроцессор будет воспринимать команды процедуры как часть этого потока. Учитывая это обстоятельство, есть следующие варианты размещения процедуры в программе:
· в начале программы (до первой исполняемой команды);
· в конце (после команды, возвращающей управление операционной системе);
19.Команда сравнения, усл переход для ком-ды сравнения.
Команды условного перехода осуществляют переход, который выполняется только в случае истинности некоторого условия. Истинность условия проверяется по значениям флагов. Поэтому обычно непосредственно перед командой условного перехода ставится команда сравнения, которая формирует значения флагов:
CMP <операнд1>, <операнд2>
Команда сравнения эквивалентна команде SUB за исключением того, что вычисленная разность никуда не заносится. Назначение команды CMP – установка и сброс флагов.
Что касается команд условного перехода, то их достаточно много, но все они записываются единообразно:
Jxx <метка>
Все команды условного перехода можно разделить на три группы.
В первую группу входят команды, которые обычно ставятся после команды сравнения. В их мнемокодах указывается тот результат сравнения, при котором надо делать переход.
JE Переход если равно op1 = op2 ZF = 1 Для всех чисел
JNE Переход если не равно op1 ≠ op2 ZF = 0
JL/JNGE Переход если меньше op1 < op2 SF ≠ OF Для чисел со знаком
JLE/JNG Переход если меньше или равно op1 ≤ op2 SF ≠ OF или ZF = 1
JG/JNLE Переход если больше op1 > op2 SF = OF и ZF = 0
JGE/JNL Переход если больше или равно op1 ≥ op2 SF = OF
JB/JNAE Переход если ниже op1 < op2 CF = 1 Для чисел без знака
JBE/JNA Переход если ниже или равно op1 ≤ op2 CF = 1 или ZF = 1
JA/JNBE Переход если выше op1 > op2 CF = 0 и ZF = 0
JAE/JNB Переход если выше или равно op1 ≥ op2 CF = 0
20.Команды условного перехода по состоянию флагов
Команды перехода по состоянию флагов
Команда | Флаг | Команда | Флаг |
jc | cf = 1 | jnc | cf = 0 |
jp | pf = 1 | jnp | pf = 0 |
jz | zf = 1 | jnz | zf = 0 |
js | sf = 1 | jns | sf = 0 |
jo | jo = 1 | jno | jo = 0 |
Команда перехода по состоянию регистра cx:
jcxz <метка>;прейти, если cx = 0
21.Организация циклов
Команда LOOP
Для организации цикла предназначена команда LOOP. У этой команды один операнд — имя метки, на которую осуществляется переход. В качестве счётчика цикла используется регистр CX. Команда LOOP выполняет декремент CX, а затем проверяет его значение. Если содержимое CX не равно нулю, то осуществляется переход на метку, иначе управление переходит к следующей после LOOP команде.
Содержимое CX интерпретируется командой как число без знака. В CX нужно помещать число, равное требуемому количеству повторений цикла. Понятно, что максимально может быть 65535 повторений. Ещё одно ограничение связано с дальность перехода. Метка должна находиться в диапазоне -127…+128 байт от команды LOOP
mov ah,02h ;Для вызова функции DOS 02h - вывод символа
mov dl,'A' ;Первый выводимый символ
mov cx,26 ;Счётчик повторений цикла
metka:
int 21h ;Обращение к функции DOS
inc dl ;Следующий символ
loop metka ;Команда цикла
22.If else
cmp eax, ebx; {сравниваем eax с ebx}
je @IfNot; {если равны, то переходим на иначе} используются команды сравнения
Осуществляется переход по метке
23. Switch
Так же, как и If else
24.Префиксы повторений
рефиксы повторения имеют свои мнемонические обозначения:
rep
repe или repz
repne или repnz
Эти префиксы повторения указываются перед нужной цепочечной командой в поле метки.
Цепочечная команда без префикса выполняется один раз. Размещение префикса перед цепочечной командой заставляет ее выполняться в цикле.
Отличия приведенных префиксов в том, на каком основании принимается решение о циклическом выполнении цепочечной команды: по состоянию регистра ecx/cx или по флагу нуля zf:
· префикс повторения rep (REPeat). Этот префикс используется с командами, реализующими операции-примитивы пересылки и сохранения элементов цепочек — соответственно, movs и stos.
Префикс rep заставляет данные команды выполняться, пока содержимое в ecx/cx не станет равным 0.
При этом цепочечная команда, перед которой стоит префикс, автоматически уменьшает содержимое ecx/cx на единицу. Та же команда, но без префикса, этого не делает;
· префиксы повторения repe или repz (REPeat while Equal or Zero). Эти префиксы являются абсолютными синонимами.
Они заставляют цепочечную команду выполняться до тех пор, пока содержимое ecx/cx не равно нулю или флаг zf равен 1.
Как только одно из этих условий нарушается, управление передается следующей команде программы. Благодаря возможности анализа флага zf, наиболее эффективно эти префиксы можно использовать с командами cmps и scas для поиска отличающихся элементов цепочек.
· префиксы повторения repne или repnz (REPeat while Not Equal or Zero). Эти префиксы также являются абсолютными синонимами. Их действие на цепочечную команду несколько отличается от действий префиксов repe/repz. Префиксы repne/repnz заставляют цепочечную команду циклически выполняться до тех пор, пока содержимое ecx/cx не равно нулю или флаг zf равен нулю.
При невыполнении одного из этих условий работа команды прекращается.
Данные префиксы также можно использовать с командами cmps и scas, но для поиска совпадающих элементов цепочек.
25-26 Цепочки
Епочечные команды
Эти команды также называют командами обработки строк символов. Названия почти синонимичны.
Отличие в том, что под строкой символов здесь понимается последовательность байт, а цепочка — это более общее название для случаев, когда элементы последовательности имеют размер больше байта — слово или двойное слово.
Таким образом, цепочечные команды позволяют проводить действия над блоками памяти, представляющими собой последовательности элементов следующего размера:
· 8 бит — байт;
· 16 бит — слово;
· 32 бита — двойное слово.
Содержимое этих блоков для микропроцессора не имеет никакого значения. Это могут быть символы, числа и все что угодно. Главное, чтобы размерность элементов совпадала с одной из перечисленных и эти элементы находились в соседних ячейках памяти.
Всего в системе команд микропроцессора имеется семь операций-примитивов обработки цепочек.
Каждая из них реализуется в микропроцессоре тремя командами, в свою очередь, каждая из этих команд работает с соответствующим размером элемента — байтом, словом или двойным словом.
Особенность всех цепочечных команд в том, что они, кроме обработки текущего элемента цепочки, осуществляют еще и автоматическое продвижение к следующему элементу данной цепочки.
Перечислим операции-примитивы и команды, с помощью которых они реализуются, а затем подробно их рассмотрим:
· пересылка цепочки:
movs адрес_приемника,адрес_источника
movsb
movsw
movsd
· сравнение цепочек:
cmps адрес_приемника,адрес_источника
cmpsb
cmpsw
cmpsd
· сканирование цепочки:
scas адрес_приемника
scasb
scasw
scasd
· загрузка элемента из цепочки:
lods адрес_источника
lodsb
lodsw
lodsd
· сохранение элемента в цепочке:
stos адрес_приемника
stosb
stosw
stosd
· получение элементов цепочки из порта ввода-вывода:
ins адрес_приемника,номер_порта
insb
insw
insd
· вывод элементов цепочки в порт ввода-вывода:
outs номер_порта,адрес_источника
outsb
outsw
outsd