- •Системное программирование
- •Контрольные вопросы
- •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 Кафедра Вычислительной Техники и Программирования Московского Государственного Открытого Университета
3.2. Директивы определения данных
Для описания переменных в языке ассемблера используются директивы определения данных.
Директива DB(DefineByte, определить байт) определяет данные размером в байт:
[<имя>] DB <операнд> {,<операнд>}
Встречая директиву DB, ассемблер вычисляет операнды и записывает их значения в последовательные байты памяти. Первому из байтов дается имя, по которому на него можно потом ссылаться.
Существует два основных способа задания операндов директивы DB:
неинициализированное начальное значение ? (знак неопределенного значения);
константное выражение со значением от -128 до 255.
XDB?
По этой директиве переменной X отводится один байт памяти, в который ничего не записывается. Ассемблер запомнит адрес переменной и когда он встретится в тексте, заменит его на данный адрес (выполнит трансляцию имен). Адрес ячейки, выделенной переменной с именем X, принято называть значением имени X (в отличие от содержимого ячейки по этому адресу).
По описанию переменной ассемблер определяет, сколько байт занимает переменная в памяти. Этот размер называется типом переменной. Значение(адрес) итип(размер) переменной однозначно определяют ячейку, обозначаемую именем.
С одного и того же адреса могут начинаться ячейки размером байт, слово или двойное слово, поэтому кроме начального адреса ячейки обычно требуется знать и ее размер. В языке ассемблера существует оператор типа:
TYPE <имя>
Значением оператора является размер (в байтах) ячейки, выделенной под переменную с указанным именем. Если переменная описана по директиве DB, то для ее имени значение оператора равно 1. В языке ассемблера есть стандартная константа с именем BYTE и значением 1:
ТУРЕ X = BYTE = 1
Для определения переменной с начальным значением в качестве операнда в директиве DB указывается выражение, которое ассемблер вычислит, и значение которого запишет в ячейку памяти. В наиболее распространенном случае начальное значение байтовой переменной задается в виде числа с величиной от -128 до 255:
A DB 254 ; 0FEh
В DB -2 ; 0FEh (256-2=254)
По каждой из директив ассемблер отводит один байт и записывает в него указанное число. Причем неотрицательные числа записываются как беззнаковые, а отрицательные записываются в дополнительном коде.
В качестве начального значения переменной можно указать символ, записав его числовой код, либо сам символ в кавычках. Например, в кодировке ASCII код символа «*» равен 2Ah, поэтому следующие две директивы эквивалентны:
S DB 2Ah
S DB "*"
Во втором случае ассемблер определит код символа и запишет его в ячейку памяти.
С помощью директивы DB можно описать двоично-десятичные числа:
PACK DB 01h, 23h ; число 123 в упакованном формате
UNPACK DB 1, 2, 3 ; число 123 в неупакованном формате
Для представления числа в упакованном формате необходимо указывать две цифры обязательно в шестнадцатеричной системе счисления для трансляции каждой цифры в тетрады.
Другим более удобным способом описания является применение ASCII-чисел – записи чисел в виде символьных строк (например, ‘123’). В кодировке ASCII символьные цифры от ‘0’ до ‘9’ имеют коды от 30h до 39h. Поэтому преобразования таких символьных чисел в двоично-десятичные выполняется путем выделения младшего полубайта кода, а обратное преобразование – путем сложением с 30h.
С помощью директивы DB можно описать массив. Например, байтовый массив A из 8 элементов с начальным значением 0 для каждого из них можно определить так:
A db 0, 0, 0, 0, 0, 0, 0, 0
Директиву можно записать иначе:
A DB 8 DUP(0)
В качестве операнда здесь использована конструкция повторения, в которой сначала указывается коэффициент повторения, а затем служебное слово DUP (duplicate, копировать) и в круглых скобках повторяемая величина:
k DUP (p1, р2,..., pn)
где
k - константное выражение с положительным значением, n 1;
рi- любой допустимый операнд директивы DB (возможна вновь конструкция повторения).
Данная запись является сокращением для k раз повторенной последовательности указанных в скобках операндов.
Вложенность конструкций DUP позволяет задать многомерные массивы. Например, байтовая матрица А размера 5x10 (10 байт в строке, 5 строк) имеет вид:
A DB 5 DUP(10 DUP(?))
Директива DW(DefineWord, определить слово) определяет переменную размером в слово.
Рассмотрим допустимые виды ее операндов.
Определение неинициализированной переменной:
A DW ?
В примере ассемблер отводит под переменную А слово памяти и переменная не получает начального значения. Тип переменной равен 2, т.е. занимает два байта.
В языке ассемблера есть стандартная константа с именем WORD и значением 2:
TYPEа =WORD= 2
Операндом директивы может быть константное выражение со значением от -32768 до 65535.
B DW1234b
Под переменную B отводится слово памяти, и в ячейку записывается число, которые становится ее начальным значением. Как для директивы DB, неотрицательные числа записываются в память как числа без знака, а отрицательные числа – в дополнительном коде. Поэтому числа, которые могут быть заданы как операнды директивы DW, должны быть в диапазоне [-215, 216-1]. Числа размером в слово хранятся в памяти в обратном порядке.
В качестве операнда директивы DW может быть указано адресное выражение, т.е. выражение, значением которого является адрес:
A DB?
B DW A
В примере ассемблер запишет в слово, выделенное, под переменную B, адрес переменной A, который становится начальным значением переменной B.
В правой части директивы DW можно указать любое число операндов, а также конструкцию повторения:
A DW 100, 3 DUP(?)
Директива DD(DefineDoubleWord, определить двойное слово) определяет переменную, под которую отводится двойное слово. Переменная имеет тип DWORD (значением константы является число 4).
Определение неинициализированной переменной:
A DD ?
Под переменную А выделяется двойное слово и переменная А не получает начального значения.
Операндом директивы может быть константное выражение со значение от -231до 232-1.
B DD123456h
Переменная В получает начальное значение, причем это значение ассемблер записывает в память в обратном порядке.
Операндом директивы может быть число в диапазоне от -215до 216-1. Все выражения вычисляются в области 16-битовых чисел (по модулю 216). Например, по директиве:
A DD 8000h+8002h
начальным значением переменной A будет число 2, а не число 10002h.
В качестве операнда директивы DD может быть указано адресное выражение. В этом случае операнд определяет абсолютный адрес.
Конструкция повторения DUP:
DW 10 DUP(?), 12345h
Директива эквивалентности EQU(Equal, равно) позволяет определить константу и имеет следующий синтаксис:
<имя> EQU <операнд>
Директива аналогична описанию константы в языке Паскаль. Она определяет, что операнду дается имя, и требует, чтобы все вхождения имени в текст программы ассемблер заменял на этот операнд. Директива EQU носит информационный характер, по ней ассемблер ничего не записывает в машинную программу. Поэтому директиву EQU можно использовать в любом месте программы.
Если в правой части директивы указано имя регистра, переменной или константы, тогда имя слева объявляется синонимом данного имени и все последующие вхождения в текст программы этого имени-синонима ассемблер будет заменять на имя, указанное справа, например:
A DW ?
В EQU A
C DW В ; эквивалентно С DW A
Имена-синонимы обычно используются для введения обозначений. Например, если регистр аккумулятора используется для хранения суммы, то его можно обозначить как SUM:
SUMEQUAX
и далее использовать более наглядное имя.
Операндом директивы EQU может быть константное выражение, например:
N EQU 100
К EQU 2*N-1
Если в правой части директивы EQU находится константное выражение, тогда указанное слева имя принято называть именем константы. Значением такой константы объявляется значение выражения. Например, N – константа со значением 100, К – со значением 199. Все последующие вхождения в текст имени константы ассемблер будет заменять на значение этой константы.
Операндом может быть любой текст:
s EQU'Ошибка’
Именно на этот текст будет заменяться каждое вхождение данного имени в программу. Такой вариант директивы EQU обычно используется, чтобы ввести более короткие обозначения для часто встречающихся длинных текстов.
Директива присваиванияопределяет константу с именем, указанным в левой части и с числовым значением, равным значению выражения справа:
<имя> = <константное выражение>
В отличие от констант, определяемых по директиве EQU, константа может менять свое значение, обозначая в разных частях текста программы разные числа. По директиве присваивания можно определить только числовую константу, например:
C=10
A DW C ; эквивалентно A DW 10
C=C+2
В DB C ; эквивалентно В DB 12