Лекции 1 часть Баула (1110626), страница 7
Текст из файла (страница 7)
Все упомянутые имена регистров являются служебными в языке Ассемблера. Как и в языке Паскаль, в языке Ассемблера принято соглашение по синтаксису имён: регистр символов не различается, таким образом, AX, Ax, aX и ax обозначают один и тот же регистр.
Рассмотрим теперь способ хранения чисел в памяти ЭВМ. Запишем, например, шестнадцатеричное число 1234h в какой-нибудь 16-тиразрядный регистр (каждая шестнадцатеричная цифра занимает по 4 бита):
1 | 2 | 3 | 4 |
Теперь поместим это число в память в ячейки с номерами, например, 100 и 101. Так вот: в ячейку с номером 100 запишется число 34h, а в ячейку 101 – 12h. Говорят, что число представлено в основной памяти (в отличие от регистров) в перевёрнутом виде. Это связано с тем, что в младших моделях ЭВМ при каждом обращении к памяти читался один байт. Чтобы считать слово, было необходимо дважды обратиться к памяти, поэтому было удобно (например, для проведения операция сложения "в столбик") получать сначала младшие цифры числа, а затем – старшие. В современной архитектуре за одно обращение из памяти получают сразу 4, 8 или 16 байт, но из-за совместимости моделей семейства пришлось оставить перевёрнутое представление (и чисел и команд! – вспомним принцип Фон-Неймана) и в старших моделях.
Структура команд
Теперь рассмотрим структуру машинных команд самых распространённых форматов регистр-регистр и регистр-память.
-
Формат регистр–регистр.
6 бит | 1 бит | 1 бит | 1 бит | 1 бит | 3 бита | 3 бита |
КОП | D | w | 1 | 1 | R1 | R2 |
Команды этого формата занимают 2 байта. Первая часть команды – код операции – занимает в команде 6 бит, за ним следуют однобитные поля d и w, где d – бит направления, а w – бит размера аргумента, последующие два бита для этого формата равны 1, а последние две части по 3 бита каждая указывают на регистры – операнды.
Стоит подробнее рассмотреть назначение битов d и w. Бит d задаёт направление выполнения команды, а именно:
<R1> := <R1> <R2> при d = 0
<R2> := <R2> <R1> при d = 1.
Бит w задаёт размер регистров-операндов, имена которых можно определить по следующей схеме:
R1,2 | 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 |
В младших ЭВМ в таком формате возможна работа лишь с упомянутыми в таблице регистрами. В последующих же моделях семейства возможности этого формата были расширены, но за счёт увеличения длины команды.
Как видно из таблицы, архитектурой не предусмотрены операции формата r8–r16, т.е. операции над регистрами разной длины запрещены, например, команды типа add AL,BX или add SI,DS являются некорректными. Поэтому появляется необходимость преобразования типов из короткого целого в длинное и из длинное в сверхдлинное. Такое преобразование зависит от трактовки числа – знаковое или беззнаковое. В первом случае число всегда расширяется слева нулями, а во втором – размножается знаковый бит (для знаковых чисел незначащими двоичными цифрами будут 0 для неотрицательных и 1 для отрицательных значений). Для этого в языке в языке машины предусмотрены безадресные команды, имеющие а Ассемблере такую мнемонику:
cbw (convert byte to word)
и
cwd (convert word to double),
которые производят знаковое расширение соответственно регистра AL до AX и AX до пары регистров (DX,AX), которые в этом рассматриваются как один длинный 32 битный регистр.
Преобразование целого значения из более длинного формата в более короткий (усечение) производится путём отбрасывания соответствующего числа левых битов целого числа. Усечённое число получится правильным, если будут отброшены только незначащие биты. Для беззнаковых чисел это всегда нулевые биты, а для знаковых – биты, совпадающие со знаковым битом усечённого числа.
-
Формат регистр–память (и память-регистр).
КОП | R1 | A2 |
Операнд A2 может иметь один из приведённых ниже видов:
-
A2 = d,
-
A2 = d[M1],
-
A2 = d[M1][M2].
Здесь d – задаваемое в команде смещение длиной 1 или 2 байта (заметим, что нулевой смещение может и не занимать места в команде), M1 и M2 – так называемые регистры-модификаторы.
Стоит отметить один факт. До сих пор адресом мы называли физический номер ячейки в памяти машины. В языке Ассемблера адресом принято называть смещение ячейки относительно начала того сегмента, в котором она находится. Для обозначения полного адреса будем употреблять термин физический адрес.
Рассмотрим подробнее каждый их трёх возможных видов операнда A2. При A2 = d физический адрес задаётся формулой
A := (B*16 + A2)mod 220,
где B, как обычно, обозначает значение сегментного регистра. Запись A2 = d[M1] означает использование регистра-модификатора, которым может быть любой из следующих регистров: BP, BX, SI, DI. В этом случае физический адрес вычисляется по формуле
A := (B*16 + (d + <M>)mod 216)mod 220,
где вместо <M1> подставляется содержимое регистра-модификатора (одного из четырёх указанных). Запись A2 = d[M1][M2] обозначает вычисление физического адреса по формуле:
A := (B*16 + (d + <M1> + <M2>)mod 216)mod 220,
где используются сразу два регистра-модификатора. На месте M1 можно указывать любой из регистров BX или BP, а на месте M2 любой из регистров SI или DI. Использование, например, регистров BX и BP (как и SI и DI) одновременно в качестве модификаторов запрещено. В старших моделях почти все ограничения на использование регистров модификаторов также было снято (за счёт увеличения длины команды).
Рассмотрим теперь внутреннее представление формата команды регистр–память. Длина этой команды 4, 5 или 6 байт:
8 бит | 2 бита | 3 бита | 3 бита | 8 бит | 8 бит | ||
КОП | d | W | mod | R1 | Mem | a8 | a8->a16 |
где mod – поле модификатора, mem – поле способа адресации, a8 и a16 – это обозначения для одно- или двухбайтного смещения. Биты d и w знакомы нам из предывущего формата регистр-регистр. Все возможные комбинации mod и mem приведены ниже в таблице:
mem \ mod | 00 | 01 | 10 | 11 |
0 доп. б. | 1 доп. байт | 2 доп. байт | ФорматRR | |
000 | [BX+SI] | [BX+SI]+a8 | [BX+SI]+a16 | |
001 | [BX+DI] | [BX+DI]+a8 | [BX+DI]+a16 | |
010 | [BP+SI] | [BP+SI]+a8 | [BP+SI]+a16 | |
011 | [BP+DI] | [BP+DI]+a8 | [BP+DI]+a16 | |
100 | [SI] | [SI]+a8 | [SI]+a16 | |
101 | [DI] | [DI]+a8 | [DI]+a16 | |
110 | a16 | [BP]+a8 | [BP]+a16 | |
111 | [BX] | [BX]+a8 | [BX]+a16 |
Данная таблица показывает, как зависит способ адресации от полей mem и mod. Как видим, она объясняет ограничения на выбор регистров-модификаторов, которые мы сформулировали ранее.
Мы не будем рассматривать машинный вид остальных форматов команд, будем изучать их только на языке Ассемблера. Напомним, что это такие форматы команд:
-
регистр – регистр (RR);
-
регистр – память, память – регистр (RX);
-
регистр – непосредственный операнд в команде (RI);
-
память – непосредственный операнд (SI);
-
память – память, т.е. оба операнда в основной памяти (SS).
Команды языка машины
Далее мы будем изучать синтаксис машинных команд и семантику их выполнения центральным процессором. Для удобства команды будем записывать так, как это принято в языке Ассемблер (можно считать, что мы уже начали понемногу изучать этот язык).
Команда пересылки
Команды пересылки одни из самых распространённых в языке машины. Все они пересылают один или два байта из одного места памяти в другое. Для более компактного описания синтаксиса команд введём следующие условные обозначения:
r8 – любой короткий регистр AH,AL,Bh,BL,CH,CL,DH,DL;
r16 – любой из длинных регистров AX,BX,CX,DX,SI,DI,SP,BP;
m8, m16 – операнды в основной памяти длиной 1 и 2 байта соответственно;
i8, i16 – непосредственные операнды в самой команде длиной 1 и 2 байта соответственно;
SR – один из сегментных регистров SS, DS, ES;
m32 – операнд в основной памяти длиной 4 байта.
Общий вид команды пересылки в нашей двухадресной ЭВМ такой (точки с запятой будем записывать, как это принято в Ассемблере, комментарий к команде):
mov op1, op2; <op1> := <op2>
Существуют следующие допустимые форматы операндов:
op1 | Op2 |
R8 | r8, m8, i8 |
R16 | r16, m16, i16, SR, CS |
M8 | r8, i8 |
M16 | r16, i16, SR, CS |
SR | r16, m16 |
Арифметические операции сложения и вычитание
КОП op1, op2, где КОП = add, sub, adc, sbb.
add – сложение,
sub – вычитание:
op1 := op1 op2
adc – сложение с учётом флага переноса,
sbb – вычитание с учётом флага переноса:
op1 := op1 op2 CF
Таблица допустимых операндов:
op1 | op2 |
r8 | r8, m8, i8 |
m8 | r8, i8 |
r16 | r16, m16, i16 |
m16 | r16, i16 |
В результате выполнения операций изменяются флаги CF, OF, ZF, SF, которые отмечают соответственно за перенос, переполнение, нулевой результат и знак результата (флагу SF всегда присваивается знаковый бит результата).
Арифметические операции умножение и деление
Формат этих команд накладывает сильные ограничения на месторасположение операндов. Первый операнд всех команд этого класса явно в команде не указывается и находится в фиксированном регистре, принимаемом по умолчанию. В младшей модели семейства есть следующие команды умножения и деления:
mul op2 – беззнаковое умножение,
imul op2 – знаковое умножение,