встречающиеся в программах, но Вы обнаружите, что около 95 %
инструкций, встреченных Вами в программах, описаны здесь, а зна-
чение остальных может быть понято благодаря комментариям к прог-
раммам.
Микропроцессор 8088 имеет 13 16-разрядных регистров, каждый из
которых имеет свои функции. В то время как в языках высокого
уровня Вы можете поместить два числа в переменные, а затем сло-
жить эти переменные, то в языке ассемблера эти числа помещаются в
регистры микропроцессора, а затем складываются значения, содержа-
щиеся в регистрах. Все операции в языке ассемблера состоят в
обмене данных с регистрами, а затем выполнении операций на ре-
гистрах, таких как изменение отдельных битов, выполнение арифме-
тических операций и т.д. Одной из причин высокой эффективности
языка ассемблера является хранение данных в регистрах микропро-
цессора; компиляторы имеют тенденцию возвращать все значения в
память после выполнения операции, а доступ к памяти требует боль-
шого времени. На рис. В-1 показаны 13 регистров микропроцессоров
8088 и 80286 (последний имеет дополнительные средства для много-
задачной работы, которые мы не будем рассматривать здесь).
Регистры AX, BX, CX и DX являются регистрами общего назначе-
ния. Их особенность состоит в том, что операции могут произво-
диться не только над содержимым всего регистра, но также и над
половиной. Каждый из четырех регистров делится на старшую и млад-
шую части, например, AH обозначает старшую половину регистра AX,
а AL - младшую. Точно так же ассемблерная программа может иметь
доступ к BH, BL, CH, CL, DH и DL. Это свойство очень полезно,
поскольку часто программе приходится работать с байтными величи-
нами. Регистры BP, SI и DI также достаточно удобны, хотя они
могут принимать только 16-битные значения. Каждый бит регистра
флагов сообщает о соответствующем статусе процессора, например, о
том, что при выполнении арифметической операции был перенос за
разрядную сетку.
В общем случае значения помещаются в регистры с помощью инст-
рукции MOV. MOV AX,BX пересылает содержимое регистра BX в AX,
затирая ранее содержащееся в AX значение. MOV AH,BL приводит к
пересылке байта из регистра в регистр, но MOV AX,BL - недопусти-
мая инструкция, так как значения должны иметь одинаковый размер.
Инструкция MOV можеть также передавать значения из памяти, напри-
мер, MOV AX,ACCT_NUMBER. Здесь ACCT_NUMBER - имя переменной,
которую создал программист, совсем как в языке высокого уровня.
Переменная создается оператором вида ACCT_NUMBER DW 0. Этот опе-
ратор оставляет место для слова (двух байтов), присваивая им
значение 0. Другие допустимые символы в этом операторе это DD -
для двойного слова и DB - для байта или строк. Ассемблер следит


за адресами переменных, поэтому при ассемблировании оператора MOV
AX,ACCT_NUMBER имя переменной заменяется на ее адрес.
Работа с именами переменных - самый простой способ идентифика-
ции данных в программах на языке ассемблера. Но имеются различные
способы хитрой адресации, которые позволяют программе хранить
массивы или использовать указатели. Например, MOV AX,[BX][SI]
посылает в AX значение, которое содержится по смещению, равному
сумме значений регистров BX и SI. Но от чего отсчитывать смеще-
ние? Ответ заключается в том, что все данные собраны в одну часть
программы, а весь исполняемый код - в другую. Часть, отведенная
под данные, называется сегментом данных, а под программу - кодо-
вым сегментом. Все переменные, отведенные для хранения данных,
адресуются через смещение относительно начала сегмента данных.
Позиция в памяти, с которой начинается сегмент данных, хранит-
ся в регистре DS, одном из четырех сегментных регистров. Как и
все остальные регистры микропроцессора он 16-разрядный, поэтому
он не может содержать числа, большие чем 65535. Каким же образом
сегмент даных может указывать на ячейки памяти, расположенные в
верхней части мегабайтного адресного пространства? Ответ состоит
в том, что сегментные регистры автоматически умножаются на 16, а
результат указывает на место в памяти, с которого начинается
сегмент. Таким образом, сегменты всегда выравнены на 16-байтную
границу. После того как сегмент установлен, все остальные регист-
ры могут содержать смещения, указывающие на любой из следующих
65535 байтов. Регистр дополнительного сегмента (ES) также исполь-
зуется для указания на данные, хранящиеся в памяти.
Среди ассемблерных инструкций, которые Вы часто будете встре-
чать в этой книге, есть инструкции загрузки сегментных и относи-
тельных адресов переменных. MOV AX,SEG ACCT_NUMBER помещает зна-
чение сегментного регистра, в котором расположен ACCT_NUMBER в
AX, а впоследствии это значение будет переслано в DS. MOV BX,OFF-
SET ACCT_NUMBER помещает в BX смещение переменной ACCT_NUMBER в
сегменте данных. После выполнения этих операций DS:BX будут ука-
зывать на ACCT_NUMBER. Если ACCT_NUMBER является одномерным мас-
сивом, то для указания на определенный элемент массива может
использоваться добавочное смещение. Вы часто будете встречать
также инструкцию LEA, предоставляющую другой способ загрузки
смещения.
Кодовый сегмент содержит последовательность машинных инструк-
ций, составляющих программу. Например, инструкция MOV существует
в виде нескольких байтов машинного кода, значение байтов которого
определяет в какой регистр идет пересылка и откуда. Регистр IP
(счетчик команд) содержит величину смещения, которая указывает на
ту инструкцию в кодовом сегменте, которая сейчас должна выпол-
няться. После выполнения инструкции IP увеличивается таким обра-
зом, чтобы он указывал на следующую инструкцию. В простейшей
программе счетчик команд будет передвигаться от первого байта
кодового сегмента к последнему, где программа и завершится. Но,
как и другие программы, программа на языке ассемблера может быть
разбита на процедуры (подпрограммы), поэтому счетчик команд может
прыгать из одного места кодового сегмента в другое.
Когда счетчик команд прыгает в другое место кодового сегмента,
то его старое значение должно быть запомнено, с тем чтобы можно
было вернуться в нужное место, так как это делает оператор RETURN


в Бейсике, возвращая управление в то место, откуда была вызвана
процедура. В языке ассемблера процедуре присваивается имя, напр-
имер, COMBINE_DATA, и оператор CALL COMBINE_DATA передает управ-
ление в процедуру. Процедура завершается инструкцией RET (возв-
рат). При вызове процедуры процессор запоминает текущее значение
счетчика команд, заталкивая его на стек.
Стек это область, используемая для временного хранения данных.
После завершения процедуры старое значение счетчика команд берет-
ся из стека и выполнение программы продолжается. Стек также со-
держится в отдельном сегменте, который, совершенно естественно,
называется сегментом стека. Ему соответствует сегментный регистр
SS. В регистре SP хранится указатель стека, который всегда указы-
вает на вершину стека и изменяется при засылке на стек и выборке
из стека.
На первый взгляд стек кажется достаточно неуклюжим способом
хранения информации, но у него есть два преимущества. Во-первых,
доступ к его содержимому намного быстрее, чем к переменным, хра-
нящимся в памяти, а, во-вторых, стек может использоваться для
многих целей. Он может хранить адреса возврата из процедуры,
вложенной в другую процедуру. Впоследствии, то же самое прост-
ранство может использоваться программистом для хранения данных,
которые должны сейчас обрабатываться, но для которых не хватает
места в регистрах микропроцессора. Программа выталкивает содержи-
мое регистра на стек командой PUSH, а позднее забирает его оттуда
командой POP. В ассемблерных программах, приведенных в этой кни-
ге, Вы не раз встретитесь с инструкциями типа PUSH BX и POP DX.
Неправильный порядок обмена данными со стеком - лучший способ
привести ассемблерную программу к краху.
После того как программист на ассемблере установил три сег-
ментных регистра (CS, DS и SS) и загрузил данные в регистры мик-
ропроцессора он имеет широкий набор встроенных средств, которыми
процессор может помочь программисту на ассемблере. Вот наиболее
распространенные из них:

ADD AX,BX Прибавляет BX к AX. Существует также инструкция вычи-
тания (SUB), а также варианты обеих этих инструкций.

MUL BL Умножает BL на AX. Имеется также инструкция деления
(DIV), а также варианты обеих этих инструкций.

INC BL Увеличивает BL на 1. Имеется также инструкция умень-
шения (DEC).

LOOP XXX Возвращает программу назад к строке помеченной XXX,
повторяя процесс столько раз, какое число содержится
в CX (аналогично инструкции FOR .. TO .. NEXT в Бей-
сике).

OR AL,BL Выполняет операцию логического ИЛИ над содержимым
регистров AL и BL, причем результат помещается в AL.
Имеются также инструкции AND, XOR и NOT.


SHL AX,1 Сдвигает все биты, содержащиеся в AX, на одну позицию
влево. Это эквивалентно умножению содержимого AX на
2. Другие инструкции сдвигают биты вправо или осу-
ществляют циклический сдвиг. Все эти инструкции очень
полезны для битовых операций, таких как установка
точек экрана.
IN AL,DX Помещает в AX байт, обнаруженный в порте, адрес кото-
рого указан в DX. Имеется также инструкция OUT.

JMP Передает управление в другое место программы, как
инструкция GOTO в Бейсике. JMP YYY передает управле-
ние на строку программы, имеющую метку YYY.

CMP AL,BL Сравнивает содержимое AL и BL. За инструкцией CMP
обычно следует инструкция условного перехода. Напри-
мер, если за инструкцией CMP следует инструкция JGE,
то переход произойдет только если BL больше или равно
AL. Инструкция CMP достигает того же результата, что
и инструкция IF .. THEN в Бейсике (на самом деле
инструкция IF .. THEN переводится интерпретатором
Бейсика в инструкцию CMP).

TEST AL,BL Проверяет есть ли среди битов, установленных в BL,
такие, которые установлены также и в AL. За этой
инструкцией обычно следует команда условного перехо-
да, так же как за CMP. TEST очень полезен при провер-
ке статусных битов (битовые операции очень просто
реализуются в языке ассемблера).

MOVS Пересылает строку, длина которой содержится в CX, с
места, на которое указывает SI, на место, на которое
указывает DI. Имеется еще несколько других инструк-
ций, связанных с пересылкой и поиском строк.

Язык ассемблера обеспечивает несколько вариантов этих инструкций,
а также ряд других специальных инструкций. Имеется также целый
класс инструкций, называемых псевдооператорами, которые помещают-
ся в текст программы с целью указания ассемблеру как обрабатывать
данную программу. Например, один из типов псевдооператоров авто-
матически вставляет часто используемый кусок кода по всей прог-
рамме. Такая порция кода называется макросом и именно это свойст-
во ассемблера дало ему название "макроассемблер".
И, наконец, ассемблер имеет возможность, которой завидуют
(или, по крайней мере, должны завидовать) все кто программирует
только на языках высокого уровня. Имеется ввиду возможность опти-
мальным образом использовать прерывания операционной системы.
Ведь это ничто иное, как готовые процедуры. Однако вместо того,
чтобы вызывать их по CALL, они вызываются инструкцией INT. INT21H
вызывает прерывание с шестнадцатиричным номером 21. Имеется ряд
таких прерываний, как в базовой системе ввода/вывода ПЗУ, так и в
операционной системе, причем некоторые из этих процедур необычай-
но мощны. На самом деле некоторые из них настолько тесно связаны
с системой, что Вы практически не можете сами написать эквива-
лентную процедуру. Языки высокого уровня позволяют использовать


многие из этих прерываний. Они используют их для вывода на экран,
приема ввода с клавиатуры и доступа к дискам. Но многие действи-
тельно полезные прерывания игнорируются языками высокого уровня,
например такие, которые позволяют запустить из одной программы
другую. Некоторые трансляторы (такие как Lattice C или Turbo
Pascal) позволяют доступ к этим прерываниям, если Вы знаете как
их готовить и Вы можете использовать разделы среднего уровня этой
книги для этой цели.
Перед вызовом прерывания некоторая информация должна быть
помещена в регистры процессора. Например, прерывание, верикально
сдвигающее экран, должно знать размеры сдвигаемого окна, число
строк на которое его надо сдвинуть и т.д. Эти значения часто
называют входными регистрами. Снова и снова Вы будете встречать
слова "при входе BX должен содержать ...", описывающие специфика-
цию входных регистров. Аналогично, при возврате из прерывания
некоторые регистры возвращают значения или статусную информацию.
Они называются выходными регистрами и мы описываем их словами
"при выходе AX содержит ...". Зачастую одно прерывание содержит
много функций. В частности, операционная система впихнула практи-
чески все свои возможности в прерывание 21H. Поэтому при вызове
прерывания необходимо указывать номер функции. Все прерывания
(как BIOS так и DOS) передают номер функции в AH (иногда в AL
содержится номер подфункции).
Все сказанное в основном служит только чтобы дать первое
представление о предмете. Но если Вы будете внимательно просмат-
ривать простейшие примеры, содержащиеся в этой книге, то Вы пой-
мете стоящую за ними логику. Язык ассемблера имеет репутацию
трудного языка. Но то, что Вы только что прочитали - настоящая
чепуха. Имеется достаточно сложностей и в языках высокого уровня.
И если ошибки в ассемблерной программе бывает очень сложно обна-
ружить, то в основном это связано с тем, что сам текст программы
намного длиннее, чем эквивалентный текст на языке высокого уров-
ня (однако ассемблерный код намного плотнее). В настоящее время
многие профессионалы пишут программы на языке C, затем анализи-
руют эффективность и переписывают критические кусочки программы,
которые расходуют много времени, на языке ассемблера. Невозмож-
ность написания таких ассемблерных процедур может иногда свести
усилия программиста к нулю. Поэтому найдите хороший букварь по
ассемблеру и приступайте! Возможно самой большой наградой для Вас
станет момент, когда Вы наконец действительно станете понимать
как же работает компьютер.

Приложение Г. Включение ассемблерных процедур в программы на
Бейсике.

Процедуры на языке ассемблера состоят из строк байтов машинно-
го кода. При выполнении этой процедуры Бейсик передает управление
из последовательности инструкций, составляющих программу на Бей-
сике, в то место, где хранятся инструкции, которые могут быть
декодированы в последовательность инструкций языка ассемблера.
При завершении ассемблерной процедуры управление возвращается в
то место бейсиковской программы, откуда была вызвана процедура.
В этой книге ассемблерные процедуры, используемые в программах
на Бейсике, приведены в двух видах. В обоих видах процедуры вклю-
чены в программу, а не хранятся в виде отдельного дискового фай-
ла. При первом способе требуется, чтобы коды процедуры находились
в отдельном месте в памяти, а при втором, менее принятом, этого
не требуется.
В первом способе процедура помещается в операторы DATA и прог-
рамма пересылается в неиспользуемую часть памяти, а затем вызы-
вается оператором CALL. Надо позаботиться о том, чтобы код проце-
дуры не накладывался на какие-либо данные и наоборот. Обычное
решение этой проблемы состоит в том, что процедура помещается в
те адреса памяти, к которым Бейсик не может получить доступ.
Поскольку интерпретатор Бейсика не может иметь доступ за пределы
64K, то для системы, скажем, с памятью 256K, нужно поместить
процедуру в старшие 64K. Для систем с памятью 128K Вы должны
вычислить сколько памяти требуется операционной системе, Бейсику
и драйверам устройств. Допустимо, чтобы они занимали 25K плюс
64K, используемых Бейсиком. В системах с 64K используйте при
старте команду CLEAR, которая ограничивает объем памяти доступный
для Бейсика. CLEAR,n ограничивает Бейсик n байтами. Затем помес-
тите процедуру в самые верхние адреса памяти.
Для указания начала области, куда будет помещена процедура,
используйте оператор DEF SEG, а затем с помощью оператора READ
считываются байты процедуры и помещаются в память до тех пор,
пока вся процедура не будет помещена на место. Например:

100 DATA &Hxx, &Hxx, &Hxx, &Hxx, &Hxx '10-байтная процедура
110 DATA &Hxx, &Hxx, &Hxx, &Hxx, &Hxx
.
.
300 '''помещаем процедуру в память
310 DEF SEG = &H3000 'указываем на область памяти
320 FOR N = 0 TO 9 'для каждого из 10 байтов
330 READ Q 'читаем байт данных
340 POKE N,Q 'помещаем его в память
350 NEXT

После того как процедура загружена в память и Вы хотите ее
использовать, необходимо чтобы последний оператор DEF SEG указы-
вал на начало процедуры. Затем присвойте целой переменной значе-
ние 0 и напишите оператор CALL с именем этой переменной. Если
процедуре передаются параметры, то они должны быть указаны в
скобках в конце оператора CALL. Например:


500 DEF SEG = &H3000 'указываем на начало процедуры
510 DOGS = 12 'у нее 3 параметра
520 CATS = 44 '
530 POSSUMS = 1 '
540 CASUALTIES = 0 'начинаем выполнение с 1-го байта
550 CALL CASUALTIES(DOGS,CATS,POSSUMS) 'выполняем процедуру

Имеется намного более простой и экономичный способ создания
ассемблерных процедур, который избегает проблемы распределения
памяти. Надо просто создать процедуру в виде строковой переменной
внутри программы. Каждый байт может быть закодирован с помощью
CHR$. Затем используйте функцию VARPTR для определения положения
этой строки в памяти. Смещение по которому находится эта перемен-
ная хранится в двух байтах, которые идут за тем, на который ука-
жет VARPTR (в первом байте содержится длина строки). Затем этот
адрес используется для вызова процедуры. Отметим способ, которым
используется оператор DEF SEG, для указания на сегмент данных
Бейсика, с тем чтобы полученное смещение указывало на адрес стро-
ки для оператора CALL. Например:

100 DEF SEG 'устанавливаем сегмент на данные Бейсика
110 X$ = "CHR$(B4)+..." 'код процедуры
120 Y = VARPTR(X$) 'получаем дескриптор строки
130 Z = PEEK(Y+1)+PEEK(Y+2)*256 'вычисляем ее адрес
140 CALL Z

Многие значения, выражаемые через CHR$() могут быть представлены
и в виде символов ASCII. Вы можете писать ROUT = CHR$(12) + "AB"
вместо ROUT = CHR$(12) + CHR$(65) + CHR$(66). На самом деле боль-
шинство символов ASCII могут вводиться путем нажатия клавиши Alt,
наборе номера кода на дополнительной клавиатуре, а затем отпуска-
ния клавиши Alt. Однако коды от 0 до 31 не могут быть введены
таким образом для наших целей.

Приложение Д. Использование драйвера устройства ANSI.SYS.

ANSI.SYS это небольшая программа, входящая в состав операцион-
ной системы, которая может быть загружена в память, с тем чтобы
увеличить возможности MS DOS. Она не сделана частью COMMAND.COM с
целью экономия памяти, когда она не используется. Средства, пре-
доставляемые ANSI.SYS, могут быть использованы для удобства прог-
раммирования, но они могут также служить средством достижения
некоторой программной совместимости с не IBM-овскими машинами,
использующими MS DOS. Этот драйвер не предоставляет никаких доба-
вочных возможностей, которых нельзя было бы добиться другим обра-
зом, но он делает некоторые возможности управления клавиатурой и
терминалом намного более простыми (и обычно более медленно). Все
свойства драйвера ANSI.SYS описаны в этой книге под соответствую-
щим заголовком.
ANSI.SYS может быть загружен только во время загрузки опера-
ционной системы. Начиная с версии 2.0 система автоматически ищет
файл CONFIG.SYS, так же как и файл AUTOEXEC.BAT. Файл CONFIG.SYS
содержит различные параметры, такие как число создаваемых буферов
для файлов. Но он содержит также и имена тех драйверов устройств,


которые должны быть загружены и включены в COMMAND.COM. ANSI.SYS
как раз и является таким драйвером. Надо просто включить в этот
файл строку DEVICE = ANSI.SYS. Она может быть единственной стро-
кой в файле. Для создания этого файла можно воспользоваться ко-
мандой COPY. Надо просто ввести с терминала такие строки:

COPY CON: CONFIG.SYS <CR>
DEVICE = ANSI.SYS <CR>
<F6> <CR>

Нажатие клавиши F6 записывает символ Ctrl-Z (ASCII 26), отмечаю-
щий конец файла.

Приложение Е. Набор инструкций микропроцессора 8088.

Число тактов, которое надо добавить для вычисления эффективно-
го адреса следующее:

компоненты адреса операнды такты

(а) база или индекс [BX],[BP],[DI],[SI] 5
(б) смещение метка или смещение 6
(в) база + индекс [BX][SI], [BX][DI] 7
[BP][SI], [BP][DI] 8
(г) смещение + база или индекс [BX],[BP],[DI],[SI] + смещ. 9
(д) смещение + база + индекс [BX][SI],[BX][DI] + смещ. 11
[BP][SI],[BP][DI] + смещ. 12

Необходимо добавить также 2 такта при пересечении сегмента. Вот
времена инструкций:

инструкция такты байты

AAA 4 1
AAD 60 2
AAM 83 1
AAS 4 1
ADC регистр, регистр 3 2
ADC регистр, память 9(13) + EA 2-4
ADC память, регистр 16(24) + EA 2-4
ADC регистр, значение 4 3-4
ADC память, значение 17(25) + EA 3-6
ADC аккумулятор, значение 4 2-3
ADD регистр, регистр 3 2
ADD регистр, память 9(13) + EA 2-4
ADD память, регистр 16(24) + EA 2-4
ADD регистр, значение 4 3-4
ADD память, значение 17(25) + EA 3-6
ADD аккумулятор, значение 4 2-3
AND регистр, регистр 3 2
AND регистр, память 9(13) + EA 2-4
AND память, регистр 16(24) + EA 2-4
AND регистр, значение 4 3-4
AND память, значение 17(25) + EA 3-6
AND аккумулятор, значение 4 2-3
CALL близкая процедура 23 3
CALL далекая процедура 36 5
CALL словный указатель в памяти 29 + EA 2-4
CALL словный регистр указатель 24 2
CALL двухсловный указатель в памяти 57 + EA 2-4
CBW 2 1
CLC 2 1
CLD 2 1
CLI 2 1
CMC 2 1
CMP регистр, регистр 3 2
CMP регистр, память 9(13) + EA 2-4
CMP память, регистр 9(13) + EA 2-4


CMP регистр, значение 4 3-4
CMP память, значение 10(14) + EA 3-6
CMP аккумулятор, значение 4 2-3
CMPS приемник, источник 22(30) 1

CMPS (REP) приемник, источник 9 + 22(30)/повтор 1
CWD 5 1
DAA 4 1
DAS 4 1
DEC словный регистр 2 1
DEC байтный регистр 3 2
DEC память 15(23) + EA 2-4
DIV байтный регистр 80-90 2
DIV словный регистр 144-162 2
DIV байт памяти (86-96) + EA 2-4
DIV слово памяти (154-172) + EA 2-4
ESC значение, память 8(12) + EA 2-4
ESC значение, регистр 2 2
HLT 2 1
IDIV байтный регистр 101-112 2
IDIV словный регистр 165-185 2
IDIV байт памяти (107-118) + EA 2-4
IDIV слово памяти (175-194) + EA 2-4
IMUL байтный регистр 80-98 2
IMUL словный регистр 128-154 2
IMUL байт памяти (86-104) + EA 2-4
IMUL слово памяти (138-164) + EA 2-4
IN аккумулятор, байт значения 10(14) 2
IN аккумулятор, DX 8(12) 1
INC словный регистр 2 1
INC байтный регистр 3 2
INC память 15(23) + EA 2-4
INT 3 52 1
INT значение байта, отличное от 3 51 2
INTO 53 или 4 1
IRET 32 1
JCXZ короткая метка 18 или 6 2
JMP короткая метка 15 2
JMP близкая метка 15 3
JMP далекая метка 15 5
Jxxx короткая метка 16 или 4 2
LAHF 4 1
LDS словный регистр, двойное слово памяти 24 + EA 2-4
LEA словный регистр, слово памяти 2 + EA 2-4
LES словный регистр, двойное слово памяти 24 + EA 2-4
LOCK 2 1
LODS строка-источник 12(16) 1
LODS (REP) строка-источник 9+13(17)/повтор 1
LOOP короткая метка 17 или 5 2
LOOPE короткая метка 18 или 6 2
LOOPNE короткая метка 19 или 5 2
LOOPNZ короткая метка 19 или 5 2
LOOPZ короткая метка 18 или 6 2
MOV память, аккумулятор 10(14) 3


MOV аккумулятор, память 10(14) 3
MOV регистр, регистр 2 2
MOV регистр, память 8(12) + EA 2-4
MOV память, регистр 9(13) + EA 2-4
MOV регистр, значение 4 2-3
MOV значение, регистр 10(14) + EA 3

MOV сегментный регистр, словный регистр 2 2
MOV сегментный регистр, слово памяти 8(12) + EA 2-4
MOV словный регистр, сегментный регистр 2 2
MOV слово памяти, сегментный регистр 9(13) + EA 2-4
MOVS приемник, источник 18(26) 1
MOVS (REP) приемник, источник 9+17(25)/повтор 1
MUL байтный регистр 70-77 2
MUL словный регистр 118-133 2
MUL байт памяти (76-83) + EA 2-4
MUL слово памяти (128-143) + EA 2-4
NEG регистр 3 2
NEG память 16(24) + EA 2-4
NOP 3 1
NOT регистр 3 2
NOT память 16(24) + EA 2-4
OR регистр, регистр 3 2
OR регистр, память 9(13) + EA 2-4
OR память, регистр 16(24) + EA 2-4
OR регистр, значение 4 3-4
OR память, значение 17(25) + EA 3-6
OR аккумулятор, значение 4 2-3
OUT байт значения, аккумулятор 10(14) 2
OUT DX, аккумулятор 8(12) 1