ПРОГРАММНАЯ МОДЕЛЬ ПРОЦЕССОРОВ СЕМЕЙСТВА X86
Пользовательские регистры
Как следует из названия, пользовательскими регистры называются потому, что программист может использовать их при написании своих программ. К этим регистрам относятся (рис. 1):
· восемь 32-битных регистров, которые могут использоваться программистами для хранения данных и адресов (их еще называют регистрами общего назначения (РОН)):
eax/ax/ah/al;
ebx/bx/bh/bl;
edx/dx/dh/dl;
ecx/cx/ch/cl;
ebp/bp;
esi/si;
edi/di;
esp/sp.
шесть регистров сегментов: cs, ds, ss, es, fs, gs;
регистры состояния и управления:
регистр флагов eflags/flags;
регистр указателя команды eip/ip.
Рис. 1. Пользовательские регистры микропроцессоров i486 и Pentium
Почему многие из этих регистров приведены с наклонной разделительной чертой?
Нет, это не разные регистры -- это части одного большого 32-разрядного регистра. Их можно использовать в программе как отдельные объекты.
Так сделано для обеспечения работоспособности программ, написанных для младших 16-разрядных моделей микропроцессоров фирмы Intel, начиная с i8086.
Микропроцессоры i486 и Pentium имеют в основном 32-разрядные регистры. Их количество, за исключением сегментных регистров, такое же, как и у i8086, но размерность больше, что и отражено в их обозначениях -- они имеют приставку e (Extended).
Регистры общего назначения
Все регистры этой группы позволяют обращаться к своим “младшим” частям.
Для самостоятельной адресации можно использовать только младшие 16 и 8-битные части этих регистров. Старшие 16 бит этих регистров как самостоятельные объекты недоступны. Это сделано, как мы отметили выше, для совместимости с младшими 16-разрядными моделями микропроцессоров фирмы Intel.
Перечислим регистры, относящиеся к группе регистров общего назначения. Так как эти регистры физически находятся в микропроцессоре внутри арифметико-логического устройства (АЛУ), то их еще называют регистрами АЛУ:
eax/ax/ah/al (Accumulator register) -- аккумулятор.
Применяется для хранения промежуточных данных. В некоторых командах использование этого регистра обязательно;
ebx/bx/bh/bl (Base register) -- базовый регистр.
Применяется для хранения базового адреса некоторого объекта в памяти;
ecx/cx/ch/cl (Count register) -- регистр-счетчик.
Применяется в командах, производящих некоторые повторяющиеся действия. Его использование зачастую неявно и скрыто в алгоритме работы соответствующей команды.
К примеру, команда организации цикла loop кроме передачи управления команде, находящейся по некоторому адресу, анализирует и уменьшает на единицу значение регистра ecx/cx;
edx/dx/dh/dl (Data register) -- регистр данных.
Так же, как и регистр eax/ax/ah/al, он хранит промежуточные данные. В некоторых командах его использование обязательно; для некоторых команд это происходит неявно.
Следующие два регистра используются для поддержки так называемых цепочечных операций, то есть операций, производящих последовательную обработку цепочек элементов, каждый из которых может иметь длину 32, 16 или 8 бит:
esi/si (Source Index register) -- индекс источника.
Этот регистр в цепочечных операциях содержит текущий адрес элемента в цепочке-источнике;
edi/di (Destination Index register) -- индекс приемника (получателя).
Этот регистр в цепочечных операциях содержит текущий адрес в цепочке-приемнике.
В архитектуре микропроцессора на программно-аппаратном уровне поддерживается такая структура данных, как стек. Для работы со стеком в системе команд микропроцессора есть специальные команды, а в программной модели микропроцессора для этого существуют специальные регистры:
esp/sp (Stack Pointer register) -- регистр указателя стека.
Содержит указатель вершины стека в текущем сегменте стека.
ebp/bp (Base Pointer register) -- регистр указателя базы кадра стека.
Предназначен для организации произвольного доступа к данным внутри стека.
Не спешите пугаться столь жесткого функционального назначения регистров АЛУ. На самом деле, большинство из них могут использоваться при программировании для хранения операндов практически в любых сочетаниях. Но, как мы отметили выше, некоторые команды используют фиксированные регистры для выполнения своих действий. Это нужно обязательно учитывать.
Использование жесткого закрепления регистров для некоторых команд позволяет более компактно кодировать их машинное представление. Знание этих особенностей позволит вам при необходимости хотя бы на несколько байт сэкономить память, занимаемую кодом программы.
Сегментные регистры cs, ss, ds, es, gs, fs.
Их существование обусловлено спецификой организации и использования оперативной памяти микропроцессорами Intel. Она заключается в том, что микропроцессор аппаратно поддерживает структурную организацию программы в виде трех частей, называемых сегментами. Соответственно, такая организация памяти называется сегментной.
Для того чтобы указать на сегменты, к которым программа имеет доступ в конкретный момент времени, и предназначены сегментные регистры. Фактически, с небольшой поправкой, как мы увидим далее, в этих регистрах содержатся адреса памяти с которых начинаются соответствующие сегменты. Логика обработки машинной команды построена так, что при выборке команды, доступе к данным программы или к стеку неявно используются адреса во вполне определенных сегментных регистрах. Микропроцессор поддерживает следующие типы сегментов:
1. Сегмент кода. Содержит команды программы.
Для доступа к этому сегменту служит регистр cs (code segment register) -- сегментный регистр кода. Он содержит адрес сегмента с машинными командами, к которому имеет доступ микропроцессор (то есть эти команды загружаются в конвейер микропроцессора).
2. Сегмент данных. Содержит обрабатываемые программой данные. Для доступа к этому сегменту служит регистр ds (data segment register) -- сегментный регистр данных, который хранит адрес сегмента данных текущей программы.
3. Сегмент стека. Этот сегмент представляет собой область памяти, называемую стеком. Работу со стеком микропроцессор организует по следующему принципу: последний записанный в эту область элемент выбирается первым. Для доступа к этому сегменту служит регистр ss (stack segment register) -- сегментный регистр стека, содержащий адрес сегмента стека.
4. Дополнительный сегмент данных.
Неявно алгоритмы выполнения большинства машинных команд предполагают, что обрабатываемые ими данные расположены в сегменте данных, адрес которого находится в сегментном регистре ds.
Если программе недостаточно одного сегмента данных, то она имеет возможность использовать еще три дополнительных сегмента данных. Но в отличие от основного сегмента данных, адрес которого содержится в сегментном регистре ds, при использовании дополнительных сегментов данных их адреса требуется указывать явно с помощью специальных префиксов переопределения сегментов в команде.
Адреса дополнительных сегментов данных должны содержаться в регистрах es, gs, fs (extension data segment registers).
Регистры состояния и управления eflags и ip
Они постоянно содержат информацию о состоянии, как самого микропроцессора, так и программы, команды которой в данный момент загружены на конвейер. Используя эти регистры, можно получать информацию о результатах выполнения команд и влиять на состояние самого микропроцессора.
eflags/flags (flag register) -- регистр флагов. Разрядность eflags/flags -- 32/16 бит. Отдельные биты данного регистра имеют определенное функциональное назначение и называются флагами. Младшая часть этого регистра полностью аналогична регистру flags для i8086.
Рис. 2. Содержимое регистра eflags
Исходя из особенностей использования, флаги регистра eflags/flags можно разделить на три группы:
8 флагов состояния. Эти флаги могут изменяться после выполнения машинных команд. Флаги состояния регистра eflags отражают особенности результата исполнения арифметических или логических операций. Это дает возможность анализировать состояние вычислительного процесса и реагировать на него с помощью команд условных переходов и вызовов подпрограмм.
1 флаг управления - df (Directory Flag). Значение флага df определяет направление поэлементной обработки цепочек данных: от начала строки к концу (df = 0) либо наоборот, от конца строки к ее началу (df = 1).
5 системных флагов, управляющих вводом/выводом, маскируемыми прерываниями, отладкой, переключением между задачами и виртуальным режимом 8086. Прикладным программам не рекомендуется модифицировать без необходимости эти флаги, так как в большинстве случаев это приведет к прерыванию работы программы.
eip/ip (Instraction Pointer register) -- регистр-указатель команд.
Регистр eip/ip имеет разрядность 32/16 бит и содержит смещение следующей подлежащей выполнению команды относительно содержимого сегментного регистра cs в текущем сегменте команд. Этот регистр непосредственно недоступен программисту, но загрузка и изменение его значения производятся различными командами управления, к которым относятся команды условных и безусловных переходов, вызова процедур и возврата из процедур. Возникновение прерываний также приводит к модификации регистра eip/ip.
Типы данных. Переменные
В программе на ассемблере переменными являются регистры или ячейки памяти, в которых хранятся данные. Существует несколько типов данных-переменных:
1. Непосредственные данные, представляющие собой числовые или символьные значения, являющиеся частью команды. 20d, 0a2h, 10111b
2. Данные простого типа, описываемые с помощью ограниченного набора директив резервирования памяти, позволяющих выполнить самые элементарные операции по размещению и инициализации числовой и символьной информации.
Эти два типа данных являются элементарными, или базовыми; работа с ними поддерживается на уровне системы команд микропроцессора. Используя данные этих типов, можно формализовать и запрограммировать практически любую задачу. Но насколько это будет удобно -- вот вопрос.
3. Данные сложного типа, (массивы, структуры, записи и пр.) которые были введены в язык ассемблера с целью облегчения разработки программ. Сложные типы данных строятся на основе базовых типов, которые являются как бы кирпичиками для их построения. Введение сложных типов данных позволяет несколько сгладить различия между языками высокого уровня и ассемблером
Физическая интерпретация данных простого типа основывается на размерности данных:
· байт -- восемь последовательно расположенных битов, пронумерованных от 0 до 7, при этом бит 0 является самым младшим значащим битом;
· слово -- последовательность из двух байт, имеющих последовательные адреса. Размер слова -- 16 бит; биты в слове нумеруются от 0 до 15. Байт, содержащий нулевой бит, называется младшим байтом, а байт, содержащий 15-й бит - старшим байтом. Микропроцессоры Intel имеют важную особенность -- младший байт всегда хранится по меньшему адресу. Адресом слова считается адрес его младшего байта. Адрес старшего байта может быть использован для доступа к старшей половине слова.
· двойное слово -- последовательность из четырех байт (32 бита), расположенных по последовательным адресам.
· учетверенное слово -- последовательность из восьми байт (64 бита), расположенных по последовательным адресам.
·
Рис. 3. Основные типы данных микропроцессора
Логическая интерпретация этих типов:
- Целый тип со знаком -- двоичное значение со знаком, размером 8, 16 или 32 бита. Знак в этом двоичном числе содержится в 7, 15 или 31-м бите соответственно. Ноль в этих битах в операндах соответствует положительному числу, а единица -- отрицательному. Отрицательные числа представляются в дополнительном коде. Числовые диапазоны для этого типа данных следующие:
o 8-разрядное целое -- от -128 до +127;
o 16-разрядное целое -- от -32 768 до +32 767;
o 32-разрядное целое -- от -231 до +231-1.
- Целый тип без знака -- двоичное значение без знака, размером 8, 16 или 32 бита. Числовой диапазон для этого типа следующий:
o байт -- от 0 до 255;
o слово -- от 0 до 65 535;
o двойное слово -- от 0 до 232-1.
- Указатель на память двух типов:
o ближнего типа -- 32-разрядный логический адрес, представляющий собой относительное смещение в байтах от начала сегмента. Эти указатели могут также использоваться в сплошной (плоской) модели памяти, где сегментные составляющие одинаковы;
o дальнего типа -- 48-разрядный логический адрес, состоящий из двух частей: 16-разрядной сегментной части -- селектора, и 32-разрядного смещения.
- Цепочка -- представляющая собой некоторый непрерывный набор байтов, слов или двойных слов максимальной длины до 4 Гбайт.
- Битовое поле представляет собой непрерывную последовательность бит, в которой каждый бит является независимым и может рассматриваться как отдельная переменная. Битовое поле может начинаться с любого бита любого байта и содержать до 32 бит.
- Неупакованный двоично-десятичный тип -- байтовое представление десятичной цифры от 0 до 9. Неупакованные десятичные числа хранятся как байтовые значения без знака по одной цифре в каждом байте. Значение цифры определяется младшим полубайтом.
- Упакованный двоично-десятичный тип представляет собой упакованное представление двух десятичных цифр от 0 до 9 в одном байте. Каждая цифра хранится в своем полубайте. Цифра в старшем полубайте (биты 4-7) является старшей.
-
Рис. 4. Основные логические типы данных микропроцессора
Язык микроопераций. Ассемблер.
Структура программы на ассемблере:
Model small ;модель программы, или же количество памяти на сегмент
.data ;сегмент данных
;описание переменных
.stack 100h ;сегмент стека
.code ;сегмент данных
;процедуры, макрокоманды
main:
;основная программа
end main
Директивы резервирования памяти
Для описания простых типов данных в программе используются специальные директивы резервирования и инициализации данных, которые, по сути, являются указаниями транслятору на выделение определенного объема памяти. Если проводить аналогию с языками высокого уровня, то директивы резервирования и инициализации данных являются определениями переменных.
Машинного эквивалента этим директивам нет; просто транслятор, обрабатывая каждую такую директиву, выделяет необходимое количество байт памяти и при необходимости инициализирует эту область некоторым значением.
Директивы резервирования и инициализации данных простых типов имеют формат:
Рис. 5. Директивы описания данных простых типов
На рис. 5 использованы следующие обозначения:
· ? показывает, что содержимое поля не определено, то есть при задании директивы с таким значением выражения содержимое выделенного участка физической памяти изменяться не будет. Фактически, создается неинициализированная переменная;
· значение инициализации -- значение элемента данных, которое будет занесено в память после загрузки программы. Фактически, создается инициализированная переменная, в качестве которой могут выступать константы, строки символов, константные и адресные выражения в зависимости от типа данных. Подробная информация приведена в приложении 1;
· выражение -- итеративная конструкция с синтаксисом, описанным на рис. 5.17. Эта конструкция позволяет повторить последовательное занесение в физическую память выражения в скобках n раз.
· имя -- некоторое символическое имя метки или ячейки памяти в сегменте данных, используемое в программе.
· db -- резервирование памяти для данных размером 1 байт. Директивой db можно задавать следующие значения:
o выражение или константу, принимающую значение из диапазона:
§ для чисел со знаком -128...+127;
§ для чисел без знака 0...255;
o символьную строку из одного или более символов. Строка заключается в кавычки. В этом случае определяется столько байт, сколько символов в строке.
· dw -- резервирование памяти для данных размером 2 байта. Директивой dw можно задавать следующие значения:
o выражение или константу, принимающую значение из диапазона:
§ для чисел со знаком -32 768...32 767;
§ для чисел без знака 0...65 535;
o выражение, занимающее 16 или менее бит, в качестве которого может выступать смещение в 16-битовом сегменте или адрес сегмента;
o 1- или 2-байтовую строку, заключенная в кавычки.
· dd -- резервирование памяти для данных размером 4 байта. Директивой dd можно задавать следующие значения:
o выражение или константу, принимающую значение из диапазона:
§ для i386 и выше:
§ для чисел со знаком -2 147 483 648...+2 147 483 647;
§ для чисел без знака 0...4 294 967 295;
o относительное или адресное выражение, состоящее из 16-битового адреса сегмента и 16-битового смещения;
o строку длиной до 4 символов, заключенную в кавычки.
· df -- резервирование памяти для данных размером 6 байт;
· dp -- резервирование памяти для данных размером 6 байт. Директивами df и dp можно задавать следующие значения:
o выражение или константу, принимающую значение из диапазона:
§ для чисел со знаком -2 147 483 648...+2 147 483 647;
§ для чисел без знака 0...4 294 967 295;
o относительное или адресное выражение, состоящее из 32 или менее бит (для i80386) или 16 или менее бит (для младших моделей микропроцессоров Intel);
o адресное выражение, состоящее из 16-битового сегмента и 32-битового смещения;
o строку длиной до 6 байт, заключенную в кавычки.
· dq -- резервирование памяти для данных размером 8 байт. Директивой dq можно задавать следующие значения:
o относительное или адресное выражение, состоящее из 32 или менее бит
o константу со знаком из диапазона -263...263-1;
o константу без знака из диапазона 0...264-1;
o строку длиной до 8 байт, заключенную в кавычки.
· dt -- резервирование памяти для данных размером 10 байт. Директивой dt можно задавать следующие значения:
o относительное или адресное выражение, состоящее из 32 или менее бит
o адресное выражение, состоящее из 16-битового сегмента и 32-битового смещения;
o константу со знаком из диапазона -279...279-1;
o константу без знака из диапазона 0...280-1;
o строку длиной до 10 байт, заключенную в кавычки;
o упакованную десятичную константу в диапазоне 0...99 999 999 999 999 999 999.
Очень важно уяснить себе порядок размещения данных в памяти. Он напрямую связан с логикой работы микропроцессора с данными. Микропроцессоры Intel требуют следования данных в памяти по принципу: младший байт по младшему адресу.
Для иллюстрации данного принципа рассмотрим листинг 1, в котором определим сегмент данных. В этом сегменте данных приведено несколько директив описания простых типов данных.
Листинг 1. Пример использования директив резервирования и инициализации данных. Программа вводит строку с клавиатуры.
model small
.stack 100h
.data
message db Массив байт, содержащих символьные переменные,10,13 $
po db 1, 3, 4, 5, 0fh, 0bh, 32, 01011b
perem_1 db 0ffh
perem_2 dw 3a7fh
perem_3 dd 0f54d567ah
k1 db 10
k2 db ?
mas db 10 dup (?)
adr dw k1
adr_full dd perem_3
.code
start:
mov ax,@data
mov ds,ax
mov ah,0ah
mov dx,offset message ; mov dx, adr
int 21h
mov ax,4c00h
int 21h
end start
Система команд
Формат предложения ассемблера
[имя метки:] КОП [операнд1] [,операнд2] [;комментарии]
Команды пересылки данных
|
mov <операнд назначения>,<операнд-источник>
|
|
можно
|
Нельзя
|
Должно быть
|
|
mov ах, вх; ах:=вх
mov ах,0а2h; ах:= 0а2h
mov per1,ax
|
mov ax,bh
mov per1, per2
mov ds,per1
mov cs,ds
mov cs,ax; пара cs:ip содержит адрес следующей команды
|
mov ah, bh
mov al, per2
mov per1,al
mov ax, per1
mov ds,ax
mov ax,ds либо push ds
mov cs,ax pop cs
|
|
|
xchg <операнд1>,<операнд2> ; двунаправленный обмен данными а:=в; в:=с; с:=а
xchg dl,dh; меняет местами данные
Команды ввода-вывода в порт
in аккумулятор,номер_порта -- ввод в аккумулятор из порта
out порт,аккумулятор -- вывод содержимого аккумулятора в порт
Команды работы с адресами и указателями памяти
lea назначение,источник -- загрузка эффективного адреса источника в регистр-назначение;
lea dx, x ; аналогично команде mov dx,offset x
lds назначение,источник -- загрузка эффективного адреса источника в регистр назначения и загрузка указателя (адрес сегмента где содержится источник) в регистр сегмента данных ds;
les назначение,источник ---//-регистр дополнительного сегмента данных es;
lgs назначение,источник -- -//- регистр дополнительного сегмента данных gs;
lfs назначение,источник -- -//- регистр дополнительного сегмента данных fs;
lss назначение,источник -- -//- регистр сегмента стека ss.
les dx,per1 ;полный указатель на per1 в пару es:dx
Команды работы со стеком
Для работы со стеком предназначены три регистра:
ss -- сегментный регистр стека;
sp/esp -- регистр указателя стека;
bp/ebp -- регистр указателя базы кадра стека.
push источник -- запись значения источник в вершину стека.
Алгоритм работы:
· уменьшить значение указателя стека esp/sp на 4/2 (в зависимости от значения атрибута размера адреса -- use16 или use32);
· записать источник в вершину стека (адресуемую парой ss:esp/sp).
Размер записываемых значений -- слово или двойное слово. Также в стек можно записывать непосредственные значения. В стек можно класть значение сегментного регистра cs. Другой интересный момент связан с регистром sp. Команда push esp/sp записывает в стек значение esp/sp по состоянию до выдачи этой команды
Команда push используется совместно с командой pop для записи значений в стек и извлечения их из стека
pop назначение -- запись значения из вершины стека по месту, указанному операндом назначение. Значение при этом “снимается” с вершины стека.
Push ax
Push bx
push cx
…
pop cx
pop bx
pop ax
push ax
pop bx ; аналогично команде mov bx,ax
pusha - размещение в стеке регистров общего назначения в следующей последовательности: ax, cx, dx, bx, sp, bp, si, di
pushad - размещение в стеке регистров общего назначения в следующей последовательности: eax, ecx, edx, ebx, esp, ebp, esi, edi
pushf - размещение в вершине стека (ss:sp) содержимого регистра флагов flags
pushfd - размещение в стеке содержимого регистра флагов eflags.
popa - извлечение из стека регистров общего назначения di, si, bp, sp, bx, dx, cx, ax
popad - извлечение из стека регистров общего назначения edi, esi, ebp, esp, ebx, edx, ecx, eax
popf - извлечение из стека слова и восстановление его в регистр флагов flags
popfd - извлечение из стека двойного слова и восстановление его в регистр флагов eflags
Организация вычислений
Логические команды
Любая логическая команда меняет значение следующих флагов of, sf,zf,pf,cf (переполнение, знак, нуля, паритет, перенос)
and операнд_1,операнд_2 -- операция логического умножения (И - конъюнкция).
оп1:=оп1 ? оп2
and ah, 0a1h; ah:=ah?0ah
and bx, cx; bx:=bx?cx
and dx, x1; dx:=dx?x1
or операнд_1,операнд_2 -- операция логического сложения (ИЛИ - дизъюнкцию)
or al, x1; оп1:=оп1 & оп2
or eax,edx
or dx, x1
xor операнд_1,операнд_2 -- операция логического исключающего сложения (исключающего ИЛИ ИЛИ-НЕ)
test операнд_1,операнд_2 -- операция “проверить” (способом логического умножения).
Команда выполняет поразрядно логическую операцию И над битами операндов операнд_1 и операнд_2. Состояние операндов остается прежним, изменяются только флаги zf, sf, и pf, что дает возможность анализировать состояние отдельных битов операнда без изменения их состояния.
not операнд -- операция логического отрицания. Команда выполняет поразрядное инвертирование (замену значения на обратное) каждого бита операнда. Результат записывается на место операнда.
Пример программы логического сложения двух однобайтных чисел.
model small
.stack 100h
.data
x1 db 0c2h
x2 db 022h
y db ?
.code
start:
mov ax,@data
mov ds,ax
mov al, x1
or al, x2
mov y, al
mov ax,4c00h
int 21h
end start
Арифметические операции над целыми двоичными числами
Сложение двоичных чисел без знака
inc операнд - операция инкремента, то есть увеличения значения операнда на 1;
inc ax; ax:=ax+1
inc x1
add оп1,оп2 - команда сложения с принципом действия: оп1 = оп1 + оп2 (addition)
add al, bl
add ax, 0fe2h
add ebx, x1+2
add x1, 0fh
add x2, ax
adc оп1,оп2 - команда сложения с учетом флага переноса cf. оп1 = оп1 + оп2 + знач_cf
Вычитание двоичных чисел без знака
dec операнд -- операция декремента, то есть уменьшения значения операнда на 1;
dec cx ;cx:=cx-1
dec x
sub операнд_1,операнд_2 -- команда вычитания; ее принцип действия:
операнд_1 = операнд_1 - операнд_2
sub al, bl; al:=al-bl
sub ax, x1
sub x2, dx
sub eax, 0f35h
sub x2, 22h
sbb операнд_1,операнд_2 -- команда вычитания с учетом заема (флага cf ):
операнд_1 = операнд_1 - операнд_2 - значение_cf
Пример программы сложения двух однобайтных чисел.
model small
.stack 100h
.data
x1 db 0c2h
x2 db 022h
y db ?
.code
start:
mov ax,@data
mov ds,ax
mov al, x1
add al, x2
mov y, al
mov ax,4c00h
int 21h
end start
Умножение двоичных чисел
mul множитель_1 - операция умножения двух целых чисел без учета знака
Алгоритм работы:
Команда выполняет умножение двух операндов без учета знаков. Алгоритм зависит от формата операнда команды и требует явного указания местоположения только одного сомножителя, который может быть расположен в памяти или в регистре. Местоположение второго сомножителя фиксировано и зависит от размера первого сомножителя
mul dl; ax:=al*dl, dl- множитель_1 , al- множитель_2
mul x1; dx:ax=ax*0ad91h, x1 word- множитель_1 , ax- множитель_2
mul ecx; edx:eax=eax*ecx, ecx- множитель_1 , eax- множитель_2
imul множитель_1 - операция умножения двух целочисленных двоичных значений со знаком
Деление двоичных чисел
div делитель - выполнение операции деления двух двоичных беззнаковых значений
Алгоритм работы:
Для команды необходимо задание двух операндов -- делимого и делителя. Делимое задается неявно и размер его зависит от размера делителя, который указывается в команде
div dl ;ah:al=ax/dl, ax -делимое, dl- делитель , ah-частное, al -остаток
div x1 ;ax:dx=dx:ax/0ad91h, dx:ax -делимое, x1 word- делитель , ax-частное,
;dx -остаток
div ecx ;eax:edx=edx:eax/ecx, edx:eax -делимое, ecx- делитель , eax-частное,
;edx -остаток
idiv делитель - операция деления двух двоичных значений со знаком
Пример программы умножения двух однобайтных чисел.
model small
.stack 100h
.data
x1 db 78
yl db ?
yh db ?
.code
start:
mov ax,@data
mov ds,ax
xor ax, ax
mov al, 25
mul x1
jnc m1 ;если нет переполнения
mov yh,ah
m1:
mov yl, al
mov ax,4c00h
int 21h
end start
Пример. Вычислите следующее выражение у=(х2-х3)/х1, х1,х2,х3 - однобайтные числа
model small
.stack 100h
.data
s1 db Введите х1,10,13,$
s2 db Введите х2,10,13,$
s3 db Введите х3,10,13,$
x1 db ?
x2 db ?
yc db ? ;частное
yo db ? ;остаток
.code
start:
mov ax,@data
mov ds,ax
mov ah,09h
mov dx, offset s1
int 21h ;вывод строки
mov ah,01h вводим х1
int 21h ;вводим число
sub al,30h ;al:=x1
mov x1,al
mov ah,09h
mov dx, offset s2
int 21h
mov ah,01h вводим х2
int 21h
sub al,30h ;al:=x2
mov x2,al
mov ah,09h
mov dx, offset s3
int 21h
mov ah,01h вводим х3
int 21h
sub al,30h ;al:=x3
mov bl,x2 ;bl:=x2
sub bl,al ;bl:=x2-x3
xchg al,bl ;al:=bl, al:=x2-x3
xor ah,ah ;ax:=x2-x3 вычисляем у
mov dl,x1 ;dl:=x1
div dl ;ax/dl, ax/x1
mov yc,ah
mov yo,al
; можно вывести результат на экран
mov ax,4c00h
int 21h
end start
Команды сдвига
Все команды сдвига обеспечивают манипуляции над отдельными битами операндов, они перемещают биты в поле операнда влево или вправо в зависимости от кода операции.
Все команды сдвига устанавливают флаг переноса cf.
shl операнд,счетчик_сдвигов (Shift Logical Left) - логический сдвиг влево. Содержимое операнда сдвигается влево на количество битов, определяемое значением счетчик_сдвигов. Справа (в позицию младшего бита) вписываются нули;
shr операнд,счетчик_сдвигов -- логический сдвиг вправо.
Алгоритм работы команд:
· очередной “выдвигаемый” бит устанавливает флаг cf;
· бит, вводимый в операнд с другого конца, имеет значение 0;
· при сдвиге очередного бита он переходит во флаг cf, при этом значение предыдущего сдвинутого бита теряется!
sal операнд,счетчик_сдвигов (Shift Arithmetic Left)
sar операнд,счетчик_сдвигов
арифметический сдвиг влево/вправо. Содержимое операнда сдвигается влево/ вправо на количество битов, определяемое значением счетчик_сдвигов. Справа/ Слева в операнд вписываются нули.
Команда sal не сохраняет знака, но устанавливает флаг cf в случае смены знака очередным выдвигаемым битом. В остальном команда sal полностью аналогична команде shl;
Команда sar сохраняет знак, восстанавливая его после сдвига каждого очередного бита.
Команды циклического сдвига
rol операнд,счетчик_сдвигов (Rotate Left) -- циклический сдвиг влево.
Содержимое операнда сдвигается влево на количество бит, определяемое операндом счетчик_сдвигов. Сдвигаемые влево биты записываются в тот же операнд справа.
ror операнд,счетчик_сдвигов (Rotate Right) -- циклический сдвиг вправо.
Как видно из рис., команды простого циклического сдвига в процессе своей работы осуществляют одно полезное действие, а именно: циклически сдвигаемый бит не только вдвигается в операнд с другого конца, но и одновременно его значение становиться значением флага cf.
Команды циклического сдвига через флаг переноса cf отличаются от команд простого циклического сдвига тем, что сдвигаемый бит не сразу попадает в операнд с другого его конца, а записывается сначала в флаг переноса cf. Лишь следующее исполнение данной команды сдвига (при условии, что она выполняется в цикле) приводит к помещению выдвинутого ранее бита с другого конца операнда (см. рис. 4).
rcl операнд,счетчик_сдвигов (Rotate through Carry Left) -- циклический сдвиг влево через перенос.
Содержимое операнда сдвигается влево на количество бит, определяемое операндом счетчик_сдвигов. Сдвигаемые биты поочередно становятся значением флага переноса cf.
rcr операнд,счетчик_сдвигов (Rotate through Carry Right) -- циклический сдвиг вправо через перенос.
Содержимое операнда сдвигается вправо на количество бит, определяемое операндом счетчик_сдвигов. Сдвигаемые биты поочередно становятся значением флага переноса cf.
Из рис. 4 видно, что при сдвиге через флаг переноса появляется промежуточный элемент, с помощью которого, в частности, можно производить подмену циклически сдвигаемых битов, в частности, рассогласование битовых последовательностей.
Под рассогласованием битовой последовательности здесь и далее подразумевается действие, которое позволяет некоторым образом локализовать и извлечь нужные участки этой последовательности и записать их в другое место
Пример. Дано отрицательное число. Выведите на экран его значение по модулю деленное на 2.
Любое отрицательное число хранится в дополнительном формате
-1 ffh
-2 feh
…
-10 f6h
получить значение числа по модулю, можно осуществив логическое отрицание над числом и добавив 1.
model small
.stack 100h
.data
x db -12
.code
start:
mov ax,@data
mov ds,ax
mov al,x ;в al отрицательное число
not al
inc al ;число по модулю
shr al,1
;выводим результат на экран
aam ;
;преобразование двоичного числа меньшего 63h (9910), которое находится в al в его ;неупакованный BCD-эквивалент
; -разделить значение регистра al на 10;
; -записать частное в регистр ah, остаток -- в регистр al.
mov dx,ax ;число в регистр dx
or dx,3030h ;получаю ASCII код числа
xchg dh,dl ;меняю местами старший и младший байт, для вывода символа из dl
mov ah,02h ;
int 21h ;вывожу старшую половинку числа
xchg dh,dl ;меняю местами старший и младший байт,
int 21h ;вывожу младшую половинку числа
mov ax,4c00h
int 21h
end start
Команды передачи управления
По принципу действия, команды микропроцессора, обеспечивающие организацию переходов в программе, можно разделить на три группы:
1. Команды безусловной передачи управления:
- команда безусловного перехода; jmp
- вызова процедуры и возврата из процедуры; call, ret
- вызова программных прерываний и возврата из программных прерываний. Int, iret
2. Команды условной передачи управления:
- команды перехода по результату команды сравнения cmp;
- команды перехода по состоянию определенного флага;
- команды перехода по содержимому регистра ecx/cx.
3. Команды управления циклом:
- команда организации цикла со счетчиком ecx/cx;
- команда организации цикла со счетчиком ecx/cx с возможностью досрочного выхода из цикла по дополнительному условию.
jmp адрес_перехода - безусловный переход без сохранения информации о точке возврата. Аналог goto.
jmp m1 m4:
… …
m1: jmp m4
Условные переходы
Команды условного перехода имеют одинаковый синтаксис:
jcc метка_перехода
Мнемокод всех команд начинается с “j” -- от слова jump (прыжок), cc -- определяет конкретное условие, анализируемое командой. Что касается операнда метка_перехода, то эта метка может находится только в пределах текущего сегмента кода, межсегментная передача управления в условных переходах не допускается.
Для того чтобы принять решение о том, куда будет передано управление командой условного перехода, предварительно должно быть сформировано условие, на основании которого и будет приниматься решение о передаче управления. Источниками такого условия могут быть:
- любая команда, изменяющая состояние арифметических флагов;
- команда сравнения cmp, сравнивающая значения двух операндов;
- состояние регистра ecx/cx.
Условные переходы по содержимому флагов
|
Название флага
|
Номер бита в eflags/flag
|
Команда условного перехода
|
Значение флага для осуществления перехода
|
|
Флаг переноса cf
|
1
|
jc
|
cf = 1
|
|
Флаг четности pf
|
2
|
jp
|
pf = 1
|
|
Флаг нуля zf
|
6
|
jz
|
zf = 1
|
|
Флаг знака sf
|
7
|
js
|
sf = 1
|
|
Флаг переполнения of
|
11
|
jo
|
of = 1
|
|
Флаг переноса cf
|
1
|
jnc
|
cf = 0
|
|
Флаг четности pf
|
2
|
jnp
|
pf = 0
|
|
Флаг нуля zf
|
6
|
jnz
|
zf = 0
|
|
Флаг знака sf
|
7
|
Страницы: [1] | 2 | 3 |
|