CodeNet / Языки программирования / Ассемблер / СПРАВОЧНИК по системе программирования ТУРБО АССЕМБЛЕР 2.0
СПРАВОЧНИК по системе программирования ТУРБО АССЕМБЛЕР 2.0
Сегментные регистры ----------------------------------------------------------------- Теперь мы подошли к наиболее необычному аспекту процессора 8086 - сегментации памяти. Основной предпосылкой сегментации яв- ляется следующее: процессор 8086 может адресоваться к 1 мегабайту памяти. Для адресации ко всем ячейкам адресного пространства в 1 мегабайт необходимы 20-разрядные сегментные регистры. Однако про- цессор 8086 использует только 16-разрядные указатели на ячейки памяти. Вспомним, например, что для ссылки на память используется 16-разрядный регистр BX. Как же тогда согласовать 16-разрядные указатели процессора 8086 и 20-разрядные адреса? Ответ состоит в том, что процессор 8086 использует двухсту- пенчатую схему адресации. Да, используются 16-разрядные указате- ли, но эта форма представляет собой только часть полной схемы ад- ресации. Каждый 16-разрядный указатель памяти или смещение комби- нируется с содержимым 16-разрядного сегментного регистра для фор- мирования 20-разрядного адреса памяти. Сегменты и смещения комбинируются следующим образом: значе- ние сегмента сдвигается влево на 4 (то есть умножается на 16), а затем складывается со смещением, как показано на Рис. 4.7. --------------------------- ---------------- | 16-разрядный сегментный | | 16-разрядное | | регистр | | смещение | --------------------------- ---------------- | | V | -------------------- | ( умножение на 16 ) | ( /сдвиг влево на 4/ ) | -------------------- | | | V | ---------------------- | | Значение сегмента, | | | умноженное на 16, | | | равно 20-разрядно- | | | му значению | | ---------------------- | | | | ----- | ---------->( + )<------------- ----- | V --------------------------------------- | 20-разрядное значение адреса памяти | --------------------------------------- Рис. 4.7 20-разрядные адреса памяти. Рассмотрим, например, следующий фрагмент программы: . . . mov ax,1000h mov ds,ax mov si,201h mov dl,[si] . . . Здесь для сегментного регистра DS устанавливается значение 1000h, SI устанавливается в значение 201h. Мы можем представить их в виде 4сегмент:смещение" - 1000:201h. (Эффективные вычисления для пары "сегмент:смещение" могут выполняться только по основа- нию 16. Это еще одна причина необходимости познакомиться с шест- надцатиричной арифметикой.) Адрес в DL, из которого загружается адрес, представляет собой: ((DS * 16) + SI) или ((1000h * 16) + 201h) 1000h Х 16 ------ 10000h Этот пример иллюстрируется на Рис. 4.8. --------------------------- ---------------- DS | 1000h | SI | 201h | --------------------------- ---------------- | | V | -------------------- | ( умножение на 16 ) | ( /сдвиг влево на 4/ ) | -------------------- | | | V | ---------------------- | | 10000h | | ---------------------- | | | | ----- | ---------->( + )<------------- ----- | V ----------------------- Адрес памяти | 10201h | ----------------------- Рис. 4.8 Вычисление адреса памяти с помощью инструкции mov. С другой стороны это можно рассматривать просто как сдвиг значения сегмента на 4 бита, или одну шестнадцатиричную цифру, что эквивалентно умножению на 16: 1000 + 201 ----- 10201 Теперь вы можете видеть, что программа получает доступ к полному адресному пространству в 1 мегабайт с помощью использова- ния только пары "сегмент:смещение". Фактически, для доступа к па- мяти вы всегда должны использовать пару "сегмент:смещение". Все инструкции и режимы адресации процессора 8086 по умолчанию рабо- тают относительно того или иного сегментного регистра, хотя в не- которых инструкциях можно явно указать, что нужно использовать желаемый сегментный регистр. Вам редко потребуется загружать значение непосредственно в сегментный регистр. Вместо этого вы будете загружать в сегментные регистры имена сегментов, которые в ходе ассемблирования, компо- новки и выполнения превращаются в числа. Это необходимо, посколь- ку нет способа сказать заранее, где в памяти будет находиться данный сегмент: это зависит от версии DOS, числа и размера рези- дентных в памяти программ, а также потребности в памяти остальной части программы. Использование имен сегментов позволяет Турбо Ас- семблеру и операционной системе DOS выполнять подобные вычисле- ния. Наиболее общим именем сегмента является @Date, которое в уп- рощенных директивах определения сегментов используется для ссылки на используемый по умолчанию сегмент данных. Например: DOSSEG .MODEL SMALL .DATA var1 DW 0 . . . .CODE mov ax,@data mov ds,ax . . . END Здесь регистр DS загружается таким образом, что он будет указывать на используемый по умолчанию сегмент данных, в котором находится Var1. Здесь мы опять забежали вперед: упрощенные директивы опреде- ления сегментов и загрузку сегментных регистров мы обсудим в сле- дующей главе. Использование сегментов процессора 8086 приводит к некоторым интересным моментам. Один из них состоит в том, что только блок памяти размером в 64К в любой момент может адресоваться через сегментный регистр, так как 64К - это максимальный объем памяти, к которой можно адресоваться с помощью 16-битового смещения. Это может оказаться неприятным при работе с большим (более 64К) объ- емом памяти, так как и значение сегментного регистра, и смещение, придется часто изменять. Адресация к большим блокам памяти в процессоре 8086 может представлять еще большую трудность, поскольку, в отличие от ре- гистров общего назначения (общих регистров), сегментные регистры не могут использоваться в качестве источников или приемников в арифметических и логических инструкциях. Фактически, единственная операция, которую можно выполнять с сегментными регистрами, сос- тоит в копировании значений между сегментными регистрами и други- ми общими регистрами или памятью. Например, чтобы добавить значе- ние 100 к регистру ES, потребуется следующее: . . . mov ax,es add ax,100 mov es,ax . . . Из всего этого можно сделать заключение, что процессор 8086 лучше подходит для работы с памятью в блоках, не превышающих 64К. Второй момент использования сегментов состоит в том, что каждая ячейка памяти адресуется через многие возможные сочетания "сегмент:смещение". Например, адрес памяти 100h адресуется с по- мощью следующих значений "сегмент:смещение": 0:100h, 1:F0h, 2:E0h и т.д., так как при вычислении всех этих пар "сегмент:смещение" получается значение адреса 100h. Аналогично регистрам общего назначения каждый сегментный ре- гистр играет свою, конкретную роль. Регистр CS указывает на код программы, DS указывает на данные, SS - на стек, сегмент (сегмен- тный регистр) ES - это "трафаретный" (дополнительный) сегмент, который может использоваться так, как это необходимо. Рассмотрим сегментные регистры более подробно.