СОДЕРЖАНИЕ
2. Программная модель микропроцессора 8086
2.4. Способы задания операндов команды
3. Основные понятия языка ассемблера
3.2. Директивы определения данных
4. Сегментированная модель памяти
4.3. Общая структура программы
5.1. Соглашению по описанию команд
5.6. Команды организации циклов
5.11. Команды управления микропроцессором
7. Разработка одномодульной программы
7.1. Трансляция и компоновка программы
8. Разработка многомодульных программ
8.1. Принципы разработки модулей
8.2. Расширенное применение директивы сегментации
Программирование микропроцессорных устройств
10. Программирование системного таймера
10.1. Описание таймера-счетчика 8254
10.3. Структура регистров таймера
11. Программирование контроллера прерываний
11.1. Механизм обработки прерываний
11.4. Контроллер прерываний 8259
11.5. Идентификация прерываний
11.6. Прерывания bios и ms-dos
12. Программирование параллельного порта
12.2. Работа с параллельным портом на низком уровне
12.3. Стандартные средства работы с параллельным портом
13. Программирование последовательного порта
13.1. Основы последовательной передачи данных
13.2. Последовательный интерфейс rs-232c
13.3. Универсальный асинхронный приемо-передатчик 8250
13.4. Порты асинхронного адаптера
13.5. Стандартные средства программирования последовательного порта
Расположение сомножителей соответствует команде MUL. Произведение имеет разрядность, вдвое превышающую разрядность множителей. Оно размещается в регистре AX (8-разрядные множители, 16-разрядный результат) или в регистровой паре DX:AX (16-разрядные множители, 32-разрядный результат, старшая часть в регистре DX, младшая – в AX).
Рассмотрим несколько примеров использования команд умножения:
N DB 10
...
MOV AL, 2
MUL N ; AX=2*10=20=0014h: AH=00h, AL=14h
MOV AL, 32
MUL N ; AX=32*10 = 320=0140h: AH=01h, AL=40h
MOV AX, 8
MOV BX, -1
IMUL BX ; (DX, AX) = -8=0FFFFFFF8h: DX=0FFFFh, AX=0FFF8h
С помощью анализа флагов переноса CF и переполнения OF выполняется проверка, умещается ли результат умножения в формат сомножителей:
произведение занимает двойной формат CF=OF=1;
произведению достаточен формат сомножителей CF=OF=0.
Во втором случае произведение байтов занимает только регистр AL, а произведение слов – только регистр АХ. Но если CF=1, то далее приходится работать с результатом как с числом удвоенного формата.
Начиная с процессора 80186, доступен упрощенный вариант команд умножения MUL и IMUL. Их мнемоника включает три операнда. Первый операнд может быть только регистром r16, второй операнд r/m16, третий операнд непосредственный imm16. Следовательно, команды позволяют оперировать только словами, и результат умножения также должен быть размером слово. Команды перемножают второй и третий операнды и помещают результат в регистр общего назначения. Такие расширения команд имеют и другие инструкции (см. команды сдвига и стековые команды).
Следует заметить, что трансляторы языка ассемблера TASM и MASM по умолчанию воспринимают только базовый набор команд процессора 8086. Чтобы сделать для них доступными расширения команд, введенные в более поздних моделях процессоров, например, в 80186, необходимо указывать специальные директивы.
Например, директива .8086 допускает использование только команд 8086, а директива .186 допускает использование команд процессора 8086 и новых команд процессора 80186. Директивы могут быть указаны в любом месте программы на языке ассемблера, и действовать они будут до появления следующей подобной директивы.
Инструкция AAM обеспечивает коррекцию результата умножения двух неупакованных двоично-десятичных чисел командой MUL (табл. 27). Флаги SF, ZF и PF устанавливаются по обычным правилам. Значение флагов OF, AF и CF не определено.
Табл. 27. Команда AAM.
|
Код |
Инструкция |
Описание |
|
D4 0A |
AAM |
Коррекция умножения неупакованных двоично-десятичных чисел. |
Коррекция заключается в том, что в регистр AH заносится целая часть от деления содержимого регистра AL на 10, а в регистр AL – остаток:
MOV AL, 8
MOV BL, 9
MUL BL ; AH=0 AL=72
AAM;AH=7AL=2
Команда DIV производит целочисленное деление двух беззнаковых двоичных чисел (табл. 28). Флаги не изменяются. Делимое должно иметь размер 16 или 32 разряда. В первом случае оно располагается в регистре AX, во втором занимает регистровую пару DX:AX (старшая часть – в регистре DX, младшая – в регистре AX). Делитель размещается в регистре или ячейке памяти, определяемой байтом ModRegR/M. При 16-разрядном делимом делитель имеет размер байт, а при 32-разрядном делимом – слово.
Частное и остаток имеют разрядность, совпадающую с разрядностью делителя, т.е. в два раза меньше, чем у делимого. В операции деления 16-разрядного числа на 8-разрядное частное располагается в регистре AL, остаток – в регистре AH. При делении 32-разрядного числа на 16-разрядное частное будет находиться в регистре AX, а остаток – в регистре DX.
Табл. 28. Команда DIV.
|
Код |
Инструкция |
Описание |
|
F6 /6 |
DIV r/m8 |
AL:= AX DIV r/m8 AH:= AX MOD r/m8 |
|
F7 /6 |
DIV r/m16 |
AX:= DX, AX DIV r/m16 DX:= DX, AX MOD r/m16 |
При выполнении команды деления возможно появление ошибки в двух случаях: делитель равен 0 или неполное частное не вмещается в отведенное ему место (регистр AL или АХ). Во втором случае происходит прекращение выполнение программы.
Команда IDIV производит целочисленное деление двух двоичных чисел со знаком (табл. 29). Флаги не изменяются. Знак остатка всегда совпадает со знаком делимого.
Табл. 29. Команда IDIV.
|
Код |
Инструкция |
Описание |
|
F6 /7 |
IDIV r/m8 |
AL:= AX DIV r/m8 AH:= AX MOD r/m8 |
|
F7 /7 |
IDIV r/m16 |
AX:= DX, AX DIV r/m16 DX:= DX, AX MOD r/m16 |
Команда AAD выполняет коррекцию двоично-десятичного неупакованного делимого, находящегося в регистре AX (в AH – старшая цифра, в AL – младшая) (табл. 30). Команда должна предшествовать DIV. Флаги SF, ZF и PF устанавливаются по обычным правилам. Значение флагов OF, AF и CF не определено.
Табл. 30. Команда AAD.
|
Код |
Инструкция |
Описание |
|
D5 0A |
AAD |
Коррекция неупакованного двоично-десятичного делимого. |
Команда корректирует делимое, состоящее из двух двоично-десятичных цифр, находящихся в младших полубайтах регистров AH и AL (старшие полубайты должны быть нулевыми). В регистр AX помещается двоичный эквивалент двоично-десятичного неупакованного числа, который вычисляется по формуле AL=10*AH + AL. После выполнения команды DIV в регистре AL будет сформировано правильное двоичное частное:
MOV AX, 0403h ; делимое 43 (AH=4 AL=3)
MOV BL, 5 ; делитель 5
AAD ; AX=43 (двоичное)
DIV BL ; AH=3 (остаток) AL=8 (частное)
Для преобразования результата в двоично-десятичный формат можно воспользоваться инструкцией AAM. Остаток в регистре AH принимает значение 0–9 в зависимости от значения исходных операндов, поэтому не нуждается в дополнительном преобразовании.
Команды изменения размера операнда.Арифметические команды не позволяют выполнять операции над операндами разного размера. Например, операция BX:=BX+AL недопустима, т.к. здесь требуется сложить слово с байтом. Поэтому для выполнения такой операции необходимо привести операнды к одной размерности – расширить байт AL до слова. Если число беззнаковое, то расширение заключается в дополнении числа слева нулями.
Например, если AL=32=20h, то AX=0020h и реализуется это записью 0 в регистр АН:
MOV АН, 0 ; AL > АХ (без знака)
Такое расширение называется расширением без знака. Для знаковых чисел следует учитывать знак. Если число неотрицательно, то его достаточно дополнить нулями. Если число отрицательное, тогда слева надо дописать двоичные единицы (FF в шестнадцатеричной системе). Например, число -32 (-20h) в дополнительном коде как байт имеет вид 256-32 = 100h-20h = 0E0h, а как слово -10000h-20h = 0FFE0h. Такое расширение называется расширением со знаком.
Для расширения со знаком в системе команд предусмотрена команда CBW (табл. 31).
Табл. 31. Команда CBW.
|
Код |
Инструкция |
Описание |
|
98 |
CBW |
Расширение байта до слова. |
Содержимое регистра AL, рассматриваемое как число со знаком, расширяется на регистр AH (рис. 19). Флаги не изменяются. Если в AL содержалось отрицательное число (т.е. если старший разряд регистра AL равен 1), все разряды регистра AH устанавливаются в единицу.

Рис. 19. Расширение со знаком байта до слова.
Если в AL содержался нуль или положительное число (старший разряд регистра AL равен 0), регистр AH обнуляется:

00hприAL>=0
AH=
0FFhприAL< 0
Приведем примеры расширения беззнаковых и знаковых чисел:
; числа без знака:
MOV АН, 0
AL > АХ (расширение без знака)
ADD ВХ, АХ
; числа со знаком:
CBW
; AL > АХ (расширение со знаком)
ADD BX, AX
Необходимость расширения байта до слова возникает при делении байтов. Разрешено делить слово на байт, но не байт на байт. Если такое деление необходимо, следует первый байт (делимое) расширить до слова. Обычно расширяют слово в регистре АХ до двойного слова, занимающего два регистра – DX и АХ (в DX находится старшая часть числа, а в АХ – младшая):
АХ > (DX, AX)
При этом расширение беззнакового числа АХ реализуется обнулением регистра DX:
MOV DX, 0 ; АХ > (DX, AX) (без знака)
Если число АХ рассматривается как знаковое, тогда для его расширения в регистр DX следует записать 0000h, если число неотрицательно, или FFFFh, если отрицательно. Для такого расширения в системе команд предусмотрена команда CWD (табл. 32).
Табл. 32. Команда CWD.
|
Код |
Инструкция |
Описание |
|
99 |
CWD |
Расширение слова до двойного слова. |
Содержимое регистра AX, рассматриваемое как число со знаком, после расширения будет занимать регистровую пару DX:AX (рис. 20). В регистр DX заносится старшая часть результата. Флаги не изменяются.

Рис. 20. Расширение со знаком слова до двойного слова.
Если в AX содержалось отрицательное число (т.е. старший разряд регистра AX равен 1), все разряды регистра DX устанавливаются в единицу. Если в AX содержался нуль или положительное число (старший разряд регистра AX равен 0), регистр DX обнуляется:

0000h при AX >=0
DX =
FFFFh при AX < 0
Приведем примеры применения команд изменения размерности:
CBW
ADD AX, DX ; сложить байт в AL со словом в DX
CBW
IMUL DX ; умножить байт в AL на слово в DX
CWD
IDIV DX ; разделить слово в AL на слово в BX
Последняя арифметическая команда меняет знак операнда на противоположный (табл. 33). Флаги OF,SF,ZF,AFиPFустанавливаются в соответствии с результатом. Флаг CF сбрасывается, если исходный операнд равен нулю, и устанавливается в противном случае.
Табл. 33. Команда NEG.
|
Код |
Инструкция |
Описание |
|
F6 /3 |
NEG r/m8 |
r/m8:= – r/m8 |
|
F7 /3 |
NEG r/m16 |
r/m16:= – r/m16 |
Пример команды изменения знака операнда:
MOV АН, 1
NEG АН ; АН:=1 (0FFh)
Заметим, что для байтовых чисел, если операнд равен -128 (80h), не меняется, т.к. нет знакового числа +128. Аналогично для чисел-слов: если значение операнда равно -32768 (8000h), то команда не меняет операнд. В этом случае флаг OF получает значение 1 (при других операндах OF=0). При нулевом операнде флаг CF равен 0, при других -1. Флаги SF и ZF меняются обычным образом.
Команда NEG полезна при вычитании значения регистра или ячейки памяти из непосредственного операнда. Допустим, необходимо вычесть из 100 значение регистра AL. Команда SUB 100, AL невозможна, т.к. непосредственный операнд не может быть приемником. Поэтому можно обратить знак содержимого регистра AL и затем добавить к нему 100:
NEG AL
ADD AL, 100