Смекни!
smekni.com

ЯЗЫК МАКРОАССЕМБЛЕРА IBM PC (стр. 4 из 9)

4) Формат "память-непосредственный операнд" (3-6 байтов):

----------- -------------- -------------- ------------------

| КОП |s|w| |mod|КОП"|mem| |адрес (0-2б)| |непоср.оп (1-2б)|

----------- -------------- -------------- ------------------

Команды этого формата описывают операции типа mem:=mem_immed. Смысл всех полей - тот же, что и в предыдущих форматах.

Помимо рассмотренных в ПК используются и другие форматы команды с двумя операндами; так, предусмотрен специальный формат для команд, один из операндов которых фиксирован (обычно это регистр AX). Имеют свои форматы и команды с другим числом операндов.

1.3.3 Запись команд в MASM

Из сказанного ясно, что одна и та же операция в зависимости от ти­пов операдов записывается в виде различных машинных команд: например, в ПК имеется 28 команд пересылки байтов и слов. В то же время в MASM

все эти "родственные" команды записываются единообразно: например, все команды пересылки имеют одну и ту же символьную форму записи:

MOV op1,op2 (op1:=op2)

Анализируя типы операндов, ассемблер сам выбирает подходящую машинную команду.

В общем случае команды записываются в MASM следующим образом:

метка: мнемокод операнды ;комментарий

Метка с двоеточием, а также точка с запятой и комментарий могут отсут­ствовать. Метка играет роль имени команды, ее можно использовать в ко­мандах перехода на данную команду. Комментарий не влияет на смысл ко­манды, а лишь поясняет ее.

Мнемонические названия операций полностью перечислены в главе 2. Операнды, если есть, перечисляются через запятую. Основные правила

записи операндов следующие.

Регистры указываются своими именами, например:

MOV AX,SI ;оба операнда - регистры

Непосредственные операнды задаются константными выражениями (их значениями являются константы-числа), например:

MOV BH,5 ;5 - непосредственный операнд

MOV DI,SIZE X ;SIZE X (число байтов, занимаемых перемен­;ной X) - непосредственный операнд

Адреса описываются адресными выражениями (например, именами пере­менных), которые могут быть модифицированы по одному или двум регист­рам; например, в следующих командах первые операнды задают адреса:

MOV X,AH

MOV X[BX][DI],5

MOV [BX],CL

При записи команд в символьной форме необходимо внимательно сле­дить за правильным указанием типа (размера) операндов, чтобы не было ошибок. Тип обычно определяется по внешнему виду одного из них, напри­мер:

MOV AH,5 ;пересылка байта, т.к. AH - байтовый регистр

MOV AX,5 ;пересылка слова, т.к. AX - 16-битовый регистр

;(операнд 5 может быть байтом и словом, по нему ;нельзя определить размер пересылаемой величины)

MOV [BX],300 ;пересылка слова, т.к. число 300 не может быть ;байтом

Если по внешнему виду можно однозначно определить тип обоих опе­рандов, тогда эти типы должны совпадать, иначе ассемблер зафиксирует ошибку. Примеры:

MOV DS,AX ;оба операнда имеют размер слова

MOV CX,BH ;ошибка: регистры CX и BH имеют разные размеры

MOV DL,300 ;ошибка: DL - байтовый регистр, а число 300 не ;может быть байтом

Возможны ситуации, когда по внешнему виду операндов нельзя опреде­лить тип ни одного из них, как, например, в команде

MOV [BX],5

Здесь число 5 может быть и байтом, и словом, а адрес из регистра BX может указывать и на байт памяти, и на слово. В подобных ситуациях ас­семблер фиксирует ошибку. Чтобы избежать ее, надо уточнить тип одного из операндов с помощью оператора с названием PTR:

MOV BYTE PTR [BX],5 ;пересылка байта

MOV WORD PTR [BX],5 ;пересылка слова

(Операторы - это разновидность выражений языка MASM, аналогичные функ­циям.)

Оператор PTR необходим и в том случае, когда надо изменить тип, предписанный имени при его описании. Если, например, X описано как имя переменной размером в слово:

X DW 999

и если надо записать в байтовый регистр AH значение только первого байта этого слова, тогда воспользоваться командой

MOV AH,X

нельзя, т.к. ее операнды имеют разный размер. Эту команду следует за­писать несколько иначе:

MOV AH,BYTE PTR X

Здесь конструкция BYTE PTR X означает адрес X, но уже рассматриваемый не как адрес слова, а как адрес байта. (Напомним, что с одного и того же адреса может начинаться байт, слово и двойное слово; оператор PTR

уточняет, ячейку какого размера мы имеем в виду.)

И еще одно замечание. Если в символьной команде, оперирующей со словами, указан непосредственный операнд размером в байт, как, напри­мер, в команде

MOV AX,80h

то возникает некоторая неоднозначность: что будет записано в регистр AX - число 0080h (+128) или 0FF80h (-128)? В подобных ситуациях ассем­блер формирует машинную команду, где операнд-байт расширен до слова, причем расширение происходит со знаком, если операнд был записан как отрицательное число, и без знака в остальных случаях. Например:

MOV AX,-128 ; => MOV AX,0FF80h (A:=-128)


MOV AX,128 ; => MOV AX,0080h (A:=+128) MOV AX,80h ; => MOV AX,0080h (A:=+128)

1.4. СЕГМЕНТИРОВНИЕ

1.4.1 Сегменты памяти. Сегментные регистры.

Первые модели ПК имели оперативную память объемом 2^16 байтов (64Кб) и потому использовали 16-битовые адреса. В последующих моделях память была увеличена до 2^20 байтов (1Мб=1000Кб), для чего уже необ­ходимы 20-битовые адреса. Однако в этих ПК ради сохранения преемствен­ности были сохранены 16-битовые адреса: именно такие адреса хранятся в регистрах и указываются в командах, именно такие адреса получаются в результате модмфикации по базовым и индексным регистрам. Как же удает­ся 16-битовыми адресами ссылаться на 1Мб памяти?

Эта проблема решается с помощью сегментирования адресов (неявного базирования адресов). В ПК вводится понятие "сегмент памяти". Так на­зывается любой участок памяти размером до 64Кб и с начальным адресом, кратным 16. Абсолютный (20-битовый) адрес A любой ячейки памяти можно

представить как сумму 20-битового начального адреса (базы) B сегмента, которому принадлежит ячейка, и 16-битового смещения D - адреса этой ячейки, отсчитанного от начала сегмента: A=B+D. (Неоднозначность выбо­ра сегмента не играет существенной роли, главное - чтобы сумма B и D давала нужный адрес.) Адрес B заносится в некоторый регистр S, а в ко­манде, где должен быть указан адрес A, вместо него записывается пара из регистра S и смещения D (в MASM такая пара, называемая адресной па­рой или указателем, записывается как S:D). Процессор же устроен так, что при выполнении команды он прежде всего по паре S:D вычисляет абсо­лютный адрес A как сумму содержимого регистра S и смещения D и только затем обращается к памяти по этому адресу A. Вот так, заменяя в коман­дах абсолютные адреса на адресные пары, и удается адресовать всю па­мять 16-битовыми адресами (смещениями).

В качестве регистра S разрешается использовать не любой регистр, а только один из 4 регистров, называемых сегментными: CS, DS, SS и ES. В связи с этим одновременно можно работать с 4 сегментами памяти: начало одного из них загружается в регистр CS и все ссылки на ячейки этого сегмента указываются в виде пар CS:D, начало другого заносится в DS и все ссылки на его ячейки задаются в виде пар DS:D и т.д. Если одновре­менно надо работать с большим числом сегментов, тогда нужно своевре­менно спасать содержимое сегментных регистров и записывать в них на­чальные адреса пятого, шестого и т.д. сегментов.

Отметим, что используемые сегменты могут быть расположены в памяти произвольным образом: они могут не пересекаться, а могут пересекаться и даже совпадать. Какие сегменты памяти использовать, в каких сегмент­ных регистрах хранить их начальные адреса - все это личное дело автора машинной программы.

Как и все регистры ПК, сегментные регистры имеют размер слова. По­этому возникает вопрос: как удается разместить в них 20-битовые на­чальные адреса сегментов памяти? Ответ такой. Поскольку все эти адреса кратны 16 (см. выше), то в них младшие 4 бита (последняя 16-ричная цифра) всегда нулевые, а потому эти биты можно не хранить явно, а лишь подразумевать. Именно так и делается: в сегментном регистре всегда хранятся только первые 16 битов (первые четыре 16-ричные цифры) на­чального адреса сегмента (эта величина называется номером сегмента или просто сегментом). При вычислении же абсолютного адреса A по паре S:D процессор сначала приписывает справа к содержимому регистра S четыре нулевых бита (другими словами, умножает на 16) и лишь затем прибавляет смещение D, причем суммирование ведется по модулю 2^20:

Aабс = 16*[S]+D (mod 2^20)

Если, например, в регистре CS хранится величина 1234h, тогда адресная пара 1234h:507h определяет абсолютный адрес, равный 16*1234h+507h = 12340h+507h = 12847h.

1.4.2 Сегментные регистры по умолчанию

Согласно описанной схеме сегментирования адресов, замену абсолют­ных адресов на адресные пары надо производить во всех командах, имею­щих операнд-адрес. Однако разработчики ПК придумали способ, позволяю­щий избежать выписывания таких пар в большинстве команд. Суть его в том, что заранее договариваются о том, какой сегментный регистр на ка-

кой сегмент памяти будет указывать, и что в командах задается только смещение: не указанный явно сегментный регистр автоматически восста­навливается согласно этой договоренности. И только при необходимости нарушить эту договоренность надо полностью указывать адресную пару.

Что это за договоренность?

Считается, что регистр CS всегда указывает на начало области памя­ти, в которой размещены команды программы (эта область называется сег­ментом команд или сегментом кодов), и потому при ссылках на ячейки этой области регистр CS можно не указывать явно, он подразумевается по умолчанию. (Отметим попутно, что абсолютный адрес очередной команды, подлежащей выполнению, всегда задается парой CS:IP: в счетчике команд IP всегда находится смещение этой команды относительно адреса из реги­стра CS.) Аналогично предполагается, что регистр DS указывает на сег­мент данных (область памяти с константами, переменными и другими вели­чинами программы), и потому во всех ссылках на этот сегмент регистр DS можно явно не указывать, т.к. он подразумевается по умолчанию. Регистр SS, считается, указывает на стек - область памяти, доступ к которой осуществляется по принципу "последним записан - первым считан" (см. 1.7), и потому все ссылки на стек, в которых явно не указан сегментный регистр, по умолчанию сегментируются по регистру SS. Регистр ES счита­ется свободным, он не привязан ни к какому сегменту памяти и его можно использовать по своему усмотрению; чаще всего он применяется для дос­тупа к данным, которые не поместились или сознательно не были размеще­ны в сегменте данных.