Перейти на: Главную | Индексную | Форумную страницу |
FFFF0, что является точкой входа в BIOS. BIOS проверяет различные порты компьютера для определения и инициализации подключенных устрой ств. Затем BIOS создает в начале памяти (по адресу 0) таблицу прерываний, которая содержит адреса обработчиков прерываний, и выполняет две операции INT 11H (запрос списка присоединенного оборудования) и INT 12H (запрос размера физической памяти). Следующим шагом BIOS определяет имеется ли на диске или дискете операционная система DOS. Если обнаружена системная дискета, то BIOS выполняет прерывание INT 19H для доступа к первому сектору диска, содержащему блок начальной загрузки. Этот блок представляет собой программу, которая считывает системные файлы IBMBIO.COM, IBMDOS.COM и COMMAND.COM с диска в память. После этого память имеет следующее распределение: Таблица векторов прерываний Данные BIOS IBMBIO.COM и IBMDOS.COM Резидентная часть COMMAND.COM Доступная память для прикладных программ Транзитная часть COMMAND.COM Конец RAM (ОЗУ) ROM BASIC ROM BIOS Внешние устройства передают сигнал внимания через контакт INTR в процессор. Процессор реагирует на этот запрос, если флаг прерывания IF установлен в 1 (прерывание разрешено), и (в большинстве случаев) игнорирует запрос, если флаг IF установлен в 0 (прерывание запрещено). Операнд в команде прерывания, например, INT 12H, содержит тип прерывания, который идентифицирует запрос. Для каждого типа система содержит адрес в таблице векторов прерываний, начинающейся по адресу 0000. Так как в таблице имеется 256 четырехбайтовых элементов, то она занимает первые 1024 байта памяти от шест.0 до шест.3FF. Каждый элемент таблицы указывает на подпрограмму обработки указанного типа прерывания и содержит адрес кодового сегмента и смещение, которые при прерывании устанавливаются в регистры CS и IP соответственно. Список элементов таблицы векторов прерываний приведен на рис. 23.1. Прерывание заносит в стек содержимое флагового регистра, регистра CS и регистра IP. Например, для прерывания 12H (которое возвращает в регистре AX размер памяти) адрес элемента таблицы равен шест.0048 (шест.12 х 4 = шест.48). Операция выделяет четырехбайтовый элемент по адресу шест. 0048 и заносит два байта в регистр IP и два байта в регистр SS. Адрес, который получается в регистровой паре CS:IP, представляет собой адрес начала подпрограммы в области BIOS, которая получает управление. Возврат из этой подпрограммы осуществляется командой IRET (Interrupt Return), которая восстанавливает флаги и регистры CS и IP из стека и передает управление на команду, следующую за выполненной командой прерывания. __________________________________________________________________________ Адрес Функция прерываний (шест.) (шест.) 0-3 0 Деление на нуль 4-7 1 Пошаговый режим (трассировка DEBUG) 8-B 2 Немаскированное прерывание (NMI) C-F 3 Точка останова (используется в DEBUG) 10-13 4 Переполнение регистра 14-17 5 Печать экрана 18-1F 6,7 Зарезервировано 20-23 8 Сигнал от таймера 24-27 9 Сигнал от клавиатуры 28-37 A,B,C,D Используются в компьютерах AT 38-3B E Сигнал от дискетного дисковода 3C-3F F Используется для принтера 40-43 10 Управление дисплеем (см.гл. 8, 9, 10) 44-47 11 Запрос оборудования (см.гл.9) 48-4B 12 Запрос размера памяти (см.гл.2) 4C-4F 13 Дисковые операции ввода-вывода (см.гл.18) 50-53 14 Управление коммуникационным адаптером 54-57 15 Кассетные операции и спец. функции AT 58-5B 16 Ввод с клавиатуры (см.гл.9) 5C-5F 17 Вывод на принтер (см.гл.19) 60-63 18 Обращение к BASIC, встроенному в ROM 64-67 19 Перезапуск системы 68-6B 1A Запрос и установка времени и даты 6C-6F 1B Прерывание от клавиатуры 70-73 1C Прерывание от таймера 74-77 1D Адрес таблицы параметров дисплея 78-7B 1E Адрес таблицы параметров дисковода 7C-7F 1F Адрес таблицы графических символов 80-83 20 Нормальное завершение программы (DOS) 84-87 21 Обращение к функциям DOS 88-8B 22 Адрес обработки завершения задачи (DOS) 8C-8F 23 Адрес реакции по Ctrl/Break (DOS) 90-93 24 Адрес реакции на фатальную ошибку (DOS) 94-97 25 Абсолютное чтение с диска (DOS) 98-9B 26 Абсолютная запись на диск (DOS) 97-9F 27 Создание резидентной программы (DOS) AO-FF 28-3F Другие функции DOS 100-1FF 40-7F Зарезервировано 200-217 80-85 Зарезервировано для BASIC 218-3C3 86-F0 Используются BASIC-интерпретатором 3C4-3FF F1-FF Зарезервировано Примечание: Прерывания 00-1F относятся к BIOS, прерывания 20-FF относятся к DOS и BASIC. __________________________________________________________________________ Рис.23.1. Таблица адресов прерываний. ПРЕРЫВАНИЯ BIOS ________________________________________________________________ В данном разделе приведены основные прерывания BIOS. INT 05H. П е ч а т ь э к р а н а. Выполняет вывод содержимого экрана на печатающее устройство. Команда INT 05H выполняет данную операцию из программы, а нажатие клавишей Ctrl/PrtSc - с клавиатуры. Операция запрещает прерывания и сохраняет позицию курсора. INT 10H. У п р а в л е н и е д и с п л е е м. Обеспечивает экранные и клавиатурные операции, детально описанные в гл.9. INT 11H. З а п р о с с п и с к а п р и с о е д и н е н н о г о о б о р у д о в а н и я. Определяет наличие различных устройств в системе, результирующее значение возвращает в регистре AX. При включении компьютера система выполняет эту операцию и сохраняет содержимое AX в памяти по адресу шест.410. Значения битов в регистре AX: Бит Устройство 15,14 Число подключенных принтеров. 13 Последовательный принтер. 12 Игровой адаптер. 11-9 Число последовательных адаптеров стыка RS232. 7,6 Число дискетных дисководов, при бите 0=1: 00=1, 01=2, 10=3 и 11=4. 5,4 Начальный видео режим: 00 = не используется, 01 = 40х25 плюс цвет, 10 = 80х25 плюс цвет, 11 = 80х25 черно-белый режим. 1 Значение 1 говорит о наличии сопроцессора. 0 Значение 1 говорит о наличии одного или более дисковых устройств и загрузка операционной системы должна осуществляться с диска. INT 12H З а п р о с р а з м е р а ф и з и ч е с к о й п а м я т и. Возвращает в регистре AX размер памяти в килобайтах, например, шест.200 соответствует памяти в 512 К. Данная операция полезна для выравнивания размера программы в соответствии с доступной памятью. INT 13H. Д и с к о в ы е о п е р а ц и и в в о д а - в ы в о д а. Обеспечивает операции ввода-вывода для дискет и винчестера, рассмотренные в главе 16. INT 14H. У п р а в л е н и е к о м м у н и к а ц и о н н ы м а д а п т е р о м. Обеспечивает последовательный ввод-вывод через коммуникационный порт RS232. Регистр DX должен содержать номер (0 или 1) адаптера стыка RS232. Четыре типа операции, определяемые регистром AH, выполняют прием и передачу символов и возвращают в регистре AX байт состояния коммуникационного порта. INT 15H. К а с с е т н ы е о п е р а ц и и в в о д а - в ы в о д а и с п е ц и а л ь н ы е ф у н к ц и и д л я к о м п ь ю т е р о в AT. Обеспечивает операции ввода-вывода для кассетного магнитофона, а также расширенные операции для компьютеров AT. INT 16H. В в о д с к л а в и а т у р ы. Обеспечивает три типа команд ввода с клавиатуры, подробно описанные в гл.9. INT 17H. В ы в о д н а п р и н т е р. Обеспечивает вывод данных на печатающее устройство. Подробно рассмотрено в гл.19. INT 18H. О б р а щ е н и е к BASIC, в с т р о е н н о м у в ROM. Вызывает BASIC-интерпретатор, находящийся в постоянной памяти ROM. INT 19H. П е р е з а п у с к с и с т е м ы. Данная операция при доступном диске считывает сектор 1 с дорожки 0 в область начальной загрузки в памяти (сегмент 0, смещение 7C00) и передает управление по этому адресу. Если дисковод не доступен, то операция передает управление через INT 18H в ROM BASIC. Данная операция не очищает экран и не инициализирует данные в ROM BASIC, поэтому ее можно использовать из программы. INT 1AH. З а п р о с и у с т а н о в к а т е к у щ е г о в р е м е н и и д а т ы. Считывает и записывает показание часов в соответствии со значением в регистре AH. Для определения продолжительности выполнения программы можно перед началом выполнения установить часы в 0, а после считать текущее время. Отсчет времени идет примерно 18,2 раза в секунду. Значение в регистре AH соответствует следующим операциям: AH=00 Запрос времени. В регистре CX устанавливается старшая часть значения, а в регистре DX - младшая. Если после последнего запроса прошло 24 часа, то в регистре AL будет не нулевое значение. AH=01 Установка времени. Время устанавливается по регистрам CX (старшая часть значения) и DX (младшая часть значения). Коды 02 и 06 управляют временем и датой для AT. INT 1FH. А д р е с т а б л и ц ы г р а ф и ч е с к и х с и м в о л о в. В графическом режиме имеется доступ к символам с кодами 128-255 в 1К таблице, содержащей по восемь байт на каждый символ. Прямой доступ в графическом режиме обеспечивается только к первым 128 ASCII-символам (от 0 до 127). ПРЕРЫВАНИЯ DOS ________________________________________________________________ Во время своей работы BIOS использует два модуля DOS: IBMBIO.COM и IBMDOS.COM. Так как модули DOS обеспечивают большое количество разных дополнительных проверок, то операция DOS обычно проще в использовании и менее машиннозависимы, чем их BIOS аналоги. Модуль IBMBIO.COM обеспечивает интерфейс с BIOS низкого уровня. Эта программа выполняет управление вводом-выводом при чтении данных из внешних устройств в память и записи из памяти на внешние устройства. Модуль IBMDOS.COM содержит средства управления файлами и ряд сервисных функций, таких как блокирование и деблокирование записей. Когда пользовательская программа выдает запрос INT 21H, то в программу IBMDOS через регистры передается определенная информация. Затем программа IBMDOS транслирует эту информацию в один или несколько вызовов IBMBIO, которая в свою очередь вызывает BIOS. Указанные связи приведены на следующей схеме: Пользовательский Высший Низший ROM Внешний уровень уровень уровень уровень ------------¬ -----------¬ -----------¬ ¦Программный¦ ¦ DOS ¦ ¦ DOS ¦ -----¬ -----------¬ ¦запрос в/в ¦.¦IBMDOS.COM¦.¦IBMBIO.COM¦.¦BIOS¦.¦Устройство¦ L------------ L----------- L----------- L----- L----------- Как показано выше, прерывания от шест.20 до шест.62 зарезервированы для операций DOS. Ниже приведены наиболее основные из них: INT 20H. З а в е р ш е н и е п р о г р а м м ы. Запрос завершает выполнение программы и передает управление в DOS. Данный запрос обычно находится в основной процедуре. INT 21H. З а п р о с ф у н к ц и й DOS. Основная операция DOS, вызывающая определенную функцию в соответствии с кодом в регистре AH. Назначение функций DOS описано в следующем разделе. INT 22H. А д р е с п о д п р о г р а м м ы о б р а б о т к и з а в е р ш е н и я з а д а ч и. (см.INT 24H). INT 23H. А д р е с п о д п р о г р а м м ы р е а к ц и и н а Ctrl/Break. (см.INT 24H). INT 24H. А д р е с п о д п р о г р а м м ы р е а к ц и и н а ф а т а л ь н у ю о ш и б к у. В этом элементе и в двух предыдущих содержатся адреса, которые инициализируются системой в префиксе программного сегмента и, которые можно изменить для своих целей. Подробности приведены в техническом описании DOS. INT 25H. А б с о л ю т н о е ч т е н и е с д и с к а. См.гл.17. INT 26H. А б с о л ю т н а я з а п и с ь н а д и с к. См.гл.17. INT 27H.З а в е р ш е н и е п р о г р а м м ы, о с т а в л я ю щ е е е е р е з е д е н т н о й. Позволяет сохранить COM-программу в памяти. Подробно данная операция рассмотрена в последующем разделе "Резидентные программы". ФУНКЦИИ ПРЕРЫВАНИЯ DOS INT 21H ________________________________________________________________ Ниже приведены базовые функции для прерывания DOS INT 21H. Код функции устанавливается в регистре AH: 00 Завершение программы (аналогично INT 20H). 01 Ввод символа с клавиатуры с эхом на экран. 02 Вывод символа на экран. 03 Ввод символа из асинхронного коммуникационного канала. 04 Вывод символа на асинхронный коммуникационный канал. 05 Вывод символа на печать (гл.19). 06 Прямой ввод с клавиатуры и вывод на экран. 07 Ввод с клавиатуры без эха и без проверки Ctrl/Break. 08 Ввод с клавиатуры без эха с проверкой Ctrl/Break. 09 Вывод строки символов на экран (гл.8). 0А Ввод с клавиатуры с буферизацией (гл.8). 0В Проверка наличия ввода с клавиатуры. 0С Очистка буфера ввода с клавиатуры и запрос на ввод. 0D Сброс диска (гл.16). 0Е Установка текущего дисковода (гл.16). 0F Открытие файла через FCB (гл.16). 10 Закрытие файла через FCB (гл.16). 11 Начальный поиск файла по шаблону (гл.16). 12 Поиск следующего файла по шаблону (гл.16). 13 Удаление файла с диска (гл.16). 14 Последовательное чтение файла (гл.16). 15 Последовательная запись файла (гл.16). 16 Создание файла (гл.16). 17 Переименование файла (гл.16). 18 Внутренняя операция DOS. 19 Определение текущего дисковода (гл.16). 1А Установка области передачи данных (DTA). 1В Получение таблицы FAT для текущего дисковода. 1С Получение FAT для любого дисковода. 21 Чтение с диска с прямым доступом (гл.16). 22 Запись на диск с прямым доступом (гл.16). 23 Определение размера файла. 24 Установка номера записи для прямого доступа. 25 Установка вектора прерывания. 26 Создание программного сегмента. 27 Чтение блока записей с прямым доступом (гл.16). 28 Запись блока с прямым доступом (гл.16). 29 Преобразование имени файла во внутренние параметры. 2А Получение даты (CX-год,DН-месяц,DL-день). 2В Установка даты. 2С Получение времени (CH-час,CL-мин,DН-с,DL-1/100с). 2D Установка времени. 2Е Установка/отмена верификации записи на диск. Следующие расширенные функции возможны в DOS начиная с версии 2.0: 2F Получение адреса DTA в регистровой паре ES:BX. 30 Получение номера версии DOS в регистре АХ. 31 Завершение программы, после которого она остается резидентной в памяти. 33 Проверка Ctrl/Break. 35 Получение вектора прерывания (адреса подпрограммы). 36 Получение размера свободного пространства на диске. 38 Получение государственно зависимых форматов. 39 Создание подкаталога (команда MKDIR). ЗА Удаление подкаталога (команда RMDIR). 3В Установка текущего каталога (команда CHDIR). 3C Создание файла без использования FCB (гл.17). 3D Открытие файла без использования FCB (гл.17). 3E Закрытие файла без использования FCB (гл.17). 3F Чтение из файла или ввод с устройства (гл.8,17,19). 40 Запись в файл или вывод на устройство (гл.8,17,19). 41 Удаление файла из каталога (гл.17). 42 Установка позиции для последовательного доступа (гл.17). 43 Изменение атрибутов файла (гл.17). 44 Управление вводом-выводом для различных устройств. 45 Дублирование файлового номера. 46 "Склеивание" дублированных файловых номеров. 47 Получение текущего каталога (гл.17). 48 Выделение памяти из свободного пространства. 49 Освобождений выделенной памяти. 4А Изменение длины блока выделенной памяти. 4В Загрузка/выполнение программы (подпроцесса). 4С Завершение подпроцесса с возвратом управления. 4D Получение кода завершения подпроцесса. 4Е Начальный поиск файла по шаблону (гл.17). 4F Поиск следующего файла по шаблону (гл.17). 54 Получение состояния верификации. 56 Переименование файла (гл.17). 57 Получение/установка даты и времени изменения файла. Следующие расширенные функции возможны в DOS начиная с версии 3.0: 59 Получение расширенного кода ошибки. 5А Создание временного файла. 5В Создание нового файла. 5С Блокирование/разблокирование доступа к файлу. 62 Получение адреса префикса программного сегмента (PSP). В техническом руководстве по DOS представлены подробные описания каждой функции. РЕЗИДЕНТНЫЕ ПРОГРАММЫ ________________________________________________________________ Существует ряд распространенных фирменных программ (Prokey, Superkey, Homebase, Sidekick и др.), специально разработанных как резидентные, которые находятся в памяти во время работы других программ. Эти программы можно активизировать нажатием определенных клавиш. Такие программы называются резидентными, и они загружаются в память сразу после загрузки DOS перед выполнением обычных программ. Для того, чтобы оставить резидентную COM-программу в памяти, необходимо вместо команды RET или INT 20H для выхода использовать команду INT 27H или функцию DOS 31Н. Для INT 27Н следует передать системе в регистре DX размер программы: MOV DX,prog-size INT 27H При выполнении программы инициализации DOS резервирует (выделяет) в старших доступных адресах блок памяти и загружает в него резидентную программу. Это наиболее простая часть создания резидентной программы. Более сложная часть включает программирование механизма активизации резидентной программы, которая хотя и присоединена к DOS, но не является внутренней программой DOS, как DIR, COPY или CLS. Общим подходом является модификация таблицы векторов прерываний таким образом, чтобы резидентная программа, получала управление при нажатии определенных клавиш или их комбинаций, а все остальные передавала через себя. Резидентная программа обычно (но не обязательно) состоит из следующих частей: 1) секции, переопределяющей адреса в таблице векторов прерываний; 2) процедуры, выполняющейся только один раз при загрузке программы и предназначенной для: - замены адреса в таблице векторов прерываний на собственный адрес; - установки размера части программы, которая должна стать резидентной; - использования прерывания DOS для завершения программы и создания резидентной части по указанному размеру; 3) процедуры, которая остается резидентной и активизируется, например, по вводу с клавиатуры или по сигналам таймера. Процедура инициализации должна создать необходимые условия для того, чтобы обеспечить работу резидентной программы, а затем - высшая жертва! - позволить себе быть стертой в памяти. В результате память будет распределена следующим образом: Таблица векторов прерываний IВМВIO.СОМ и IBMDOS.COM COMMAND.СОМ Резидентная часть программы - остается в памяти Инициализирующая часть программы - перекрывается следующей программой Остальная часть доступной памяти __________________________________________________________________________ TITLE RESIDENT (COM) Резидентная программа для очистки ; экрана и установки цвета при нажатии ; Alt+Left Shift ;---------------------------------------------------------- INTTAB SEGMENT AT 0H ;Таблица векторов прерываний: ORG 9H*4 ; адрес для Int 9H, KBADDR LABEL DWORD ; двойное слово INTTAB ENDS ;---------------------------------------------------------- ROMAREA SEGMENT AT 400H ;Область параметров BIOS: ORG 17H ; адрес флага клавиатуры, KBFLAG DB ? ; состояние Alt + Shift ROMAREA ENDS ;---------------------------------------------------------- CSEG SEGMENT PARA ;Сегмент кода ASSUME CS:CS ORG 100H BEGIN: JMP INITZ ;Выполняется только один раз KBSAVE DD ? ;Для адреса INT 9 BIOS ; Очистка экрана и установка цветов: ; --------------------------------- COLORS PROC NEAR ;Процедура выполняется PUSH AX ; при нажатии Alt+Left Shift PUSH BX PUSH CX ;Сохранить регистры PUSH DX PUSH SI PUSH DI PUSH DS PUSH ES PUSHF CALL KBSAV ;Обработать прерывание ASSUME DS:ROMAREA MOV AX,ROMAREA ;Установить DS для MOV DS,AX ; доступа к состоянию MOV AL,KB AG ; Alt+Left Shift CMP AL,00001010B ;Alt+Left Shift нажаты? JNE EXIT ; нет - выйти MOV AX,0600H ;Функция прокрутки MOV BH,61H ;Установить цвет MOV CX,00 MOV DX,18 FH INT 10H EXIT: POP ES ;Восстановить регистры POP DS POP DI POP SI POP DX POP CX POP BX POP AX IRET ;Вернуться COLORS ENDP ; Подпрограмма инициализации: ; -------------------------- INITZE PROC NEAR ;Выполнять только один раз ASSUME DS:INTTAB PUSH DS ;Обеспечить возврат в DOS MOV AX,INTTAB ;Установить сегмент данных MOV DS,AX CLI ;Запретить прерывания ;Замена адреса обработчика: MOV AX,WORD PTR KBADDR ;Сохранить адрес MOV WORD PTR KBSAVE,AX ; BIOS MOV AX,WORD PTR BADDR+2 MOV WORD PTR KBSAVE+2,AX MOV WORD PTR KBADDR,OFFSET COLORS ;Заменить MOV WORD PTR KBADDR+2,CS ; адрес BIOS STI ;Разрешить прерывания MOV DX,OFFSET INITZE ;Размер программы INT 27H ;Завершить и остаться INITZE ENDP ; резидентом CSEG ENDS END BEGIN __________________________________________________________________________ Рис.23.2 Резидентная программа Пример на рис.23.2 иллюстрирует резидентную программу, которая устанавливает цвет экрана при одновременном нажатии клавиш Alt и Left Shift. Основные моменты, представляющие интерес: Сегмент INTTAB определяет таблицу векторов прерываний, начинающуюся по адресу 0, а точнее - адрес элемента для прерывания 9 (ввод с клавиатуры), названный в программе KBADDR. Имя ROMAREA определяет сегмент, начинающийся по адресу 400Н, и в нем флаговый байт клавиатуры (KBFLAG), который отражает состояние клавиатуры. Бит 3 в этом байте регистрирует нажатие клавиши Alt, а бит 1 - нажатие клавиши Left Shift. Сегмент CSEG начинает сегмент обычной COM-программы. Первая выполняемая команда JMP INITZE обходит резидентную часть и передает управление в процедуру инициализации (INITZE) в конце программы. Эта процедура устанавливает в регистре DS адрес таблицы векторов прерывания (INTTAB) и передает адрес элемента таблицы для INT 9 (KBADDR) в поле KBSAVE в резидентной процедуре. Следующим шагом в таблице в KBADDR утанавливается адрес резидентной процедуры (COLORS) (первое слово) и содержимое регистра CS (второе слово). Таким образом, KBADDR содержит теперь два измененных слова: смещение и значение адреса из регистра CS, которые вместе определяют адрес процедуры COLORS в памяти, куда будут направляться теперь все символы, поступающие с клавиатуры. Затем процедура инициализации заносит в регистр DX размер процедуры COLORS (адрес INITZE на один байт больше, чем адрес конца процедуры COLORS) и прекращает работу, используя INT 27H. Процедура COLORS является резидентной, и она получает управление при нажатии любой клавиши на клавиатуре. Так как это происходит при работе других программ (например, DOS или текстового редактора), то процедура должна сохранить все регистры, которые она использует (а также несколько других на всякий случай). Затем происходит вызов по адресу KBSAVE, т.е. вызов подпрограммы обработки прерывания, после чего процедура проверяет флаг клавиатуры для определения нажатия клавиш Alt и Left Shift. Если эти клавиши были нажаты, то процедура устанавливает необходимые цвета. Завершающие команды включают восстановление всех запомненных вначале регистров (в обратной последовательности) и выход из обработки прерывания по команде IRET. Поскольку приведенная программа носит иллюстративный характер, ее можно модифицировать или расширить для собственных целей. Некоторые фирменные программы, также изменяющие адрес в векторной таблице для прерывания 9, не разрешают конкурентное использование резидентных программ, аналогичных рассмотренной в данной главе. ПОРТЫ ________________________________________________________________ Порт представляет собой устройство, которое соединяет процессор с внешним миром. Через порт процессор получает сигналы с устройств ввода и посылает сигналы на устройство вывода. Теоретически процессор может управлять до 65 536 портами, начиная с нулевого порта. Для управления вводом-выводом непосредственно на уровне порта используются команды IN и OUT: - Команда IN передает данные из входного порта в регистр AL (байт) или в регистр АХ (слово). Формат команды: IN регистр,порт - Команда OUT передает данные в порт из регистра AL (байт) или из регистра АХ (слово). Формат команды: OUT порт,регистр Номер порта можно указывать статически или динамически: 1. Статическое указание порта возможно при непосредственном использовании значения от 0 до 255: Ввод: IN AL.порт# ;Ввод одного байта Вывод: OUT порт#,АХ ;Вывод одного слова 2. Динамическое указание порта устанавливается в регистре DX от 0 до 65535. Этот метод удобен для последовательной обработки нескольких портов. Значение в регистре DX в этом случае увеличивается в цикле на 1. Пример ввода байта из порта 60Н: MOV DX,60H ;Порт 60Н (клавиатура) IN AL,DX ;Ввод байта Ниже приведен список некоторых портов (номера в шестнадцатиричном представлении): 21 Регистры маски прерывании. 40...42 Таймер/счетчик 60 Ввод с клавиатуры 61 Звуковой порт (биты 0 и 1) 201 Управление играми 3B0...3BF Монохромный дисплей и параллельный адаптер печати 3D0...3DF Цветной/графический адаптер 3F0...3F7 Дисковый контроллер Если, например, программа запрашивает ввод с клавиатуры, то она выдает команду прерывания INT 16H. В этом случае система устанавливает связь с BIOS, которая с помощью команды IN вводит байт с порта 60Н. На практике рекомендуется пользоваться прерываниями DOS и BIOS. Однако можно также успешно обойтись без BIOS при работе с портами 21, 40...42, 60 и 201. Листинги BIOS в техническом руководстве по IBM PC содержат различные примеры команд IN и OUT. ГЕНЕРАЦИЯ ЗВУКА ________________________________________________________________ Компьютер имеет возможность генерировать звук посредством встроенного динамика с постоянным магнитом. Можно выбрать один из двух способов управления динамиком или использовать оба в комбинации: 1) использование бита 1 порта 21 Н для активизации микросхемы Intel 8255A-5 (программируемый периферийный интерфейс) (РР1); 2) использование триггера программируемого интервального таймера Intel 8353-5 (PIT). Часовой генератор выдает сигнал с частотой 1,19318 МГц. Таймер PPI управляет триггером 2 через бит 0 порта 61 Н. Программа на рис.23.3 генерирует серию звуковых нот с возрастающей частотой. Значение в поле DURTION формирует продолжительность звучания каждой ноты, а значение в поле TONE определяет частоту звучания. В начале работы программа считывает содержимое порта 61 Н и сохраняет полученное значение. Команда CLI сбрасывает флаг прерываний, обеспечивая равномерное звучание. Интервальный таймер генерирует 18,2 такта в секунду, что (при отсутствии CLI) прерывает выполнение программы и вызывает появление звука. Значение поля TONE определяет частоту звука: большие значения дают низкую частоту, а малые - высокую. После того, как подпрограмма BIOSPKR исполнит очередную ноту, она увеличивает частоту звука посредством сдвига вправо на 1 бит значения в поле TONE (т.е. делит значение поля TONE на 2). Так как уменьшение TONE в данном примере приводит к сокращению продолжительности звучания, то подпрограмма также увеличивает DURTION посредством сдвига его значения на один бит влево, т.е. удваивает это значение. Программа завершается, когда содержимое поля TONE уменьшится до нуля. Начальные значения в полях DURTION и TONE не имеют принципиального значения. Можно поэкспериментировать с другими значениями, а также испытать выполнение без команды CLI. Можно изменить программу для генерации звуков с уменьшающейся частотой, установив для этого в поле TONE значение 01, а в поле DURTION - некоторое большее значение. В каждом цикле при этом необходимо увеличивать значение в поле TONE и уменьшать значение в поле. DURTION. При достижении нуля в DURTION программу можно завершить. Можно использовать любые варианты исполнения последовательности нот, например, для привлечения внимания пользователя. __________________________________________________________________________ TITLE SOUND (COM) Процедура для генерации звука SOUNSG SEGMENT PARA 'Code' ASSUME CS:SOUNG,DS:SOUNG,SS:SOUNG ORG 100H BEGIN: JMP SHORT MAIN ; ------------------------------------------------------- DURTION DW 1000 ;Время звучания TONE DW 256H ;Высота (частота) звука ; ------------------------------------------------------- MAIN PROC NEAR IN AL,61H ;Получить и сохранить PUSH AX ; данные порта CLI ;Запретить прерывания CALL B10SPKR ;Произвести звук POP AX ;Восстановить значение OUT 61H,AL ; порта STI ;Разрешить прерывания RET MAIN ENDP B10SPKR PROC NEAR B20: MOV DX,DURTION ;Установить время звучания B30: AND AL,11111100B ;Очистить биты 0 и 1 OUT 61H,AL ;Передать на динамик MOV CX,TONE ;Установить частоту B40: LOOP B40 ;Задержка времени OR AL,00000010B ;Установить бит 1 OUT 61H,AL ;Передать на динамик MOV CX,TONE ;становить частоту B50: LOOP B50 ;Задержка времени DEC DX ;Уменьшить время звучания JNZ B30 ;Продолжать? SHL DURTION,1 ; нет - увеличить время, SHR TONE,1 ; сократить частоту JNZ B20 ;Нулевая частота? RET ; да - выйти B10SPKR ENDP SOUNSG ENDS END BEGIN __________________________________________________________________________ Рис.23.3 Генерация звука ГЛАВА 24 Справочник по директивам языка Ассемблер __________________________________________________________________________ Ц е л ь: подробно описать операторы и директивы языка Ассемблер. ВВЕДЕНИЕ ________________________________________________________________ Некоторые особенности Ассемблера кажутся на первый взгляд несколько странными. Но после того, как вы ознакомились с простейшими и наиболее общими свойствами Ассемблера, описанными в предыдущих главах, то обнаружите, что описания в этой главе более понятны и являются удобным руководством к программированию. В данной главе представлены операторы атрибутов, операторы, возвращающие значение, директивы данных, а также индексная адресация памяти. ИНДЕКСНАЯ АДРЕСАЦИЯ ПАМЯТИ ________________________________________________________________ При прямой адресации памяти в одном из операндов команды указывается имя определенной переменной, например для переменной COUNTER: ADD CX,COUNTER Во время выполнения программы процессор локализует указанную переменную в памяти путем объединения величины смещения к этой переменной с адресом сегмента данных. При индексной адресации памяти ссылка на операнд определяется через базовый или индексный регистр, константы, переменные смещения и простые переменные. Квадратные скобки, определяющие операнды индексной адресации, действуют как знак плюс (+). Для индексном адресации памяти можно использовать: - базовый регистр BX в виде [BX] вместе с сегментным регистром DS или базовый регистр BP в виде [BP] вместе с сегментным регистром SS. Например, с помощью команды MOV DX,[BX] ;Базовый регистр в регистр DX пересылается элемент, взятый по относительному адресу в регистре BX и абсолютному адресу сегмента в регистре DS; - индексный регистр DI в виде [DI] или индексный регистр SI в виде [SI], оба вместе с сегментным регистром DS. Например, с помощью команды MOV AX,[SI] ;Индексный регистр в регистр AХ пересылается элемент, взятый по относительному адресу в регистре SI и абсолютному адресу сегмента в регистре DS; - [константу], содержащую непосредственный номер или имя в квадратных скобках. Например, с помощью команды MOV [BX+SI+4],AX ;База+индекс+константа содержимое регистра АХ пересылается по адресу, который вычисляется, как сумма абсолютного адреса в регистре DS, относительного адреса в регистре BX, относительного адреса в регистре SI и константы 4; - смещение (+ или -) совместно с индексным операндом. Существует небольшое различие при использовании константы и смещения. Например, с помощью команды MOV DX,8[DI][4] ;Смещение+индекс+константа в регистр DX пересылается элемент, взятый по абсолютному адресу в регистре DS, смещению 8, относительному адресу в регистре DI и константе 4. Эти операнды можно комбинировать в любой последовательности. Но нельзя использовать одновременно два базовых регистра [BX + BP] или два индексных регистра [DI + SI]. Обычно индексированные адреса используются для локализации элементов данных в таблицах. ОПЕРАТОРЫ ЯЗЫКА АССЕМБЛЕР ________________________________________________________________ Существует три типа ассемблерных операторов: операторы атрибута, операторы, возвращающие значение, и операторы. специфицирующие битовую строку. В данном разделе рассмотрены первые два типа операторов. Операторы, специфицирующие битовую строку, оператор MASK, счетчик сдвига и оператор WIDTH относятся к директиве RECORD и будет рассмотрены в следующем разделе. Оператор LENGTH ----------------- Оператор LENGTH возвращает число элементов, определенных операндом DUP. Например, следующая команда MOV заносит в регистр DX значение 10: TABLEA DW 10 DUP(?) ... MOV DX,LENGTH TABLEA Если операнд DUP отсутствует, то оператор LENGTH возвращает значение 01. См. операторы SIZE и TYPE в этом разделе. Оператор OFFSET ------------------ Оператор OFFSET возвращает относительный адрес переменной или метки внутри сегмента данных или кода. Оператор имеет следующий формат: OFFSET переменная или метка Например, команда MOV DX,OFFSET TABLEA устанавливает в регистре DX относительный адрес (смещение) поля TABLEA в сегменте данных. (Заметим, что команда LEA выполняет аналогичное действие, но без использования оператора OFFSET.) Оператор PTR --------------- Оператор PTR используется совместно с атрибутами типа BYTE, WORD или DWORD для локальной отмены определенных типов (DB, DW или DD) или с атрибутами NEAR или FAR для отмены значения дистанции по умолчанию. Формат оператора следующий: тип PTR выражение В поле "тип" указывается новый атрибут, например BYTE. Выражение имеет ссылку на переменную или константу. Приведем несколько примеров оператора PTR: FLDB DB 22H DB 35H FLDW DW 2672H ;0бьектный код 7226 MOV AН,BYTE PTR FLDW ;Пересылает 1-й байт (72) ADD BL,BYTE PTR FLDW+1 ;Прибавляет 2-й байт (26) MOV BYTE PTR FLDW,05 ;Пересылает 05 в 1-й байт MOV AX,WORD PTR FLDB ;3аносит в АХ байты (2235) CALL FAR PTR[BX] ;Длинный вызов процедуры Директива LABEL, описанная в следующем разделе, выполняет функцию, аналогичную оператору PTR. Оператор SEG -------------- Оператор SEG возвращает адрес сегмента, в котором расположена указанная переменная или метка. Наиболее подходящим является использование этого оператора в программах, состоящих из нескольких отдельно ассемблируемых сегментов. Формат оператора: SEG переменная или метка Примеры применения оператора SEG в командах MOV: MOV DX,SEG FLOW ;Адрес сегмента данных MOV DX,SEG A20 ;Адрес сегмента кода Оператор SHORT ---------------- Назначение оператора SHORT - модификация атрибута NEAR в команде JMP, если переход не превышает границы +127 и -128 байт: JMP SHORT метка В результате ассемблер сокращает машинный код операнда от двух до одного байта. Эта возможность оказывается полезной для коротких переходов вперед, так как в этом случае ассемблер не может сам определить расстояние до адреса перехода и резервирует два байта при отсутствии оператора SHORT. Оператор SIZE --------------- Оператор SIZE возвращает произведение длины LENGTH и типа TYPE и полезен только при ссылках на переменную с операндом DUP. Формат оператора: SIZE переменная См. пример для оператора TYPE. Оператор TYPE --------------- Оператор TYPE возвращает число байтов, соответствующее определению указанной переменной: Определение Число байтов DB 1 DW 2 DD 4 DQ 8 DT 10 STRUC Число байтов, определённых в STRUC NEAR метка FFFF FAR метка FFFE Формат оператора TYPE: TYPE переменная или метка Ниже приведены примеры, иллюстрирующие применение операторов TYPE, LENGTH и SIZE: FLDB DB ? TABLEA DW 20 DUP(?) ;Определение 20 слов ... MOV AX,TYPE FLDB ;AX = 0001 MOV AX,TYPE TABLEA ;AX = 0002 MOV CX,LENGTH TABLEA ;CX = 000A (10) MOV DX,SIZE TABLEA ;DX = 0014 (20) Так как область TABLEA определена как DW, то оператор TYPE возвращает 0002Н, LENGTH - 000АН (соответственно операнду DUP) и SIZE - произведение типа и длины, т.е. 14Н (20). ДИРЕКТИВЫ АССЕМБЛЕРА ________________________________________________________________ В данном разделе описано большинство ассемблерных директив. В гл.5 были подробно рассмотрены директивы для определения данных (DB, DW и проч.). Директива ASSUME ------------------ Назначение директивы ASSUME - установить для ассемблера связь между сегментами и сегментными регистрами CS, DS, ES и SS. Формат директивы: ASSUME сегментный_регистр:имя [, ... ] В директиве указываются имена сегментных регистров, групп (GROUP) и выражений SEG. Одна директива ASSUME может назначить до четырех сегментных регистров в любой последовательности, например: ASSUME CS:CODESG,DS:DATASG,SS:STACK,ES:DATASG Для отмены любого ранее назначенного в директиве ASSUME сегментного регистра необходимо использовать ключевое слово NOTHING: ASSUME ES:NOTHING Если, например, регистр DS оказался не назначен или отменен ключевым словом NOTHING, то для ссылки к элементу из сегмента данных в командах используется операнд со ссылкой к регистру DS: MOV AX,DS:[BX] ;Использование индексного адреса MOV AX,DS:FLDW ;Пересылка содержимого поля FLDW Конечно, регистр DS должен содержать правильное значение сегментного адреса. Директива EXTRN ----------------- Назначение директивы EXTRN - информировать ассемблер о переменных и метках, которые определены в других модулях, но имеют ссылки из данного модуля. Формат директивы: EXTRN имя: тип [, ... ] Директива EXTRN подробно рассмотрена в гл.21. Директива GROUP ----------------- Программа может содержать несколько сегментов одного типа (код, данные, стек). Назначение директивы GROUP - собрать однотипные сегменты под одно имя так, чтобы они поместились в один сегмент объемом 64 Кбайт, формат директивы: имя GROUP имя сегмента [, ... ] Следующая директива GROUP объединяет SEG1 и SEG2 в одном ассемблерном модуле: GROUPX GROUP SEG1,SEG2 SEG1 SEGMENT PARA 'CODE' ASSUME CS:GROUPX SEG1 ENDS SEG2 SEGMENT PARA 'CODE' ASSUME CS:GROUPX SEG2 ENDS Директива INCLUDE ------------------- Отдельные фрагменты ассемблерного кода или макрокоманды могут использоваться в различных программах. Для этого такие фрагменты и макрокоманды записываются в отдельные дисковые файлы, доступные для использования из любых программ. Пусть некоторая подпрограмма, преобразующая ASCII-код в двоичное представление, записана на диске С в файле по имени CONVERT.LIB. Для доступа к этому файлу необходимо указать директиву INCLUDE C:CONVERT.LIB причем в том месте исходной программы, где должна быть закодирована подпрограмма преобразования ASCII-кода. В результате ассемблер найдет необходимый файл на диске и вставит его содержимое в исходную программу. (Если файл не будет найден, то ассемблер выдаст соответствующее сообщение об ошибке и директива INCLUDE будет игнорирована.) Для каждой вставленной строки ассемблер выводит в LST-файл в 30-й колонке символ С (исходный текст в LST-файле начинается с 33-й колонки). В гл.20 (Макрокоманды) дан практический пример директивы INCLUDE и дано объяснение, каким образом можно использовать эту директиву только в первом проходе ассемблера. Директива LABEL ----------------- Директива LABEL позволяет переопределять атрибут определенного имени. Формат директивы: имя LABEL тип В качестве типа можно использовать BYTE, WORD или DWORD для переопределения областей данных или имен структур или битовых строк. Директивой LABEL можно переопределить выполнимый код, как NEAR или FAR. Эта директива позволяет, например, определить некоторое поле и как DB, и как DW. Ниже проиллюстрировано использование типов BYTE и WORD: REDEFB LABEL BYTE FIELDW DW 2532H REDEFW LABEL WORD FIELDB DB 25H DB 32H MOV AL,REDEFB ;Пересылка первого байта MOV BX,REDEFW ;Пересылка двух байтов Первая команда MOV пересылает только первый байт поля FIELDW. Вторая команда MOV пересылает два байта, начинающихся по адресу FIELDB. Оператор PTR выполняет аналогичные действия. Директива NAME ---------------- Директива NAME обеспечивает другой способ назначения имени модулю: NAME имя Ассемблер выбирает имя модуля в следующем порядке: 1) если директива NAME присутствует, то ее операнд становится именем модуля; 2) если директива NAME отсутствует, то ассемблер использует первые шесть символов из директивы TITLE; 3) если обе директивы NAME и TITLE отсутствуют, то именем модуля становится имя исходного файла. Выбранное имя передается ассемблером в компоновщик. Директива ORG --------------- Для определения относительной позиции в сегменте данных или кода ассемблер использует адресный счетчик. Рассмотрим сегмент данных со следующими определениями: Смещение Имя Операция Операнд Адресный счетчик 00 FLDA DW 2542H 02 02 FLDB DB 36H 03 03 FLDC DW 212EH 05 05 FLDD DD 00000705H 09 Начальное значение адресного счетчика - 00. Так как поле FLDA занимает два байта, то для получения адреса следующего элемента адресный счетчик увеличивается до значения 02. Поле FLDB занимает один байт, значит значение адресного счетчика увеличивается до значения 03 и т.д.. Для изменения значения адресного счетчика и соответственно адреса следующего определяемого элемента используется директива ORG. Формат директивы: OR6 выражение Выражение может быть абсолютным числом, но не символическим именем, и должно формировать двухбайтовое абсолютное число. Рассмотрим следующие элементы данных, определенные непосредственно после поля FLDD: Смещение Имя Операция Операнд Адресный счетчик ORG 0 00 00 FLDX DB ? 01 01 FLDY DW ? 02 03 FLDZ DB ? 04 ORG $+5 09 Первая директива ORG возвращает адресный счетчик в нулевое значение. Поля FLDX, FLDY и FLDZ определяют те же области памяти, что и поля FLDA, FLDB и FLDC: Смещение: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | | | | FLDA FLDB FLDC FLDD | | | FLDX FLDY FLDZ Операнд, содержащий символ доллара ($), как во второй директиве ORG, имеет текущее значение адресного счетчика. Таким образом, операнд $+5 устанавливает адресный счетчик равным 04 + 5 = 09, что представляет собой то же значение, что и после определения поля FLDD. Метка FLDC указывает на поле длиной в одно слово, находящееся по смещению 03, а метка FLDZ указывает на однобайтовое поле по тому же смещению: MOV AX,FLOC ;Одно слово MOV AL,FLDZ ;Oдин байт Директиву ORG можно использовать для переопределения областей памяти. При этом следует правильно устанавливать адресный счетчик и учитывать все переопределяемые адреса памяти. Кроме того, новые переменные не должны определять константы, так как при этом будут перекрыты константы, определенные ранее. Директиву ORG нельзя использовать внутри определения STRUCT. Директива PROC ---------------- Любая процедура представляет собой совокупность кодов, начинающуюся директивой PROC и завершающуюся директивой ENDP. Обычно эти директивы используются для подпрограмм в кодовом сегменте. Ассемблер допускает переход на процедуру с помощью команды JMP, но обычной практикой является использование команды CALL для вызова процедуры и RET для выхода из процедуры. Процедура, находящаяся в одном сегменте с вызывающей процедурой, имеет тип NEAR: имя-процедуры PROC [NEAR] Если операнд опущен, то ассемблер принимает значение NEAR no умолчанию. Если процедура является внешней по отношению к вызывающему сегменту, то ее вызов может осуществляться только командой CALL, а сама процедура должна быть объявлена как PUBLIC. Более того, если в вызываемой процедуре используется другое значение ASSUME CS, то необходимо кодировать атрибут FAR: PUBLIC имя-процедуры, имя-процедуры PROC FAR При вызове любой процедуры с помощью команды CALL необходимо обеспечить возврат по команде RET. Директива PUBLIC ------------------ Назначение директивы PUBLIC - информировать ассемблер, что на указанные имена имеются ссылки из других ассемблерных модулей. Формат директивы: PUBLIC имя [,...] Директива PUBLIC подробно описана в гл.21. Директива RECORD ------------------ Директива RECORD позволяет определять битовые строки. Одно из назначений этой директивы - определить однобитовые или многобитовые переключатели. Формат директивы: имя RECORD имя-поля:ширина [=выражение] [, ... ] Имя директивы и имена полей могут быть любыми уникальными идентификаторами. После каждого имени поля следует двоеточие (:) и размер поля в битах, которое может быть от 1 до 16 бит: Число определенных битов Принимаемый размер 1...8 8 9...16 16 Любой размер поля до 8 бит представляется восемью битами, а от 9 до 16 бит - представляется шестнадцатью битами, выровненными справа (если необходимо). Рассмотрим следующую директиву RECORD: BITREC RECORD BIT1:3,BIT2:7,BIT3:6 Имя BIT1 определяет первые 3 бит поля BITREC, BIT2 - следующие 7 бит и BIT3 - последние 6 бит. Общее число битов - 16, т.е. одно слово. Можно инициализировать поле BITREC, например, следующим образом: BITREC2 RECORD BIT1:3=101B,BIT2:7=0110110B,BIT3:011010B Предположим, что директива RECORD находится перед сегментом данных. Тогда внутри сегмента данных должен быть другой оператор, который отводит память под данные. Для этого необходимо определить уникальное имя, имя директивы RECORD и операнд, состоящий из угловых скобок (символы меньше и больше): DEFBITS BITREC <> Данное определение генерирует объектный код AD9A. который записывается как 9AAD в сегмент данных. В угловых скобках может находиться значение, переопределяющее BITREC. Программа на рис.24.1 иллюстрирует определение BITREC директивой RECORD, но без начальных значений. В этом случае соответствующий оператор в сегменте данных инициализирует каждое поле операндом в угловых скобках. Дополнительно к директиве RECORD имеются операторы WIDTH, MASK и фактор сдвига. Использование этих операторов позволяет изменять определение директивы RECORD без изменения команд, которые имеют ссылки на директиву RECORD. О п е р а т о р WIDTH. Оператор WIDTH возвращает число битов в директиве RECORD или в одном из ее полей. На рис.24.1 после метки А10 имеется два примера оператора WIDTH. Первая команда MOV загружает в регистр BH число битов во всем поле RECORD BITREC (16 бит); вторая команда MOV загружает в регистр AL число битов в поле BIT2 (7 бит). В обоих случаях ассемблер генерирует для числа битов непосредственный операнд. __________________________________________________________________________ TITLE RECORD (COM) Проверка директивы RECORD 0000 CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG 0100 ORG 100H 0100 EB 02 BEGIN: JMP SHORT MAIN ; ----------------------------------------------------- BITREC RECORD BIT1:3,BIT2:7,BIT3:6 ;Определить запись 0102 9A AD DEFBITS BITREC <101B,0110110B,011010B> ;Инициализировать биты ; ----------------------------------------------------- 0104 MAIN PROC NEAR 0104 A10: ;Ширина: 0104 B7 10 MOV BH,WIDTH BITREC ; записи (16) 0106 B0 07 MOV AL,WIDTH BIT2 ; поля (07) 0108 B10: ;Величина сдвига: 0108 B1 0D MOV CL,BIT1 ; шест.0D 010A B1 06 MOV CL,BIT2 ; 06 010C B1 00 MOV CL,BIT3 ; 00 010E C10: ;Маска: 010E B8 E000 MOV AX,MASK BIT1 ; шест.E000 0111 BB 1FC0 MOV BX,MASK BIT2 ; 1FC0 0114 B9 003F MOV CX,MASK BIT3 ; 003F 0117 D10: ;Выделение BIT2: 0117 A1 0102 R MOV AX,DEFBITS ; получить запись, 011A 25 1FC0 AND AX,MASK BIT2 ; очистить BIT1 и BIT3, 011D B1 06 MOV CL,BIT2 ; получить сдвиг 06, 011F D3 E8 SHR AX,CL ; сдвинуть вправо 0121 E10: ;Выделение BIT1: 0121 A1 0102 R MOV AX,DEFBITS ; получить запись, 0124 B1 0D MOV CL,BIT1 ; получить сдвиг 13, 0126 D3 E8 SHR AX,CL ; сдвинуть вправо 0128 C3 RET 0129 MAIN ENDP 0129 CODESG ENDS END BEGIN _____________________________________________________________________ Structures and records: N a m e Widht # fields Shift Widht Mask Initial BITREC . . . . . . . . . . . 0010 0003 BIT1 . . . . . . . . . . . . 000D 0003 E000 0000 BIT2 . . . . . . . . . . . . . 0006 0007 1FC0 0000 BIT3 . . . . . . . . . . . . 0000 0006 003F 0000 Segments and Groups: N a m e Size Align Combine Class CODESG . . . . . . . . . . . . 0129 PARA NONE 'CODE' Symbols: N a m e Type Value Attr A10. . . . . . . . . . . . . . L NEAR 0104 CODESG B10. . . . . . . . . . . . . . L NEAR 0108 CODESG BEGIN. . . . . . . . . . . . . L NEAR 0100 CODESG C10. . . . . . . . . . . . . . L NEAR 010E CODESG D10. . . . . . . . . . . . . . L NEAR 0117 CODESG DEFBITS. . . . . . . . . . . . L WORD 0102 CODESG E10. . . . . . . . . . . . . . L NEAR 0121 CODESG MAIN . . . . . . . . . . . . . N PROC 0104 CODESG Length =0025 __________________________________________________________________________ Рис.24.1. Использование диpективы RECORD Ф а к т о р с д в и г а. Прямая ссылка на элемент в RECORD,например: MOV CL,BIT2 в действительности не имеет отношения к содержимому BIT2. Вместо этого ассемблер генерирует непосредственный операнд, который содержит "фактор сдвига", помогающий изолировать необходимое поле. Непосредственное значение представляет собой число, на которое необходимо сдвинуть BIT2 для выравнивания справа. На рис.24.1 после метки В10 имеются три команды, которые загружают в регистр CL фактор сдвига для полей BIT1, BIT2 и BITЗ. О п е р а т о р MASK. Оператор MASK возвращает "маску" из единичных битовых значений, которые представляют специфицированное поле, иными словами, определяют битовые позиции, которые занимает поле. Например, оператор MASK для каждого из полей, определенных в области BITREC, возвращает следующие значения: Поле Двоичное значение Шестнадцатиричное значение В1Т1 1110000000000000 Е000 В1Т2 0001111111000000 1FC0 В1ТЗ 0000000000111111 003F На рис.24.1 три команды после метки С10 загружают в регистры значения оператора MASK для полей BIT1, BIT2 и BITЗ. Команды после меток D10 и Е10 иллюстрируют выделение значений полей BIТ2 и BIТ1 соответственно из области BITREC. После метки D10 в регистр АХ загружается все значение области, определенной директивой RECORD, а затем из этого значения с помощью оператора MASK выделяются только биты поля BIТ2: Область RECORD: 101 0110110 011010 AND MASK BIТ2: 000 1111111 000000 Результат: 000 0110110 000000 В результате сбрасываются все биты, кроме принадлежащих к полю BIТ2. Следующие две команды приводят к сдвигу содержимого регистра АХ на шесть битов для выравнивания справа: 0000000000110110 (0036Н) После метки Е10 в регистр AХ загружается все значение области, определенной директивой RECORD, и так как BIТ1 является самым левым полем, то в примере используется только фактор для сдвига значения вправо на 13 бит: 0000000000000101 (0005Н) Директива SEGMENT ------------------- Ассемблерный модуль может состоять из одного или более сегментов, части сегмента или даже частей нескольких сегментов. Формат директивы: имя_сегмента SEGMENT [выравнивание] [объединение] [класс] . . . имя_сегмента ENDS Все операнды являются необязательными. Ниже описаны операнды для выравнивания, объединения и указания класса. В ы р а в н и в а н и е. Операнд выравнивания определяет начальную границу сегмента, например PAGE = xxx00 PARA = хххх0 (граница по умолчанию) WORD = ххххe (четная граница) BYTE = ххххх где х - любая шестнадцатиричная цифра, е - четная шестнадцатиричная цифра. О б ъ е д и н е н и е. Операнд объединения указывает способ обработки сегмента, при компоновке: NONE: Значение по умолчанию. Сегмент должен быть логически отделен от других сегментов, хотя физически он может быть смежным. Предполагается, что сегмент имеет собственный базовый адрес; PUBLIC: Все PUBLIC - сегменты, имеющие одинаковое имя и класс, загружаются компоновщиком в смежные области. Все такие сегменты имеют один общий базовый адрес; STACK: Для компоновщика операнд STACK аналогичен операнду PUBLIC. В любой компонуемой программе должен быть определен по крайней мере один сегмент STACK. Если объявлено более одного стека, то стековый указатель (SP) устанавливается на начало первого стека; COMMON: Для сегментов COMMON с одинаковыми именами и классами компоновщик устанавливает один общий базовый адрес. При выполнении происходит наложение второго сегмента на первый. Размер общей области определяется самым длинным сегментом; AT-параграф: Параграф должен быть определен предварительно. Данный операнд обеспечивает определение меток и переменных по фиксированным адресам в фиксированных областях памяти, таких, как ROM или таблица векторов прерываний в младших адресах памяти. Например, для определения адреса дисплейного видеобуфера используется VIDEO_RAM SEGMENT AT 0B800H Класс: Операнд класс может содержать любое правильное имя, заключенное в одиночные кавычки. Данный операнд используется компоновщиком для обработки сегментов, имеющих одинаковые имена и классы. Типичными примерами являются классы 'STACK' и 'CODE'. Следующие два сегмента объединяются компоновщиком в один физический сегмент при одном значении сегментного регистра: -------------------------------- Ассемблерный SEG1 SEGMENT PARA PUBLIC 'CODE' модуль 1 ASSUME CS:SEG1 ... SEG1 ENDS -------------------------------- Ассемблерный SEG2 SEGMENT PARA PUBLIC 'CODE' модуль 2 ASSUME CS:SEG1 ... SEG2 ENDS -------------------------------- Сегменты могут быть вложенными один в другой: SEG1 SEGMENT ... Начало SEG1 SEG2 SEGMENT ... Область SEG2 SEG2 ENDS ... Конец SEG1 SEG1 ENDS Для объединения сегментов в группы используйте директиву GROUP. Директива STRUC ----------------- Директива STRUC обеспечивает определение различных полей в виде структуры. Данная директива не поддерживается в малом ассемблере ASM. Формат директивы: Имя-структуры STRUC ... [определение полей данных] ... Имя-структуры ENDS Структура начинается собственным именем в директиве STRUC и завершается таким же именем в директиве ENDS. Ассемблер записывает поля; определенные в структуре, одно за другим от начала структуры. Правильными операторами определения полей являются DB, DW, DD и DT с указанием имен или без них. На рис.24.2 директива STRUC определяет список параметров PARLIST для ввода имени с клавиатуры. Следующий далее оператор выделяет память под данную структуру: PARAMS PARLIST <> Данный оператор обеспечивает адресацию структуры внутри программы. Угловые скобки (символы меньше и больше) в данном случае пусты, но в них можно указать данные для переопределения областей внутри структуры. В командах ассемблера может использоваться прямая адресация по имени структуры. Для ссылки на определенное поле внутри структуры в командах используется имя структуры (PARAMS в данном примере) и через точку имя конкретного поля: MOV AL,PARAMS.ACTLEN Используя оператор выделения памяти, можно переопределить содержимое полей внутри структуры. Правила для практического использования этой возможности можно найти в руководстве по Ассемблеру. __________________________________________________________________________ TITLE DSTRUC (COM) Определение структуры 0000 CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG 0100 ORG 100H 0100 EB 29 BEGIN: JMP SHORT MAIN ; --------------------------------------------- PARLIST STRUC ;Список параметров 0000 19 MAXLEN DB 25 ; 0001 ?? ACTLEN DB ? ; 0002 19 [ 20 ] NAMEIN DB 25 DUP(' ') ; 001B PARLIST ENDS ; 0102 19 PARAMS PARLIST <> ;Область структуры 0103 ?? 0104 19 [ 20 ] 011D 57 68 61 74 20 69 PROMPT DB 'What is name?', 'S' 73 20 6E 61 6D 65 3F 24 ; --------------------------------------------- 012B MAIN PROC NEAR 012B B4 09 MOV AH,09 ;Выдать запрос 012D 8D 16 011D R LEA DX,PROMPT 0131 CD 21 INT 21H 0133 B4 0A MOV AH,0AH ;Получить ввод 0135 8D 16 0102 R LEA DX,PARAMS 0139 CD 21 INT 21H 013B A0 0103 R MOV AL,PARAMS.ACTLEN ;Длина ввода ; ... 013E C3 RET 013F MAIN ENDP 013F CODESG ENDS END BEGIN Structures and records: N a m e Width # fields Shift Width Masc Initial PARLIST. . . . . . . . . . . . . 001B 0003 MAXLEN . . . . . . . . . . . . 0000 ACTLEN . . . . . . . . . . . . 0001 NAMEIN . . . . . . . . . . . . 0002 Segments and Groups: N a m e Size Align Combine Class CODESG . . . . . . . . . . . . . 013F PARA NONE 'CODE' Symbols: N a m e Type Value Attr BEGIN. . . . . . . . . . . . . L NEAR 0100 CODESG MAIN . . . . . . . . . . . . . N PROC 012B CODESG Length =0014 PARAMS . . . . . . . . . . . . L 001B 0102 CODESG PROMPT . . . . . . . . . . . . L BYTE 011D CODESG __________________________________________________________________________ Рис.24.2. Пpимеp опpеделения стpуктуpы ГЛАВА 25 Справочник по командам языка Ассемблер __________________________________________________________________________ Ц е л ь: описать набор команд Ассемблера и объяснить их машинные коды. ВВЕДЕНИЕ ________________________________________________________________ В данной главе приведены объяснения машинных кодов и перечислены в алфавитном порядке символические коды команд с указанием их назначений. Многие специфические команды имеют однобайтовые машинные коды, например: Объектный код: Символические команды: 40 INC AX ;Увеличение AX на 1 50 PUSH AX ;Запись AХ в стек С3 RET (short) ;Короткий возврат из процедуры CB RET (far) ;Длинный возврат из процедуры FD STD ;Остановка флага направления Ни одна из перечисленных команд не использует прямой адресации памяти. Другие команды, использующие непосредственный операнд, 8-битовый регистр, регистровую пару или адрес памяти, требуют более сложного машинного кода. ОБОЗНАЧЕНИЕ РЕГИСТРОВ ________________________________________________________________ Команды, использующие регистр, могут содержать три бита, указывающих на конкретный регистр, и один бит "w", определяющий размер регистра: байт или слово. Кроме того, лишь некоторые команды обеспечивают доступ к сегментным регистрам. На рис.25.1 показана полная идентификация регистров. Рассмотрим команду MOV с однобайтовым непосредственным операндом: MOV АН,00 10110 100 00000000 | | w rеg = AН __________________________________________________________________________ Основные, базовые и индексные регистры: Биты: w = 0 w = 1 000 AL AX 001 CL CX 010 DL DX 011 BL BX 100 AH SP 101 CH BP 110 DH SI 111 BH DI Биты: Сегментный регистр: 00 ES 01 CS 10 SS 11 DS __________________________________________________________________________ Рис.25.1. Обозначение регистров В данном случае первый байт машинного кода указывает на однобайтовый размер (w = 0) и на регистр AН (100). Следующая команда MOV содержит непосредственный двухбайтовый операнд: MOV AX,00 10111 000 00000000 00000000 | | w reg = AX Первый байт машинного кода указывает на размер в одно слово (w=1) и на регистр AХ (000). Не следует обобщать приведенные примеры, так как указание регистра и бита w может быть в различных позициях кода. БАЙТ СПОСОБА АДРЕСАЦИИ ________________________________________________________________ Байт способа адресации, если он присутствует, занимает второй байт машинного кода и состоит из следующих трех элементов: 1) mod - двухбитового кода, имеющего значения 11 для ссылки на регистр и 00, 01 и 10 для ссылки на память; 2) reg - трехбитового указателя регистра; 3) r/m - трехбитового указателя регистра или памяти (r - регистр, m - адрес памяти). Кроме того, первый байт машинного кода может содержать бит "а", который указывает направление потока между операндом 1 и операндом 2. Рассмотрим пример сложения содержимого регистра АХ с содержимым регистра BX: ADD BX,AX 00000011 11 011 000 dw mod reg r/m В этом примере d=1 означает, что mod (11) и reg (011) описывают операнд 1, а r/m (000) описывает операнд 2. Так как бит w=1, то размер равен одному слову. Таким образом, команда должна прибавить AX (OOQ) к BХ (011). Второй байт команды в объектном коде указывает большинство способов адресации памяти. В следующем разделе способы адресации будут подробно рассмотрены. Биты MOD ---------- Два бита mod определяют адресацию регистра или памяти. Ниже поясняется их назначение: 00 биты г/m дают абсолютный адрес, байт смещения (относительный адрес) отсутствует; 01 биты г/m дают абсолютный адрес памяти и имеется один байт смещения; 10 биты г/m дают абсолютный адрес и имеется два байта смещения; 11 биты г/m определяют регистр. Бит w (в байте кода операции) определяет ссылку на восьми- или шестнадцатибитовый регистр. Биты REG ---------- Три бита reg (вместе с битом w) определяют конкретный восьми- или шестнадцатибитовый регистр. Биты R/M ---------- Три бита г/m (регистр/память) совместно с битами mod определяют способ адресации, как показано на рис.25.2. __________________________________________________________________________ r/m mod=00 mod=01 mod=10 mod=1.1 mod=11 w=0 w=1 000 BX+SI BX+SI+disp BX+SI+disp AL AX 001 BX+DI BX+DI+disp BX+DI+disp CL CX 010 BP+SI BP+SI+disp BP+SI+disp DL DX 011 BP+DI BP+DI+disp BP+DI+disp BL BX 100 SI SI+disp SI+disp AH SP 101 DI DI+disp DI+disp CH BP 110 Direct BP+disp BP+disp DH SI 111 BX BX+disp BX+disp BH DI __________________________________________________________________________ Рис.25.2. Биты r/m ДВУХБАЙТОВЫЕ КОМАНДЫ ________________________________________________________________ Рассмотрим пример сложения содержимого регистров BХ и AХ: ADD BX,AX 0000 0011 11 011 000 dw mod reg r/m d 1 означает, что биты reg и w описывают операнд 1 (BХ), а биты mod, r/m и w - Операнд 2 (AХ); w 1 определяет размер регистров в одно слово, mod 11 указывает, что операнд 2 является регистром; reg 011 указывает, что операнд 1 является регистром BХ; r/m 000 указывает, что операнд 2 является регистром AX. Рассмотрим пример умножения регистра AL на регистр BL: MUL BL 11110110 11 100 011 w mod reg r/m Команда MUL предполагает, что регистр AL содержит множимое. Размер регистра равен одному байту (w = 0), mod указывает на регистровую операцию, г/m = 011 указывает на регистр BL. В данном случае reg = 100 не имеет смысла. ТРЕХБАЙТОВЫЕ КОМАНДЫ ________________________________________________________________ Следующая команда MOV генерирует три байте машинного кода: MOV mem,AX 10100001 dddddddd dddddddd Для команды пересылки из регистра AХ или AL необходимо знать, сколько байтов участвует в операции: один или два. В данном примере w = 1 означает слово, следовательно, предполагается 16-битовый регистр AХ. Использование во втором операнде регистра AL приведет к значению бита w = 0. Байты 2 и 3 содержат относительный адрес памяти. Команды, использующие регистры АХ или AL, часто генерируют более эффективный (короткий) машинный код. ЧЕТЫРЕХБАЙТОВЫЕ КОМАНДЫ ________________________________________________________________ Рассмотрим пример умножения регистра AL на значение в памяти. Процессор предполагает, что множимое находится в регистре AL для однобайтового умножения и в регистре AХ для Двухбайтового умножения: MUL mem_byte 11110110 00 100 110 w mod reg r/m Для данной команды reg всегда имеет значение 100, mod = 00 указывает на операцию с памятью, a r/m=110 - на прямой способ адресации. Машинная команда также содержит два следующих байта, определяющих относительный адрес памяти. Рассмотрим еще один пример, иллюстрирующий команду LEA, которая всегда специфицирует двухбайтовый адрес: LEA DX,mem 10001101 00 010 110 LEA mod rеg r/m Reg =010 означает регистр DX. Mod =00 и r/m=110 определяют прямой способ адресации памяти. В следующих двух байтах содержится относительный адрес. КОМАНДЫ В АЛФАВИТНОМ ПОРЯДКЕ ________________________________________________________________ В данном разделе представлен набор команд Ассемблера в алфавитном порядке. Некоторые команды, например сдвиг и циклический сдвиг, для краткости сгруппированы. Ряд специальных команд для процессоров 80186, 80286 и 80386 выходят за рамки данной книги и поэтому в данной главе также отсутствуют. При пояснении команд и способов адресации используются следующие сокращения: addr адрес памяти; addr-high первый байт адреса (старший); addr-low левый (младший) байт. адреса; data непосредственный операнд (8 бит при w=0 и 16 бит при w= 1); data-high правый (старший) байт непосредственного операнда; data-low левый (младший) байт непосредственного операнда; disp смещение (относительный адрес); rеg ссылка на регистр. AAA: Коррекция ASCII-формата для сложения ------------------------------------------- О п е р а ц и я: Корректирует сумму двух ASCII-байтов в регистре AL. Если правые четыре бита регистра AL имеют значение больше 9 или флаг AF установлен в 1, то команда AAA прибавляет к регистру АН единицу и устанавливает флаги AF и CF. Команда всегда очищает четыре левых бита в регистре AL. Ф л а г и: Команда воздействует на флаги AF и CF (флаги OF, PF, SF и ZF не определены). О б ъ е к т н ы й к о д: 00110111 (без операндов). AAD: Коррекция ASCII-формата для деления ------------------------------------------ О п е р а ц и я: Корректирует ASCII-величины для деления. Команда AAD используется перед делением неупакованных десятичных чисел в регистре AХ (удаляет тройки ASCII-кода). Эта команда корректирует делимое в двоичное значение в регистре AL для последующего двоичного деления. Затем умножает содержимое регистра AН на 10. прибавляет результат к содержимому регистра AL и очищает AН. Команда AAD не имеет операндов. Ф л а г и: Команда воздействует на флаги PF, CF, ZF (флаги AF CF и OF не определены). О б ъ е к т н ы й к о д: |11010101|00001010|. AAМ: Коррекция ASCII-формата для умножения -------------------------------------------- О п е р а ц и я: Команда AAM используется для коррекции результата умножения двух неупакованных десятичных чисел. Команда делит содержимое регистра AL на 10, записывает частное в регистр AН, а остаток в регистр AL. Ф л а г и: Команда воздействует на флаги PF, SF и ZF (флаги AF CF и OF не определены). О б ъ е к т н ы й к о д: |11010100|00001010| (без операндов). AAS: Коррекция ASCII-формата для вычитания -------------------------------------------- О п е р а ц и я: Корректирует разность двух ASCII-байтов в регистре AL. Если первые четыре бита имеют значение больше 9 или флаг CF установлен в 1, то команда AAS вычитает 6 из регистра AL и 1 из регистра АН, флаги AF и CF при этом устанавливаются в 1. Команда всегда очищает левые четыре бита в регистре AL. Ф л а г и: Команда воздействует на флаги AF и CF (флаги OF PF SF и ZF не определены). О б ъ е к т н ы й к о д: 00111111 (без операндов). ADC: Сложение с переносом --------------------------- О п е р а ц и я: Обычно используется при сложении многословных величин для учета бита переполнения в последующих фазах операции. Если флаг CF установлен в 1, то команда ADC сначала прибавляет 1 к операнду 1. Команда всегда прибавляет операнд 2 к операнду 1, аналогично команде ADD. Ф л а г и: Команда воздействует на флаги AF, CF, OF, PF, SF и ZF. О б ъ е к т н ы й к о д (три формата): Регистр плюс регистр или память: |000100dw|modregr/m| Регистр АХ (AL) плюс непосредственное значение: |0001010w|-- data--|data, если w=1| Регистр или память плюс непосредственное значение: y100000sw|mod010r/m|--data--|data, если sw=01| ADD: Сложение двоичных чисел ------------------------------ О п е р а ц и я: Прибавляет один байт или одно слово в памяти, регистре или непосредственно к содержимому регистра или прибавляет один байт или слово в регистре или непосредственно к памяти.
Материалы находятся на сайте http://cracklab.narod.ru/asm/