- •Системное программирование
- •Контрольные вопросы
- •2. Программная модель микропроцессора 8086
- •2.1. Представление информации
- •2.2. Регистры микропроцессора
- •2.3. Формат машинной команды
- •2.4. Способы задания операндов команды
- •Контрольные вопросы
- •3. Основные понятия языка ассемблера
- •3.1. Предложения
- •3.2. Директивы определения данных
- •3.3. Выражения
- •Контрольные вопросы
- •4. Сегментированная модель памяти
- •4.1. Сегментирование адресов
- •4.2. Директивы сегментации
- •4.3. Общая структура программы
- •4.4. Модели памяти
- •Контрольные вопросы
- •5. Основные группы команд
- •5.1. Соглашению по описанию команд
- •5.2. Команды пересылки данных
- •5.3. Арифметические команды
- •5.4. Логические команды
- •5.5. Команды переходов
- •5.6. Команды организации циклов
- •5.7. Команды обработки строк
- •5.8. Стековые команды
- •5.9. Команды ввода-вывода
- •5.10. Команды прерываний
- •5.11. Команды управления микропроцессором
- •Контрольные вопросы
- •6. Подпрограммы
- •Контрольные вопросы
- •7. Разработка одномодульной программы
- •7.1. Трансляция и компоновка программы
- •7.2. Отладка программы
- •Контрольные вопросы
- •8. Разработка многомодульных программ
- •8.1. Принципы разработки модулей
- •8.2. Расширенное применение директивы сегментации
- •9. Упражнения
- •Контрольные вопросы
- •Программирование микропроцессорных устройств
- •10. Программирование системного таймера
- •10.1. Описание таймера-счетчика 8254
- •10.2. Режимы работы таймера
- •10.3. Структура регистров таймера
- •10.4. Упражнения
- •Контрольные вопросы
- •11. Программирование контроллера прерываний
- •11.1. Механизм обработки прерываний
- •11.2. Типы прерываний
- •11.3. Приоритеты прерываний
- •11.4. Контроллер прерываний 8259
- •11.5. Идентификация прерываний
- •11.6. Прерывания bios и ms-dos
- •11.7. Упражнения
- •Контрольные вопросы
- •12. Программирование параллельного порта
- •12.1. Интерфейс Centronics
- •12.2. Работа с параллельным портом на низком уровне
- •12.3. Стандартные средства работы с параллельным портом
- •12.4. Упражнения
- •Контрольные вопросы
- •13. Программирование последовательного порта
- •13.1. Основы последовательной передачи данных
- •13.2. Последовательный интерфейс rs-232c
- •13.3. Универсальный асинхронный приемо-передатчик 8250
- •13.4. Порты асинхронного адаптера
- •13.5. Стандартные средства программирования последовательного порта
- •13.6. Упражнения
- •Контрольные вопросы
- •Литература
- •141 Кафедра Вычислительной Техники и Программирования Московского Государственного Открытого Университета
4.2. Директивы сегментации
Все предложения, которые требуется разместить в одном сегменте памяти, в исходном тексте программы должны быть объединены в один программный сегмент, который имеет следующую структуру:
<имя сегмента> SEGMENT <параметры>
<предложение>
...
<предложение>
<имя сегмент> ENDS
Между директивами может быть указано любое число предложений, которые ассемблер разместит в одном сегменте памяти. Размер сегмента не должен превышать 64 Кб. В программе может быть несколько сегментов с одним и тем же именем. В этом случае они рассматриваются как один сегмент, разделенный на несколько частей, и все предложения из этих сегментов ассемблер объединит вместе.
Ассемблер размещает в памяти программные сегменты последовательно, с адреса, кратного 16 (выравнивание по границе параграфа), и имени каждого сегмента присваивает его номер в памяти, т.е. первые 16 разрядов начального адреса данного сегмента.
Приведем пример использования директивы SEGMENT:
A SEGMENT
A1 DB 100h DUP(?)
A2 DW 8
A ENDS
В SEGMENT
B1 DW A2
B2 DD А2
В ENDS
С SEGMENT
L: MOV AX, A2
MOVBX,B2
С ENDS
При трансляции предложений ассемблер ставит в соответствие описанным именам переменных и меткам адреса – смещения соответствующих ячеек памяти, отсчитанные от начала сегмента. В примере имя A1 получит смещение 0, имя A2 – смещение 100h, имя B1 – смещение 0, имя B2 – смещение 2, имя L – смещение 0. Имена переменных и метки рассматриваются как адресные выражения. Но есть возможность рассматривать их и как константные, для чего используется оператор:
OFFSET <имя>
Значением оператора является смещение переменной, относительно начала сегмента, в котором оно описано:
OFFSET A1 = 0
OFFSET A2 = 100h
OFFSET L = 0
Оператор SEG позволяет узнать, в каком сегменте описано имя переменной или метка:
SEG <имя>
Значением оператора является имя сегмента, в котором описана переменная-операнд:
SEG A1 = SEG A2 = А
SEG B1 = SEG B2 = В
SEG L = С
Директива SEGMENT не содержит информации о функциональном назначении сегментов, поэтому все сегменты равноправны. Директива ASSUME (предполагать) позволяет сообщить транслятору, что данный сегмент будет использоваться как сегмент кода, данных или стека.
Директиву ASSUME обычно указывают в начале сегмента команд:
ASSUME <пара> {, <пара>}
где <пара> обозначает адресную пару <сегментный регистр>:<имя сегмента>
Например, директива:
ASSUME ES: A, DS: B, CS: C
сообщает транслятору, что для сегментирования адресов из сегмента A выбран регистр ES, для адресов из сегмента B – регистр DS, а для адресов из сегмента C – регистр CS.
Например, команда MOV AX, A2 будет транслироваться как MOV AX, ES:A2 (имя A2 описано в сегменте А), а команда MOV АХ, B2 как MOV AX, DS:B2 (имя B2 описано в сегменте B).
Перечисли особенности применения директивы ASSUME. Если в директиве ASSUME указано несколько пар с одним сегментным регистром, то последнее объявление отменяет предыдущее, т.к. каждому сегментному регистру можно поставить в соответствие только один сегмент. Например, по директиве:
ASSUME DS:A, DS:B
ассемблер будет считать, что регистр DS указывает только на сегмент В.
На один и тот же сегмент могут указывать разные сегментные регистры. Например, в следующей директиве:
ASSUME ES:A, DS:A
на сегмент A будут указывать регистры ES и DS. Ассемблер выберет префикс, который в транслируемой команде подразумевается по умолчанию, поскольку его можно опустить и сэкономить память.
Если в директиве ASSUME в качестве второго элемента пары задано служебное слово NOTHING (ничего), например ASSUME ES:NOTHING, то сегментный регистр не указывает ни на какой сегмент, и ассемблер не должен использовать регистр при трансляции команд. Для отмены ранее установленных соответствий для всех сегментных регистров, используется конструкция:
ASSUME NOTHING
Директива ASSUME может быть указана любое число раз. При этом несколько подряд идущих директив можно объединить в одну. Например, последовательность директив:
ASSUME ES:A ASSUME DS:B ASSUME CS:C
эквивалентна директиве:
ASSUMEES:A,DS:B,CS:C
Следует заметить, что директива ASSUME не загружает в сегментные регистры начальные адреса сегментов. Поэтому выполнение программы должно начинаться с загрузки в сегментные регистры начальных адресов соответствующих сегментов памяти.
Например, сегментный регистр DS требуется установить на начало сегмента B, т.е. выполнить присваивание DS:=B. Команда пересылки MOV DS, B недопустима, т.к. имя сегмента есть константное выражение, а помещение непосредственного операнда в сегментный регистр запрещена. Поэтому инициализацию регистра DS можно выполнить, используя только несегментный регистр, например АХ:
MOV AX, B
MOV DS, AX
Аналогично загружаются регистр ES. Регистр CS загружать не нужно, т.к. к началу выполнения программы регистр уже будет указывать на начало сегмента команд. Такую загрузку выполнит операционная система, прежде чем передаст управление программе.
Регистр SS должен указывать на начало стека. Настроить его можно аналогично DS или поручить операционной системе. В последнем случае в директиве SEGMENT необходимо указать параметр STACK:
S SEGMENT STACK
В результате загрузка S в регистр SS будет выполнена автоматически до начала выполнения программы.