Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Assembler / P10

.pdf
Скачиваний:
54
Добавлен:
02.06.2015
Размер:
252.31 Кб
Скачать

10. Кодирование команд.

Мы не будем детально изучать кодирование всех команд: лучше предоставить Ассемблеру работу по переводу мнемоники команд в их код. Однако полезно иметь ясное представление о принципах кодирования команд. Заметим, что мы уже изучили кодирование команд перехода.

10.1. Однооперандные команды.

Для примера возьмем команду inc dst — она увеличивает операнд на единицу. Имеется несколько вариантов кодирования этой команды.

10.1.1. Инкремент 16-разрядного регистра. Код команды занимает один байт:

7 6 5 4 3 2 1 0

КОП

 

 

reg16

Здесь КОП — код операции, для inc

reg16 это 01000. 16-разрядные регистры ко-

дируются в соответствии с табл. 10.1.

 

 

 

 

Таблица 10.1.

 

000

 

AX

 

 

001

 

CX

 

 

010

 

DX

 

 

011

 

BX

 

 

100

 

SP

 

 

101

 

BP

 

 

110

 

SI

 

 

111

 

DI

 

Тогда inc cx кодируется так: 01000 001= 41h. Упражнение. Проверить это утверждение в TD.

10.1.2. Инкремент любого регистра (8- или 16-разрядного), байта или слова памяти. Код команды занимает два байта (старший байт носит название постбайта):

постбайт

КОП

w

mod КОП r/m

КОП теперь содержится в двух полях: в битах 7:1 первого байта и 5:3 постбайта. Для команды inc содержимое этих полей 1111111 и 000.

w (word) — длина операнда. Если w = 1 (ДА) — операнд-слово, w = 0 (НЕТ) — опе- ранд-байт.

mod (mode) — режим. При mod = 11 операнд находится в регистре, при mod = 00, 01, 10 операнд располагается в памяти.

r/m (register/memory) — если операнд находится в регистре, это поле содержит номер регистра.

10.1.2.1. Операнд в регистре.

Таблицу кодирования регистров придется расширить (табл. 10.2).

Таблица 10.2.

r/m

w=1

w=0

000

AX

AL

 

 

 

 

 

 

001

 

 

 

CX

 

 

 

CL

 

 

 

 

 

 

 

 

 

 

 

010

 

 

 

DX

 

 

 

DL

 

 

 

 

 

 

 

 

 

 

 

011

 

 

 

BX

 

 

 

BL

 

 

 

 

 

 

 

 

 

 

 

100

 

 

 

SP

 

 

 

AH

 

 

 

 

 

 

 

 

 

 

 

101

 

 

 

BP

 

 

 

CH

 

 

 

 

 

 

 

 

 

 

 

110

 

 

 

SI

 

 

 

DH

 

 

 

 

 

 

 

 

 

 

 

111

 

 

 

DI

 

 

 

BH

 

 

 

 

 

Пример: Расшифруем код команды inc cl — FE C1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

1

1

1

1

1

 

1

 

0

 

1

 

1

0

0

0

0

0

1

 

 

 

 

 

 

 

 

 

 

 

 

 

CL

 

 

 

 

КОП

 

 

 

 

w

reg8

КОП

 

 

На первый взгляд парадокс! Код inc cl занимает два байта, а код inc cx — один байт! Конечно, inc cx можно было закодировать и в двух байтах (какой бит для этого надо изменить?), но для инкремента 16-разрядных регистров предусмотрен укороченный формат кода команды. Именно его и выбирает Ассемблер.

10.1.2.2. Операнд в памяти.

Содержимое поля mod расшифровывается так: 00 — смещения нет;

01 — D8 (расширяется со знаком до D16); 10 — D16.

Здесь D8 — число, занимающее байт, D16 — число, занимающее слово (D — сокращение от слова DATA — данные).

Содержимое поля r/m теперь означает комбинацию базового и индексного регистров

(табл. 10.3).

Таблица 10.3.

 

 

 

 

 

 

 

 

 

 

 

 

000

 

BX+SI

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

001

 

BX+DI

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

010

 

BP+SI

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

011

 

BP+DI

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

100

 

 

SI

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

101

 

 

DI

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

110

 

 

D16

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

111

 

 

BX

 

 

 

 

 

 

 

 

 

 

 

 

Исключение: mod = 00, r/m = 110 — это не [BP]!

 

 

 

 

 

 

 

 

 

 

 

Пример. Дешифруем команду FF445C.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

1

1

1

1

1

1

1

 

0

1

 

0

0

0

1

0

0

 

0

1

0

1

1

1

0

0

КОП 1111111 000 — команда inc; w = 1 — операнд-слово; mod = 01 — имеется 8- разрядное смещение, D8 = 5C, расширяем знак: 005С; r/m = 100 — соответствует индексному регистру SI.

Итак, мнемоника команды inc word ptr [si+5C].

Теперь посмотрим, как будет работать эта команда. Для этого сделаем допущения:

SI = 0A086h, DS = 20F0h. Тогда эффективный адрес равен 0A086h + 005Ch = 0A0E2h —

смещение в сегменте. Так как в адресаци не участвует BP, то сегментный адрес выбирается из DS. Физический адрес: 20F00h + 0A0E2h = 2AFE2h. Операнд — слово — расположен в байтах с адресами 2AFE2 и 2AFE3.

Предположим, что до операции [2AFE2] = 0FFh, [2AFE3] = 00h. Тогда после операции

[2AFE2] = 00h, [2AFE3] = 01h.

10.1.3. Прямая адресация.

В команде непосредственно указывается адрес (точнее, смещение) операнда, например inc word ptr [200]. Разработчики процессора хотели закодировать прямую адресацию какой-либо комбинацией mod и r/m, но все сочетания оказались задействованы для регистровой и косвенной адресации. Пришлось привлечь редко используемую комбинацию mod = 00 и r/m = 110 (т.е. [BP]; далее мы увидим, что использовать этот метод адресации нет необходимости).

Смещение кодируется в двух байтах в самой команде:

 

постбайт

 

 

00

110

 

 

 

 

 

 

 

DISP-LO (младший

 

DISP-HI (старший

 

 

 

байт смещения)

 

байт смещения)

Упражнение. Вручную закодируйте inc word ptr [200] и проверьте результат в отладчике.

Упражнение. Выясните, как мини-ассемблер отладчика закодирует команду inc word ptr [bp].

Составим сводную таблицу (табл. 10.4) методов адресации в зависимости от содержимого полей r/m, mod и w. Эта таблица не содержит для нас новой информации.

Таблица 10.4

 

 

 

Поле mod

 

 

 

Поле r/m

00

01

 

10

 

11

 

 

w=0

 

w=1

 

 

 

 

 

 

000

BX+SI

BX+SI+D8

 

BX+SI+D16

AL

 

AX

001

BX+DI

BX+DI+D8

 

BX+DI+D16

CL

 

CX

010

BP+SI

BP+SI+D8

 

BP+SI+D16

DL

 

DX

011

BP+DI

BP+DI+D8

 

BP+DI+D16

BL

 

BX

100

SI

SI+D8

 

SI+D16

AH

 

SP

101

DI

DI+D8

 

DI+D16

CH

 

BP

110

D16

BP+D8

 

BP+D16

DH

 

SI

111

BX

BX+D8

 

BX+D16

BH

 

DI

Еще раз заметим, что красоту этой таблицы портит прямая адресация при r/m = 110, mod = 00.

Может возникнуть вопрос: мы узнали, как кодируется регистровая, прямая и косвенная адресации. А как же непосредственная? Ответ: в однооперандных командах непосредственного операнда не бывает (команда не может изменить свой код — ведь он находится в очереди команд в центральном процессоре).

10.2. Двухоперандные команды.

На этот раз в качестве примера рассмотрим команду сложения add dst,src. Поставим себя на место разработчиков системы команд процессора. Если приемник и

источник оба находятся в памяти, то для кодирования каждого из них потребуются свои поля mod и r/m. Сосчитаем количество битов, необходимых для кодирования: на поле mod нужно 2 + 2 бита и на поле r/m — 3 + 3 бита — всего 10 битов. Получается, что постбайта не хватит, и ради двух битов придется в код команды включить дополнительный байт. Чтобы сократить длину команд, разработчики решили, что хотя бы один операнд должен обязательно находиться в регистре (мы пока не рассматриваем случай непосредственного операнда). Тогда для одного операнда потребуется поле reg — 3 бита, а для другого —

mod и r/m — 2 + 3 = 5 битов. Всего 8 бит — ровно байт. Формат типичной команды имеет вид:

 

 

 

 

 

 

 

 

 

 

 

постбайт

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

КОП

 

 

d w

 

mod reg

r/m

Для команды ADD, например, код операции 0000000. Назначение поля w уже известно. Новое поле d (destination — приемник) несет следующую информацию: если d = 0, то приемник определяется полями mod и r/m (т.е. этот операнд находится в памяти или регистре), если d = 1, то приемник определяется полем reg (т.е. заведомо находится в реги-

стре).

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Пример. Дешифруем код 02 EB.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

0

0

0

0

0

1

0

 

1

1

 

1

 

0

 

1

0

 

1

 

1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

КОП

 

 

d

w

 

mod

 

 

reg

 

 

r/m

 

 

w = 0 — операнды-байты; d = 1

— приемник

в

регистре, определяемом полем reg;

reg = 101 — это регистр CH (в соответствии с табл. 10.4); mod = 11 — источник также в регистре; r/m = 11 — это регистр BL (по табл. 10.4). Итак, код соответствует команде add ch,bl.

Упражнение. Реассемблировать вручную код 00 00. Проверить результат в отладчике.

10.3. Непосредственный операнд.

Напомним, что удобство использования непосредственного операнда определяется двумя причинами:

1)уменьшается требуемая память (иначе пришлось бы в команде хранить адрес константы, а саму константу хранить в памяти);

2)непосредственный операнд берется прямо из кода команды, поэтому не тратится время на обращение к памяти для выборки операнда.

Опять обратимся к примеру. Команда сложения с непосредственным операндом add dst, imm максимально кодируется шестью байтами.

постбайт

 

 

 

 

DISP-LO

DISP-HI

DATA-LO

DATA-HI

 

присутствие зависит от

 

имеется,

 

поля mod

 

если s:w=01

Байты, которые необязательно присутствуют в коде команды, показаны пунктиром. Сначала посмотрим структуру первых двух байтов:

1

0

0

0

0

0

 

 

 

 

 

0

0

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

КОП

 

 

s w

 

mod КОП r/m

Сразу заметим, что код операции ADD изменился, увеличилась и его длина: вместо 6 бит стало 9. Бит приемника d исчез — понятно почему, ведь непосредственный операнд не может быть приемником. Поля mod и r/m нам уже знакомы. Соответственно, в зависимости от mod в коде может присутствовать смещение D8 или D16.

Зато появился новый бит s (sign — знак). Он занимает место d, т.к. бит d теперь не нужен. Смысл бита s таков. В арифметических операциях часто используются небольшие по величине непосредственные операнды и отводить для них целое слово слишком расточительно. При w = 0 (операнд-байт) значение s не играет роли. При w = 1 (операнд-слово): если s=0, то в команде присутствуют все 16 бит DATA; если же s = 1, то присутствуют 8 бит (DATA-LO), которые расширяются со знаком до 16-разрядного операнда. Благодаря биту s экономится один байт! Это — кодировка с расширением знака (sign-extended encodings).

Упражнение. Введите в TD в панели данных окна CPU по адресу ds:0100 (этот адрес совпадает с cs:0100 при входе в TD) последовательность байтов: 81,0C3,0FF,0,83,0C3,0FF. Объяснить результат, полученный в панели кода.

Казалось бы, мы полностью разобрались с командой ADD. Но есть еще один ее вариант! При выполнении команды сложения приемником, как правило, является аккумулятор (AX или AL). Для прибавления к аккумулятору введена специальная кодировка (укоро-

ченный формат ADD):

 

 

 

 

0 0 0 0 0 1 0

w

 

DATA-LO

DATA-HI

 

 

 

 

 

присутствует, если w=1

10.4. Общие замечания о кодировании команд.

Подведем итоги. Создатели микропроцессора 8086 приложили максимум усилий для компактного кодирования команд: для часто используемых вариантов команд имеются сокращенные форматы. В качестве одного из операндов полезно по возможности использовать аккумулятор, т.к. для него нередко генерируется меньшая по длине команда.

Очень много форматов используется для кодирования наиболее распространенной команды mov. Поэтому в примерах эта команда отсутствовала.

Длина команды может составлять от одного до шести байт (для процессора 8086). Полученные сведения могут показаться излишними, но теперь вы должны четко по-

нимать, например, почему нельзя использовать адресацию [CX]. Потому что разработчикам не хватило номеров для методов адресации. Стал ясным запрет на использование в команде двух операндов из памяти.

Еще одно упражнение, которое поможет понять нехитрые программистские трюки для сокращения длины кода программы.

Упражнение. 1) При обработке массива слов для перехода к следующему слову нужно увеличивать на два содержимое индексного регистра. Что короче: две команды inc si или одна команда add si,2 ?

2) Какая команда обнуления регистра короче: mov bx,0 или xor bx,bx ?

В процессоре 80386 набор методов адресации существенно увеличен. Естественно, увеличилась и возможная длина кода команды. Набор методов адресации 8086 входит в 80386 как подмножество.

Задание A5. Получить с помощью отладчика коды команд, выделить в этих кодах поля и расшифровать их.

1) dec ax; 2) dec al; 3) inc word ptr [bx+si+24h]; 4) inc byte ptr [bx+di–4A0h]; 5) sub [bx+si],ah; 6) sub word ptr [bx+14h],3; 7) sub byte ptr [bx+14h],–3.

10.5. Префикс замены сегмента.

С помощью изученных методов адресации можно обращаться только к сегменту данных, адрес которого хранится в DS, или к стековому сегменту, адрес которого хранится в SS. А если нужно обратиться к данным, хранящимся в сегменте, адрес которого лежит в ES? Тогда перед кодом команды нужно вставить байт — префикс замены сегмента (segment override prefix). Формат этого байта:

7

6

5

4

3

2

1

0

0

0

1

seg

 

1

1

0

Здесь seg — номер сегментного регистра, кодируемый в соответствии с таблицей 10.5.

Таблица 10.5.

ES

00

CS

01

SS

10

DS

11

Может возникнуть вопрос: а к какому из операндов команды относится префикс замены сегмента. Ответ прост: в команде только один операнд может ссылаться на ячейку памяти, поэтому неоднозначности не возникает.

Пример. Для команды mov ax, es:[bx], или mov ax, es:[bx] (эти две формы эквивалентны) Ассемблер сгенерирует перед кодом команды префиксный байт 26h=00100110. Проверьте.

10.6. Команда загрузки исполнительного адреса.

С косвенной адресацией тесно связана команда загрузки адреса.

Загрузить исполнительный адрес

lea r16,mem

reg ← адрес mem

Load Effective Address

 

флаги не изменяются

lea r16,m

 

 

Врегистр загружается не сам операнд, а его адрес, точнее, смещение в текущем сегменте данных.

Пример. mov si,200 mov bx,10

lea di,[bx+si+4]

Врезультате выполнения этих команд DI = 214.

Упражнение. Результат выполнения команды lea di,[200]?

Соседние файлы в папке Assembler