Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
ЗМІСТ
Вступ.....................................................................................................................5
Лабораторна робота №5- Макрозасоби мови Асемблера……………..6
2.5.5 Циклічні макроси (директиви повторення).............................................9
2.5.6 Умовні макроси (умовні директиви)......................................................11
Порядок виконання роботи.....................................................................13
Лабораторна робота №6 - Транслятор з мови Асемблера.................…13
2.6.1 Призначення та основні функції транслятора з мови Асемблер........13
2.6.2 Види трансляторів з мови Асемблера ...................................................14
2.6.3 Запуск на виконання транслятора TASM...............................................14
2.6.9 Обєктні бібліотеки..................................................................................24
Порядок виконання роботи.........................................................…........24
Лабораторна робота №7 Компонувачі...............................................25
2.7.1 Призначення та основні функції компонувача (редактора звязків)...25
2.7.2 Типи компонувачів ..................................................................................26
2.7.3 Запуск компонувача на виконання.........................................................27
2.7.4 Карта завантаження..................................................................................28
2.7.5 Директиви звязку модулів та сегментів................................................29
2.7.6 Приклад розбиття програми на зовнішні процедури.......................31
Порядок виконання роботи.......................................................................34
Лабораторна робота №8 Математичний співпроцесор.......................34
2.8.1 Архітектура математичного співпроцесора…………………………...34
2.8.2 Формати даних співпроцесора 8087.......................................................36
Порядок виконання роботи.....................................................................43
Лабораторна робота №9 Керування дисплеєм……...........................43
2.9.1 Технічні особливості дисплеїв................................................................43
2.9.3 Приклад програми прямого доступу до відеопамяті.........................47
2.9.5 Керування дисплеєм за допомогою функцій BIOS...............................52
2.9.7 Приклади програми для виведення зображення в текстовому режимі з використанням функцій BIOS.......................................................................57
2.9.8 Приклади програми для виведення зображення в графічному режимі з використанням функцій BIOS.......................................................................59
Порядок виконання роботи...................................................................61
Лабораторна робота №10 Робота з файлами…................................61
2.10.1 Класи функцій для роботи з файлами..................................................61
2.10.2 Створення файлів...................................................................................62
2.10.3 Відкриття файла......................................................................................63
2.10.4 Закриття файла........................................................................................64
2.10.5 Читання даних із файла або пристрою..............................................64
2.10.6 Запис даних у файл або на пристрій.....................................................65
2.10.7 Вилучення файла....................................................................................65
2.10.8 Приклад програми роботи з файлом.....................................................66
2.10.9 Методи доступу до файлів.....................................................................67
2.10.10 Алгоритм запису даних у послідовний файл.....................................67
2.10.11 Алгоритм читання даних із послідовного файла……...…...……....68
2.10.12 Операції читання та запису даних у файлах прямого доступу........68
2.10.13 Приклад програми читання даних із послідовного файла………...68
2.10.14 Робота з атрибутами файлів................................................................70
2.10.15 Робота з дисками, каталогами та організація пошуку файлів……..73
2.10.16 Робота з файлами в MS DOS у випадку довгих імен………………77
Порядок виконання роботи..................................................................78
Лабораторна робота №11 Керування пристроєм “миша”.............80
2.11.1 Ініціалізація та визначення поточного стану драйвера
пристрою “миші”.............................................................................. ….80
2.11.2 Визначення типу і форми курсора “миші” у текстовому режимі....81
2.11.3 Визначення типу і форми курсора “миші” у графічному режимі....83
2.11.5 Керування станом курсора “миші”......................................................87
2.11.6 Читання позиції курсора і стану кнопок “миші”.................................87
2.11.8 Приклад програми для керування пристроєм “миша” в
текстовому режимі роботи відеоадаптера..........................................90
Порядок виконання роботи....................................................................91
Література..........................................................................................................92
Вступ
Друга частина лабораторного практикуму орієнтована на продовження практичного вивчення програмування мовою Асемблера для мікропроцесорів фірми Intel.
В першій лабораторній роботі розглядаються макроси в мові Асемблера, які є особливим різновидом підпрограм, що дозволяють скоротити обсяг асемблерних програм.
Опанувавши програмування математичного співпроцесора можна використовувати арифметичні операції зі всіма типами даних, включаючи числа із плаваючою комою. В результаті значно розширюється сфера застосування Асемблера.
Дві лабораторні роботи повязані із програмним керуванням двох важливих периферійних пристроїв: дисплея та “миші”. Вивчивши графіку на Асемблері в текстовому та графічному режимах роботи дисплея можна легко формувати графічні зображення будь-якої складності з максимально можливою швидкодією. Це дасть змогу створювати програми з динамічними зображеннями, які часто використовуються в різноманітних ігрових та навчальних програмах. Використання в таких програмах пристрою “миша” є обовязковим.
Велику користь програмісту надасть також вміння програмувати роботу з файлами в різних режимах.
Практично засвоївши лабораторні роботи, які розглянуті в методичці, можна створювати достатньо складні асемблерні програми на професійному рівні.
Лабораторна робота № 5
Макрозасоби мови Асемблера
Тема: Макрозасоби мови Асемблера. Директиви повторення, умовні директиви. Макробібліотеки.
Теоретичні відомості
Програмування мовою Асемблер з використанням виключно машинних команд являє собою програмування мовою низького рівня, оскільки кожна команда виконує досить елементарні дії.
За допомогою макрозасобів можна ввести в програму свої власні команди (макрокоманди), які за своїми можливостями можуть бути порівняні з командами мов високого рівня. Програма в цьому випадку стає коротшою і зрозумілішою.
Машиноорієнтована мова, в якій використовуються макрозасоби (макровизначення, макрокоманди, макробібліотеки і таке інше), називається макромовою або Макроасемблером.
Припустимо, що ми маємо два фрагменти програми:
Фрагмент 1: MOV AX, A ADD AX, B SUB AX, C |
Фрагмент 2: MOV AX, M ADD AX, N SUB AX, P |
Якщо ввести формальні параметри ARG1, ARG2, ARG3, тоді можна написати одну узагальнену програму:
MOV AX, ARG1
ADD AX, ARG2
SUB AX, ARG3
Така узагальнена програма може бути оформлена у вигляді макровизначення.
Макровизначення це записана за чітко визначеними правилами послідовність машинних команд Асемблера, якій присвоєно імя.
Загальний формат макровизначення:
Імя макровизначення MACRO [Список формальних параметрів]
Тіло макровизначення
ENDM
Для нашого прикладу макровизначення буде мати такий вигляд:
CALC MACRO ARG1, ARG2, ARG3
MOV AX, ARG1
ADD AX, ARG2
SUB AX, ARG3
ENDM
У тому місці програми, де повинна виконуватись послідовність команд, яка розміщена у макровизначенні, записується макрокоманда. Її формат:
Імя макровизначення [Список фактичних параметрів]
Для нашої програми приклади макрокоманд:
CALC A, B, C
CALC M, N, P
Імя макрокоманди повинно збігатись з іменем макровизначення, до якого звертається макрокоманда.
У макрокоманді фактичні параметри записуються у тому самому порядку, в якому перераховані формальні параметри у відповідному макровизначенні.
У середині макровизначення може бути розташоване звернення до іншої макрокоманди, яка в цьому випадку носить назву вкладеної макрокоманди.
Під час трансляції програми макрокоманда заміняється командами з відповідного макровизначення. Цей процес називається макророзширенням.
Наведена нижче програма демонструє використання макросів, які зменшують обсяг програми і надають їй більшої наглядності.
NAME MYPROG
KARETKA MACRO ARG ; Макровизначення для роботи з кареткою
MOV AH, 02h
MOV DL, ARG
INT 21h
ENDM
OUT_NUMB MACRO ; Макровизначення для виведення цифри
MOV AH, 06h
ADD AL, 48
MOV DL, AL
INT 21h
ENDM
OUT_STR MACRO ; Макровизначення для виведення рядка
MOV AH, 09h
INT 21h
ENDM
STACKSG SEGMENT STACK
DB 128 DUP(?) ; резервування памяті для стеку
STACKSG ENDS
DATE_SG SEGMENT
A DB 2
B DB 3
C DB 4
str0 DB "Data: A=2; B=3; C=4.$"
str1 DB "Rezult 1: Y = A+B+C = $"
str2 DB "Rezult 2: Y = A*B-C = $"
DATE_SG ENDS
CODE_SG SEGMENT
ASSUME CS:CODE_SG, DS:DATE_SG, SS:STACKSG
START PROC FAR
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,DATE_SG
MOV DS,AX
CALL MAIN
RET
START ENDP
MAIN PROC
KARETKA 0Ah ; Переведення каретки
MOV DX, OFFSET str0
OUT_STR
KARETKA 0Ah ; Переведення каретки
KARETKA 0Dh ; Повернення каретки
MOV DX, OFFSET str1
OUT_STR
MOV AL, A
MOV BL, B
ADD AL, BL
ADD AL, C
OUT_NUMB
KARETKA 0Ah ; Переведення каретки
KARETKA 0Dh ; Повернення каретки
MOV DX, OFFSET str2
OUT_STR
MOV AL, A
CBW
IMUL B
SUB AL, C
OUT_NUMB
KARETKA 0Ah ; Переведення каретки
RET
MAIN ENDP
CODE_SG ENDS
END START
У наведеній програмі створено три макроси. Макрос OUT_NUMB використовується для виведення на екран однієї цифри, значення якої знаходиться у регістрі АL. Макрос OUT_STR призначений для виведення на екран рядка символів, причому перед викликом цього макросу необхідно занести в регістр DX адресу символьного рядка. Макрос KARETKA використовується для роботи з кареткою (переведення на новий рядок, повернення каретки на початок рядка). У ньому використовується параметр ARG, який дозволяє змінювати призначення цього макроса. Так, якщо значення аргументу дорівнюватиме 0Ah, то відбудеться переведення каретки на новий рядок, 0Dh повернення каретки, 08h переведення на один символ назад, 07h подача звукового сигналу, тощо.
В одній програмі одне й те саме макровизначення може бути використано декілька разів. Якщо макровизначення містить мітку, то при його багаторазовому використанні у відповідних макророзширеннях зявляються оператори з однаковими мітками. З точки зору мови це є синтаксичною помилкою.
Для запобігання дублювання міток вони описуються за допомогою директиви (оператора) LOCAL, наприклад:
LOCAL МЕТ1, МЕТ2
У цьому випадку транслятор замість вказаної мітки записує число, а при кожному зверненні до макровизначення це число збільшується на 1.
2.5.5 Циклічні макроси (директиви повторення)
Директиви повторення вимагають від асемблера повторити блок операторів, що завершується директивою ENDM. Ці директиви не обовязково повинні знаходитись в макровизначенні, але якщо вони там знаходяться, то одна директива ENDM потрібна для завершення блоку, який повторюється, а друга директива ENDM для завершення макровизначення.
Директива REPT приводить до повторення блока операторів (команд або інших директив) до директиви ENDM у відповідності з кількістю повторень, вказаних у виразі
REPT вираз
Наприклад, якщо записати
REPT 3
INC CX
ENDM
то команда INC CX виконається тричі:
INC CX
INC CX
INC CX
За допомогою директиви IRP можна при кожному повторенні використовувати різні параметри:
IRP формальний параметр, <список>.
У списку параметри можуть бути символами, рядками, числовими або арифметичними константами.
Наприклад, якщо макрокомандою
PUSH_REGS <AX, BX, CX, DX>
викликається макровизначення
PUSH_REGS MACRO LIST
IRP REG, <LIST>
PUSH REG
ENDM
ENDM
це означатиме, що виконуються такі команди:
PUSH AX
PUSH BX
PUSH CX
PUSH DX
Як видно з наведеного прикладу, асемблер здійснює стільки проходів тіла макровизначення, скільки вказано елементів у списку. І при кожному такому проході асемблер підставляє замість формального параметра наступний за порядком елемент у списку.
Якщо список параметрів містить символи, тоді можна застосувати директиву повторення IRPC, формат якої такий:
IRPC формальний параметр, рядок символів
Наприклад, якщо записати
IRPC CHAR, ABCD
ADD AX, CHAR&X
ENDM
то виконається така група команд
ADD AX, AX
ADD AX, BX
ADD AX, CX
ADD AX, DX
В даному прикладі використовується символ ”&” (амперсанд), який вказує асемблеру на необхідність конкатенації символів.
2.5.6 Умовні макроси (умовні директиви)
Виконання макровизначення може бути поставлено у залежність від виконання певних умов, що задаються директивою IFxx:
IFxx вираз умови
. . .
ELSE
. . .
ENDIF
Якщо задана умова виконується, то транслюються лише оператори, розташовані до директиви ELSE, у протилежному випадку ті оператори, що записані після директиви ELSE.
У середині умови макровизначення можна використовувати також директиву EXITM, яка достроково завершує виконання макровизначення.
Так cамо, як і директиви повторення, умовні директиви не обовязково повинні знаходитися у макровизначенні.
У таблиці 1 наведено перелік різних умовних директив.
Нижче наведено приклад умовної директиви, яка викликає макровизначення ERROR у випадку, коли опущено деякий параметр m:
IFB <m>
ERROR
EXITM
ENDIF
Як видно з цього прикладу, директива ELSE може бути відсутньою.
Таблиця 1 Умовні директиви
Директива |
Умова виконання директиви |
IF вираз |
Якщо вираз не дорівнює 0 |
IFE вираз |
Якщо вираз дорівнює 0 |
IFDEF імя |
Якщо імя визначено в програмі або обявлено в директиві EXTRN |
IFNDEF імя |
Якщо імя не визначено в програмі або не обявлено в директиві EXTRN |
IFB <arg> |
Якщо arg дорівнює пропуску (аргумент повинен бути взятий у кутові дужки) |
IFNB <arg> |
Якщо arg не дорівнює пропуску (аргумент повинен бути взятий у кутові дужки) |
IFIDN <arg1>, <arg2> |
Якщо рядки arg1 та arg2 збігаються (аргументи повинні бути взяті у кутові дужки) |
IFDIF <arg1>, <arg2> |
Якщо рядки arg1 та arg2 не збігаються (аргументи повинні бути взяті у кутові дужки) |
IF1 (немає виразу) |
Якщо виконується перший прохід транслятора |
IF2 (немає виразу) |
Якщо виконується другий прохід транслятора |
Найбільшої ефективності і зручності у роботі з макросами можна досягти лише при використанні макробібліотек.
За допомогою будь-якого текстового редактора можна створити свою особисту бібліотеку, куди можуть бути розміщені макровизначення.
Якщо файл макробібліотеки має імя MACRO.LIB, то для її підключення на початку програми слід використати таку директиву:
INCLUDE MACRO.LIB
Слід зауважити, що при підключенні макробібліотеки асемблер переписує в програму всі наявні в ній макровизначення, у тому числі і ті, до яких може і не бути звернень у даній програмі. Тому доцільніше мати декілька невеликих макробібліотек і підключати їх при необхідності.
Наприклад, якщо в наведеному вище прикладі вилучити макроси KARETKA, OUT_STR та OUT_NUMB і записати їх в окремий файл з іменем “MyLib.lib”, то в основній програмі замість текстів коду цих макросів слід написати лише одну директиву:
INCLUDE MyLib.lib.
Існує ряд директив, за допомогою яких можна керувати кількістю інформації, яка видається у лістинг програми, а отже, отримати або короткі, або більш детальні лістинги програми.
За допомогою директиви .LALL можна отримати найповнішій лістинг, включаючи макророзширення з коментарями.
Макровизначення може містити декілька коментарів (нагадаємо, що ознакою коментаря є наявність символу “;” на початку рядка), причому деякі з них можуть виводитися у лістингу, а інші не будуть виводитись. Для того, щоб не виводити коментарі в лістингу, необхідно перед таким коментарем записати символи “;;”.
За замовчуванням в асемблері діє директива .XALL, яка виводить у лістинг тільки ті рядки макровизначення, які генерують обєктний код.
За допомогою директиви .SALL можна виключити з лістинга всі макророзширення, тобто отримати найкоротший лістинг.
- вивчити теоретичну частину даної лабораторної роботи;
- для заданого прикладу скласти макровизначення;
- виконати програму з макровизначенням у тексті програми;
- створити власну макробібліотеку і виконати програму з підключенням цієї макробібліотеки;
- отримати лістинг програми і оформити звіт з лабораторної роботи.
Лабораторна робота № 6
Транслятор з мови Асемблера
Тема: Вивчення роботи транслятора з мови Асемблера. Структура лістинга Асемблера. Обєктні бібліотеки.
Теоретичні відомості
Транслятором з мови Асемблер, або, коротше кажучи, асемблером, називається системна програма, яка переводить текст програми з мови Асемблера на машинну мову.
Для зручності розрізнення однойменних назв будемо назву транслятора писати з маленької літери, а назву мови з великої літери.
У загальному випадку програма мовою Асемблер може містити команди мови Асемблер, макрокоманди і директиви мови Асемблер (псевдокоманди). Тому Асемблер мікропроцесорів Intel 80I86 є по суті макромовою, і процес трансляції складається з двох стадій.
На першій стадії всі макрокоманди заміняються командами Асемблера. На другій стадії команди мови Асемблер переводяться в машинні коди, тобто здійснюється власне асемблювання.
На другій стадії в процесі трансляції вхідної програми асемблер виконує два перегляди (надалі проходи) вхідного тексту. Однією з основних причин цього є посилання вперед. Це здійснюється у тому випадку, коли в деякій команді є перехід на мітку, значення (величина зміщення) якої ще не визначено асемблером.
Під час першого проходу асемблер переглядає всю вхідну програму і будує таблицю символічних імен, які використовуються в програмі, тобто таблицю змінних, констант та міток програми і їх відносних адрес (зміщень).
Під час другого проходу, маючи в наявності всю необхідну інформацію, генерується обєктна програма.
2.6.2 Види трансляторів з мови Асемблера
В наш час існує декілька різних трансляторів з мови Асемблера. Найбільш розповсюдженими з них є такі асемблери:
Найбільш повний діапазон можливостей мають асемблери MASM та TASM. Якщо в процесі роботи з прикладними програмами будуть використовуватись інші системні програми фірми Borland, тоді перевагу у цьому випадку слід надати TASM. Відмінною особливістю асемблера Tasm є те, що від генерує налагоджувальну інформацію для програми-налагоджувальника TURBO-DEBUGGER.
В подальшому розглядатиметься функціонування асемблера TASM.
2.6.3 Запуск на виконання транслятора TASM
Перед зверненням до транслятора необхідно створити файл з розширенням “.asm”, в якому буде знаходитись код вхідної програми мовою Асемблер.
В результаті трансляції одного вхідного файла може бути створено до трьох вихідних файлів:
У деяких випадках таблиця перехресних посилань може знаходитись безпосередньо у файлі лістингу.
Отримання необхідних вихідних файлів визначається способом запуску транслятора на виконання. Тому розглянемо формат команди запуску TASM на виконання:
TASM [options] source[,object][,listing][,xref],
де options - опції, що визначають додаткові можливості трансляції,
source - імя вхідного файла,
object - імя обєктного файла,
listing імя файла лістингу,
xref імя файла перехресних посилань.
Нехай, наприклад, файл “PROG.ASM” містить код вхідної програми мовою Асемблер. Тоді найпростіший варіант виклику асемблера буде такий:
TASM PROG
В результаті трансляції буде сформовано тільки один файл - PROG.OBJ.
Якщо ж необхідно отримати також і лістинг програми, то в командному рядку слід набрати команду:
TASM PROG, PROG, PROG
або
TASM PROG , ,
Для отримання всіх трьох вихідних файлів слід використати команду:
TASM PROG, PROG, PROG, PROG
або
TASM PROG , , ,
В результаті будуть створені такі файли: PROG.OBJ, PROG.LST, PROG.XRF. Імена цим файлам можна задати довільно, але початковий файл повинен обовязково мати імя PROG.
Як вже відмічалось у першій частині даного посібника формуванням вказаних вихідних файлів можна керувати також за допомогою опцій команди TASM.
Найчастіше використовуються такі опції транслятора:
TASM /L - отримання обєктного модуля і лістинга;
TASM /L/C - те саме, але лістинг містить також таблицю перехресних посилань;
TASM /L/N - виключення з лістингу таблиці символічних імен;
TASM /ZI - отримання обєктного модуля разом з необхідною довідковою інформацією для налагоджувач TURBO DEBUGGER.
Повний список опцій транслятора можна отримати, якщо у командному рядку набрати тільки команду TASM (без параметрів). Тоді на екран буде виведено довідкову інформацію про опції транслятора
Всі наведені вище команди є правильними у тому випадку, коли всі програмні файли знаходяться у поточному каталозі. У випадку, коли деякі файли знаходяться у інших каталогах, необхідно вказувати повний шлях до них.
Після асемблювання лістинг програми містить таку інформацію:
Мова Асемблер має у своєму арсеналі ряд директив, які дозволяють керувати процесом асемблювання і формування лістингу. Особливість директив у тому, що вони діють лише в процесі асемблювання і не генерують машинних кодів.
Директива LIST передбачає видачу повного лістингу (дії за замовчуванням). Директива XLIST забороняє видачу вхідної та обєктної програм у лістингу.
Директива NAME у форматі
NAME імя_модуля
присвоює “внутрішнє” імя обєктному модулю.
Для того, щоб зверху на кожній сторінці лістингу виводився заголовок (титул) програми, використовується директива TITLE у такому форматі:
TITLE текст.
Перші 6 знаків тексту використовуються як імя модуля, якщо немає директиви NAME. В разі відсутності директив NAME та TITLE імя вхідного файла вважається іменем обєктного модуля.
Директиви CREF та XREF означають відповідно видачу і заборону таблиці перехресних посилань.
Для встановлення ширини та довжини сторінки використовується директива PAGE у такому форматі:
PAGE операнд_1, операнд_2,
де операнд_1 кількість рядків на сторінку (число від 10 до 255), операнд_2 кількість символів у рідку (число від 60 до 132). За замовчуванням в асемблері встановлено PAGE 66, 80.
Основну частину лістинга займають вхідна програма (праворуч) і обєктна програма (ліворуч).
У крайній лівій колонці вказані номери рядків програми.
У наступній колонці міститься значення лічильника адреси в шістнадцятковому форматі для кожного рядка програми. Кожний сегмент програми (стека, даних, коду) починається з відносної адреси 0000. В сегменті даних значення лічильника команд збільшується на кількість числа байтів у відповідності з типом даних (DB 1, DW 2, DD 4). В сегменті коду значення лічильника команд збільшується на число байтів у відповідності з форматом команди. Директиви у програмі не змінюють значення лічильника команд.
Розглянемо більш детально процес трансляції команд Асемблера в машинний код.
Мова Асемблер є по суті майже машинною мовою, оскільки кожна її команда відповідає одній машинній команді, але записаній у символічній формі (у мнемокоді). Тому процес трансляції зводиться до заміни мнемокоду, зручного для людини, на машинний код, зручний для апаратної реалізації.
Для отримання машинного коду будь-якої команди необхідно знати її формат та режим адресації мікропроцесора.
Наприклад, команда
MOV reg1, reg2
використовує регістрову адресацію для обох операндів, тому її формат такий, як показано на рис.1.
7 |
2 |
1 |
0 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|||||
КОП |
d |
w |
mod |
reg1 |
reg2 |
|||||||||||
Рисунок 1 Формат команди для режиму регістрової адресації |
Перший байт команди містить код операції (КОП) і два однобітових поля направлення передачі d (якщо d=1,то в напрямі мікропроцесора, а якщо d=0, то, навпаки, з мікропроцесора) та формат даних w (якщо w=1, то команда оперує словом, а якщо w=0, то байтом).
Другий байт команди (постбайт) вказує на режим адресації mod і коди регістрів reg1 та reg2. Для регістрової адресації поле mod дорівнює 11. Спосіб кодування регістрів мікропроцесора наведений в табл.2.
Таблиця 2 Адресація регістрів
Код (поле reg) |
8-бітові регістри |
16-бітові регістри |
32-бітові регістри |
000 |
AL |
AX |
EAX |
001 |
CL |
CX |
ECX |
010 |
DL |
DX |
EDX |
011 |
BL |
BX |
EBX |
100 |
AH |
SP |
ESP |
101 |
CH |
BP |
EBP |
110 |
DH |
SI |
ESI |
111 |
BH |
DI |
EDI |
Таким чином, команді Асемблера
MOV BX, SI
відповідає такий машинний код:
10001011 11011110
Розглянемо більш загальні випадки, коли один з операндів знаходиться у комірці памяті. Таким випадкам відповідають наступні режими адресації, тобто, методи визначення ефективної (виконавчої) адреси в команді: пряма, індексна, базово-індексна, опосередкована регістрова.
Найбільш загальний формат двооперандної команди для вказаних режимів адресації наведено на рис.2.
Другий байт команди складається з трьох полів:
mod режим адресації;
reg регістр;
r/m регістр/память.
7 |
2 |
1 |
0 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
7 |
0 |
7 |
0 |
|||||||||
КОП |
d |
w |
mod |
reg |
r/m |
disp L |
disp Н |
|||||||||||||||||
Рисунок 2 Загальний формат двооперандної команди |
Якщо mod = 11, це означає, що операнд знаходиться в регістрі, в решті випадків операнд знаходиться в памяті, і тоді поле mod визначає, як використовується (необовязкове) зміщення disp, яке знаходиться в третьому та четвертому байтах команди, а саме:
mod= |
00, disp=0 зміщення відсутнє, |
|
01, disp=disp L команда містить 8-бітне зміщення, яке розширюється зі знаком до 16 бітів |
||
10, disp=disp H, disp L команді містить два байти зміщення |
В тих самих випадках (коли mod ≠ 11) поле r/m визначає, яким чином формується ефективна адреса операнда. Кодування поля r/m наведено в таблиці 3.
Таблиця 3 Формування ефективної адреси памяті
Поле r/m |
Ефективна адреса |
000 |
EA = (BX) + (SI) + disp |
001 |
EA = (BX) + (DI) + disp |
010 |
EA = (BP) + (SI) + disp |
011 |
EA = (BP) + (DI) + disp |
100 |
EA = (SI) + disp |
101 |
EA = (DI) + disp |
110 |
EA = (BP) + disp |
111 |
EA = (BX) + disp |
Наведені правила формування ефективної адреси мають один виняток: якщо mod = 00 та r/m = 110, то EA = disp H, disp L. Тут в команді міститься абсолютна адреса памяті.
Як приклад розглянемо асемблювання команди додавання до регістру ВХ елемента масива MAS:
ADD BX, MAS[SI]
В цій команді використовується індексна адресація, при якій ефективна адреса операнда обчислюється як сума зміщення, що знаходиться в команді, так і вмісту регістрів SI і DI.
При асемблюванні величина зміщення disp визначається транслятором із сегменту даних, де описується масив MAS. Нехай, наприклад, елементи масива MAS задані у форматі слова і починаються з шостого байта від початку сегмента даних. Код операції даної команди додавання становить 000 000.
Таким чином, отримуємо такий машинний код команди, яку ми асемблюємо:
0000 0011 1001 1100 0000 0110 0000 0000
або в шістнадцятковому форматі:
03 9С 06 00.
Існує ряд особливостей асемблювання команд з безпосередньою адресацією. Формат двооперандної команди з безпосередньою адресацією наведено на рис.3.
7 |
2 |
1 |
0 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
7 |
0 |
7 |
0 |
7 |
0 |
7 |
0 |
|||||||||||||
КОП |
s |
w |
Mod |
КОП |
r/m |
disp L |
disp H |
data L |
data H |
|||||||||||||||||||||||
Рисунок 3 Формат двооперандної команди з безпосередньою адресацією |
В таких командах другий операнд знаходиться в самій команді і його адресувати немає потреби, тому поле reg другого байта команди використовується як розширення коду операції. Крім того, тут не потрібний біт d, оскільки результат можна розмістити тільки на місце першого операнда. Але і в цьому форматі необхідно визначити розмір (тип) безпосереднього операнда. Для цієї мети призначені біти s та w.
sw= |
x0, один байт даних data L; |
|
01, два байти (слово) даних data H, data L; |
||
10, один байт даних, який розширюється зі знаком до 16 бітів |
Поля mod та r/m інтерпретуються так само, як і в попередньому форматі.
В Асемблері є також велика кількість інших форматів команд, інформацію про які можна знайти в спеціальній літературі.
Розглянемо для прикладу просту програму мовою Асемблер, яка призначення для знаходження найбільшого елемента масива.
NAME PROG
STACKSG SEGMENT STACK
DB 128 DUP(?) ; резервування памяті для стеку
STACKSG ENDS
DATE SEGMENT
A DB 1,2,33,4,2,0,5,6,7,8,5,-3,9,127,11,12,2,2
DB 9,127,11,12,2,2,13,14,15,16,-10,1
N DB 4
M DB 6
MAX DB 0
BUF DB 32 DUP(0)
mess db "REZULT: $"
DATE ENDS
CODE_SG SEGMENT
ASSUME CS:CODE_SG, DS:DATE_SG, SS:STACKSG
START PROC FAR
PUSH DS
SUB AX, AX
PUSH AX
MOV AX, DATE_SG
MOV DS, AX
CALL MAIN
CALL VYVOD
RET
START ENDP
MAIN PROC
MOV AL, N
CBW
MUL M
MOV CX, AX ; загальна кількість елементів у масиві
SUB AX, AX
MOV SI, 0
MOV AL, A[SI] ; завантажуємо перший елемент масива
M1:
INC SI
CMP A[SI], AL
JGE M2 ; вибір більшого елемента
MOV AL, A[SI]
M2:
LOOP M1
CBW
RET
MAIN ENDP
VYVOD PROC
; тіло процедури для виведення на екран десяткового числа
VYVOD ENDP
CODE_SG ENDS
END START
Побудуємо машинний код для фрагмента програми, яка власне здійснює обчислення найбільшого елементу, тобто процедуру MAIN. Результати нашої роботи для зручності занесемо у табл. 4. Для того, щоб мати адреси даних, що використовуються, наведемо і результати І проходу для сегмента даних.
За обєктною та вхідною програмами розташована таблиця символічних імен.
Перша частина таблиці містить довідкову інформацію про імя файла, куди розміщено вхідну програму, дату та час трансляції і т.д.
У другій частині таблиці символічних імен зібрані дані про використані в програмі символічні імена, для змінних вказується їх тип (BYTE, WORD, DWORD), зміщення та імя сегмента. Якщо в програмі використані зовнішні змінні та глобальні імена, тоді всі вони перераховуються у таблиці символічних імен.
Таблиця 4 Побудова машинного коду фрагменту програми
Команди програми |
І прохід |
ІІ прохід |
Шістнад-цятковий код команди |
|||
. . . DATE SEGMENT A DB 1,2,33,4,2,0 DB 5,6,7,8,5,-3 DB 9,7,11,1,2,2 DB 4,5,6,10,1,0 N DB 4 M DB 6 . . . |
. . . 7 0000 8 0000 9 0006 10 000C 11 0012 12 0018 13 0019 . . . |
|||||
MOV AL, N |
39 0010 |
10100000 |
00000000 |
00011000 |
A0 00 18 |
|
CBW |
40 0013 |
10011000 |
98 |
|||
MUL M |
41 0014 |
11110110 |
00100110 |
00000000 |
00011001 |
F6 26 00 19 |
MOV CX, АX |
42 0018 |
10001011 |
11001000 |
8B C8 |
||
SUB AX, AX |
43 001A |
00101011 |
11000000 |
2B C0 |
||
MOV SI, 0 |
44 001C |
10111110 |
00000000 |
00000000 |
BE 00 00 |
|
MOV AL, A[SI] |
45 001F |
10001010 |
10000100 |
00000000 |
00000000 |
8A 84 00 00 |
M1: |
46 0023 |
|||||
INC SI |
47 0023 |
01000110 |
46 |
|||
CMP A[SI], AL |
48 0024 |
00111000 |
10000100 |
00000000 |
00000000 |
38 84 00 00 |
JGE M2 |
49 0028 |
01111101 |
00000100 |
7D 04 |
||
MOV AL, A[SI] |
50 002A |
10001010 |
10000100 |
00000000 |
00000000 |
8A 84 00 00 |
M2: |
51 002E |
|||||
LOOP M1 |
52 002E |
11100010 |
11110011 |
E2 F3 |
||
CBW |
53 0030 |
10011000 |
98 |
|||
RET . . . |
54 0031 . . . |
11000011 |
C3 |
Для всіх сегментів і груп, що використовуються в програмі, наводяться їх імена, розмір в байтах, типи обєднання та вирівнювання.
Нижче показано таблицю символічних імен для програми, яку ми навели вище.
Symbol Table
Symbol Name Type Value
??DATE Text "16/02/04"
??FILENAME Text "lab4 "
??TIME Text "08:36:34"
??VERSION Number 040A
@CPU Text 0101H
@CURSEG Text CODE_SG
@FILENAME Text LAB4
@WORDSIZE Text 2
A Byte DATE:0000
ADDRMES Dword DATE_SG:0045
BUF Byte DATE:001B
M Byte DATE:0019
M1 Near CODE:0023
M2 Near CODE:002E
MAIN Near CODE_SG:0010
MAX Byte DATE:001A
MESS Byte DATE:003B
MET1 Near CODE_SG:0049
MET2 Near CODE_SG:0055
N Byte DATE_SG:0018
START Far CODE_SG:0000
VYVOD Near CODE_SG:0032
Groups & Segments Bit Size Align Combine Class
CODE_SG 16 0063 Para none
DATE_SG 16 0049 Para none
STACKSG 16 0080 Para Stack
Перехресні посилання використовуються для допомоги при відлагоджуванні програми.
У таблиці перехресних посилань для кожного символічного імені вказуються номери рядків програми, в яких вони зявляються. Якщо за номером рядка знаходиться символ “#”, це означає, що імя було визначено саме в цьому рядку; в противному разі у цьому рядку міститься тільки посилання на вказане імя. Така інформація дозволяє легко визначити всі команди, що використовують дане імя.
Якщо транслятор формує окремий файл перехресних посилань типу .CRF, то для використання цього файла, необхідно перетворити його в текстовий (формат ASCII). Для цього необхідно запустити програму CREF або TCREF. В результаті буде отримано необхідний вихідний файл типу .REF.
2.6.9 Обєктні бібліотеки
При налагоджуванні багатомодульних програм є сенс обєднувати окремі обєктні модулі в одну обєктну бібліотеку. Формат команди запуску обєктної бібліотеки TLIB на виконання має вигляд:
TLIB libname [/c] [/e] commands, listfile
де libname імя бібліотеки;
commands операції з бібліотекою, наприклад:
+ означає додавання модуля в бібліотеку;
- означає вилучення модуля з бібліотеки;
* означає добування модуля з бібліотеки без його вилучення;
/c режим роботи з урахуванням регістра, тобто режим, при якому розрізняються великі і малі літери;
/e створення розширеного словника.
Наприклад, для створення обєктної бібліотеки MYLIB.LIB і поміщення туди обєктних модулів PROG1.obj та PROG2.OBJ необхідно виконати команду:
TLIB MYLIB + PROG1, PROG2
- вивчити теоретичну частину лабораторної роботи;
- для заданого прикладу скласти текст програми мовою Асемблер і виконати трансляцію з отриманням лістинга програми;
- вивчити різні варіанти отримання лістинга програми;
- отримати окремий файл перехресних посилань в коді ASCII.
- оформити звіт по лабораторній роботі.
Лабораторна робота № 7
Компонувачі
Тема: Вивчення роботи компонувача (редактора звязків). Структура карти завантаження. Розбиття програми на Асемблері на зовнішні процедури (модулі).
2.7.1 Призначення та основні функції компонувача
(редактора звязків)
Обєктна програма, яку ми отримуємо після трансляції, не може бути відразу виконана.
По-перше, всі адреси в обєктній програмі є відносними, оскільки в кожному сегменті вони починаються з нульової адреси. У випадку, коли вхідна програма складається з окремих модулів, кожний з яких транслювався окремо, їх обєктні модулі необхідно обєднати в один, виконавши при цьому настроювання всіх адрес.
Таким чином, необхідна спеціальна системна програма, що називається компонувачом, або редактором звязків, для виконання таких функцій:
Результатом роботи компонувача є завантажувальний модуль.
Для того, щоб виконати завантажувальний модуль, його необхідно розмістити в потрібну область оперативної памяті, змінивши попередньо всі відносні адреси на абсолютні, тобто фізичні. Цю останню задачу виконує системна програма завантажувач.
Загальна схема виконання найпростішої одномодульної прикладної програми в компютері наведена на рис.4.
Головною властивістю компонувача є можливість з його допомогою реалізувати принцип модульного програмування. Розробка складних прикладних програм як набору вхідних модулів має певні переваги, а саме:
2.7.2 Типи компонувачів
Існує декілька типів компонувачів. Найбільше розповсюджені з них такі:
Компонувач TLINK серед наведених є найшвидшим, хоча і має ряд обмежень:
Надалі розглядатимемо функціонування компонувачів TLINК та LINK, які за виконуваними функціями близькі один до одного.
2.7.3 Запуск компонувача на виконання
Вхідною інформацією для компонувача є один або декілька обєктних модулів, що містяться у файлах типу “.OBJ”. Обєктні модулі можуть також знаходитись в обєктних бібліотеках.
В результаті компонування може бути отримано два файли:
Кількість вхідних файлів та їх структура визначаються способом запуску компонувача на виконання.
Формат команди запуску компонувача TLINK на виконання має такий вигляд:
TLINK [options] objfiles, mapfiles, libfiles
де options опції, що визначають додаткові можливості компонувача;
objfiles імя обєктного файла;
mapfiles імя файла, що містить карту завантаження;
libfiles імя обєктної бібліотеки.
Нехай, наприклад, обєктний модуль знаходиться у файлі “PROG.OBJ”. Тоді для отримання завантажувального модуля і карти завантаження необхідно виконати команду
TLINK PROG.
В результаті компонування будуть сформовані файли “PROG.EXE” та “PROG.MAP”.
При обєднані декількох обєктних модулів, наприклад, “PROG1.OBJ” та “PROG2.OBJ”, команда запуску TLINK може бути такою:
TLINK PROG1+PROG2, PR, PR
В результаті компонування будуть створені єдиний завантажувальний модуль у файлі “PR.EXE” і обєднана карта завантаження у файлі “PR.MAP”.
Якщо деякі обєктні модулі знаходяться в обєктній бібліотеці “MYLIB.OBJ”, то команда запуску TLINK буде такою:
TLINK PROG1, PR, PR, MYLIB
Якщо в командному рядку набрати тільки TLINK, тоді можна отримати довідкову інформацію про опції компонувача. Опції, що використовуються найчастіше, такі:
TLINK /m PROC видача карти завантаження з таблицею зовнішніх імен;
TLINK /s PROC видача розширеної карти завантаження (по сегментах);
TLINK /x PROC заборона на видачу карти завантаження;
TLINK /t PROC створення завантажувального модуля у файлі типу “.СОМ”;
TLINK /v PROC отримання додаткової довідкової інформації для налагоджувача TURBO DEBUGGER.
2.7.4 Карта завантаження
Карта завантаження (карта звязків), що знаходиться у файлі “.МАР”, містить результат роботи компонувача, тобто являє собою по суті лістинг компонувача.
У цій карті для кожного сегмента вказано його довжину в байтах, а також початкову та кінцеву адреси у тому вигляді, в якому вони будуть завантажені в оперативну память. Всі ці адреси є 20-бітовими і розпочинаються від нульової комірки.
Приклад найпростішої карти завантаження:
START STOP LENGTH NAME
00000H 0007FH 00080H SSTACK
00080H 00085H 00006H DATA
00090H 000B8H 00029H CODE
Оскільки завантаження програми в оперативну память здійснюється операційною системою, то завантажувач змінить значення цих адрес. Але ж відносно один одного їх значення залишаться такими самими.
Зазвичай сегменти розташовуються на границях параграфів для того, щоб адреси зміщення зберігали вірні значення. При цьому між окремими сегментами можуть знаходитись невикористані байти (до 15 байтів), як це видно з попереднього прикладу. Але в Асемблері передбачено засоби, що забезпечують більш щільне розміщення сегментів. За допомогою директиви SEGMENT можна задавати тип вирівнювання на границях слів або байтів.
Наприкінці карти завантаження вказується вхідна точка виконуваного файла. Ця адреса, як і інші, розраховується по відношенню до початку завантажувального модуля і настроюється в памяті завантажувача. Існує декілька способів вказування стартової адреси для завантажувального модуля типу “.ЕХЕ”.
При одному із способів програма виконується, починаючи з першого байта. При цьому необхідно слідкувати за тим. щоб в першому байті першого сегмента виконуваного файла містилася саме та команда, з якої і треба починати виконання.
Переважає спосіб задання вхідної точки в директиві END головного модуля програми:
END START,
де START мітка першої виконуваної команди у програмі.
У випадку, коли в програмі задано більше, ніж одна точка входу, компонувач вибирає ту, яка вказана останньою.
Все це справедливо для завантажувального модуля типу “.ЕХЕ”. Модулі типу “.СОМ” завжди починають виконуватись зі зміщення 100Н сегмента коду.
2.7.5 Директиви звязку модулів та сегментів
При модульному програмуванні виникають специфічні проблеми обєднання окремо відтрансльованих модулів у єдиний завантажувальний модуль.
Головна проблема полягає у тому, що з даного модуля можливі звернення (посилання) до символічних імен (в першу чергу до змінних і міток) в інших модулях, а ці інші модулі можуть звертатись до таких самих імен даного модуля. Саме за допомогою таких модульних звернень окремі модулі обєднуються в єдину програму.
Припустимо, що програма складається з двох модулів MOD1 та MOD2. Нехай у модулі MOD1 визначена зміннаVAR1, а в модулі MOD2 змінна VAR2, причому обидві змінні використовуються в обох модулях.
Для того, щоб використовувати вказані змінні в обох модулях, їх імена повинні бути вказані в директивах EXTRN та PUBLIC.
В директиві EXTRN перераховуються всі імена, до яких є звернення в даному модулі, але які визначені в інших модулях. Такі імена є зовнішніми по відношенню до даного модуля. Дана директива має такий формат:
EXTRN імя: тип [, імя: тип, . . .].
Іменем в директиві EXTRN може бути імя змінної, мітки або константи, визначної директивою EQU. Типом може бути BYTE, WORD або DWORD для змінної, NEAR або FAR для мітки, ABS для константи, причому ABS означає абсолютне число, а не змінну і не мітку.
В директиві PUBLIC перераховуються всі імена, які визначені в даному модулі і є доступними для звернення з інших модулів. Такі імена є глобальними по відношенню до даного модуля. Дана директива має такий формат:
PUBLIC імя [, імя, . . .]
Іменами тут можуть бути такі самі імена, як і в директиві EXTRN.
На перший погляд здається зручним перераховувати в директиві PUBLIC імена всіх змінних, що використовуються у модулі. Але ж це означало би, що в будь-якому модулі, які повинні бути звязані між собою, всі імена мають бути унікальними. Тому доцільно в директиві PUBLIC перераховувати лише ті імена, які необхідні для звязування модулів, тоді решта імен в різних модулях можуть бути однаковими.
Таким чином, для нашого прикладу змінні VAR1 і VAR2 мають бути описані так, як це показано на рис. 5.
Припустимо, що модулі MOD1 і MOD2 містять сегменти стеку, даних та коду. Тоді при обєднанні цих модулів можна отримати шість сегментів. Оскільки сегменти коду і даних в обох модулях адресуються за допомогою одних і тих самих сегментних регістрів (CS, DS), то при кожній передачі управління між модулями необхідно змінювати вміст сегментних регістрів. Крім того, обєднаній програмі потрібен один стек, а отже, одна з областей стеку виявляється непотрібною, а розмір іншої повинен відповідати вимогам до стеку обох модулів.
Якщо обєднаний розмір сегментів коду менший за 64К, то сегменти кодів обох модулів можна обєднати і немає необхідності витрачати час на модифікацію регістра CS. Аналогічним чином можна розвязати проблеми при обєднанні сегментів даних і сегментів стека модулів.
Варіанти обєднання логічних сегментів задаються в директиві SEGMENT, повний формат якої має вигляд:
імя SEGMENT [тип вирівнювання] [тип обєднання] [імя класу]
В полі “тип вирівнювання” вказуються атрибути, що визначають границю, на якій повинен бути розміщений логічний сегмент:
PARA на границі параграфа;
WORD на границі слова;
BYTE на границі байта;
PAGE на границі сторінки.
В полі “тип обєднання” вказуються атрибути, що визначають спосіб обєднання даного логічного сегмента з іншим логічним сегментом, що має таке саме імя: PUBLIC, STACK, COMMON, MEMORY, AT.
Коли логічному сегменту призначається атрибут “імя класу”, то компонувач збирає разом всі області з однаковими іменами класів.
Нижче наведено код програми на Асемблері для обчислення суми елементів вектора.
NAME PROG
SSTACK SEGMENT
DB 128 DUP (?)
SSTACK ENDS
DATA SEGMENT
MAS DW 1,3,1,2,1
N DW 5
Y DW ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:SSTACK
START PROC FAR
PUSH
SUB AX, AX
PUSH AX
MOV AX, DATA
MOV DS, AX
CALL MAIN
CALL OUTPUT
RET
START ENDP
MAIN PROC
SUB AX, AX
MOV CX, 5
LEA SI, MAS
MET: ADD AX, [SI]
ADD SI, 2
LOOP MET
MOV Y,AX
RET
MAIN ENDP
OUTPUT PROC
MOV AX, Y
ADD AL, 48
MOV DL, AL
MOV AH, 06h
INT 21h
RET
OUTPUT ENDP
CODE ENDS
END START
Розібємо цю програму на три процедури: головну процедуру START, процедуру MAIN - для визначення суми, процедуру OUTPUT - для виведення результату обчислень. В процедурі START будуть визначатися всі змінні і здійснюватись виклики решти процедур. Процедура MAIN отримує від процедури START початкові дані для обчислень і повертає їй результат обчислень. Процедура OUTPUT отримує від процедури START значення результату для виведення його на екран дисплея.
З урахуванням вказаних вище умов головна процедура буде мати такий вигляд:
NAME PROG1
EXTRN MAIN:NEAR, OUTPUT:NEAR
PUBLIC MAS, N, Y
SSTACK SEGMENT
DB 128 DUP (?)
SSTACK ENDS
DATA SEGMENT
MAS DW 1,3,1,2,1
N DW 5
Y DW ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:SSTACK
START PROC FAR
PUSH
SUB AX, AX
PUSH AX
MOV AX, DATA
MOV DS, AX
CALL MAIN
CALL OUTPUT
RET
START ENDP
CODE ENDS
END START
Зовнішня процедура MAIN матиме вигляд:
NAME PROG2
EXTRN MAS:WORD, N:WORD, Y:WORD
PUBLIC MAIN
SSTACK SEGMENT
DB 128 DUP (?)
SSTACK ENDS
CODE SEGMENT PUBLIC
ASSUME CS:CODE, SS:SSTACK
MAIN PROC NEAR
SUB AX, AX
MOV CX, 5
LEA SI, MAS
MET: ADD AX, [SI]
ADD SI, 2
LOOP MET
MOV Y,AX
RET
MAIN ENDP
CODE ENDS
END
Зовнішня процедура OUTPUT буде такою:
NAME PROG3
EXTRN Y:WORD
PUBLIC OUTPUT
SSTACK SEGMENT
DB 128 DUP (?)
SSTACK ENDS
CODE SEGMENT PUBLIC
ASSUME CS:CODE, SS:SSTACK
OUTPUT PROC
MOV AX, Y
ADD AL, 48
MOV DL, AL
MOV AH, 06h
INT 21h
RET
OUTPUT ENDP
CODE ENDS
END
Лабораторна робота № 8
Математичний співпроцесор
Тема: Знайомство з архітектурою математичного співпроцесора. Вивчення форматів даних та системи команд для управління математичним співпроцесором. Програмування мовою Асемблер із використанням математичного співпроцесора.
Теоретичні відомості
2.8.1 Архітектура математичного співпроцесора
Математичний співпроцесор (МС) призначений для виконання операцій над числами з фіксованою та плаваючою комою. Завдяки математичному співпроцесору можна досягти високої точності і швидкодії при різноманітних математичних обчисленнях, при роботі з машинною графікою, при виконанні статистичних та інженерних розрахунків, при використанні засобів мультимедіа і т.д.
Математичний співпроцесор може працювати лише разом із головним процесором, оскільки в ньому відсутній механізм вибірки команд.
Перший математичний співпроцесор 8087 працював у перших моделях ІВМ РС. Згодом були розроблені математичні співпроцесори 80287 та 80387. У процесорах Intel 80486 та Pentium наявний вбудований співпроцесор, що є одним з модулів головного процесора, але з програмної точки зору вони залишились повністю сумісними з 80387.
В загальному випадку МС х87 можна розглядати як архітектурне розширення центрального процесора, тобто до загальних регістрів процесора додаються вісім 80-розрядних арифметичних регістри стека і блок регістрів стану та управління.
Блок регістрів стану та управління складається з таких 16-розрядних регістрів:
Група арифметичних регістрів частіше використовується в режимі стеку, тобто операнди зчитуються у порядку, оберненому до порядку запису. Але підтримуються всі форми команд, що виконують запис і зчитування для конкретних регістрів.
З регістрами стеку повязаний 3-бітовий покажчик стеку ST, що визначає регістр, який в даний момент є вершиною стеку (рис.10). Нумерація регістрів завжди починається від вершини стеку.
ST |
79 64 |
63 0 |
||||||
101 |
0 |
(порядок) |
(мантиса) |
ST(3) |
TAG(3) |
|||
(покажчик стеку |
1 |
ST(4) |
TAG(4) |
|||||
2 |
ST(5) |
TAG(5) |
||||||
3 |
ST(6) |
TAG(6) |
||||||
4 |
ST(7) |
TAG(7) |
||||||
5 |
ST(0) |
TAG(0) |
||||||
6 |
ST(1) |
TAG(1) |
||||||
7 |
ST(2) |
TAG(2) |
Рисунок 10 Схема звязку покажчика стеку з регістрами співпроцесора
При завантаженні даних в арифметичний регістр вміст покажчика стеку попередньо зменшується на одиницю (ST ← ST-1) і вказує номер регістра, в який здійснюється завантаження. При добуванні даних з регістру вміст покажчика стеку автоматично збільшується на одиницю (ST ← ST+1).
З кожним з арифметичних регістрів повязаний регістр тегів, в якому є 2-бітове поле, значення якого залежить від вмісту регістра ST(i) (рис.11).
Математичний співпроцесор має у своєму складі:
Код поля TAG(i) |
Вміст регістра ST(i) |
00 |
Скінчене число, що не дорівнює 0 |
01 |
Нуль |
10 |
NAN, ± ∞ |
11 |
Регістр пустий (позначається е) |
Рисунок 11 Значення полів тегів
Математичний співпроцесор Х87 підтримує 7 форматів:
На рис. 12 наведені формати цілих чисел математичного співпроцесора Х87.
Ціле слово (ЦС): |
15 |
0 |
||||
S |
Двійковий код |
- 16 розрядів |
||||
Коротке ціле (КЦ): |
31 |
0 |
||||
S |
Двійковий код |
- 32 розряди |
||||
Довге ціле (ДЦ): |
63 |
0 |
||||
S |
Двійковий код |
- 64 розряди |
Рисунок 12 Формати цілих чисел.
У всіх цих форматах відємні числа записуються у доповняльному коді (якщо s=0, число додатне, якщо s=1, - число відємне).
Формати дійсних чисел
Дійсні числа можуть бути представлені в одному з трьох форматів (рис.13).
Мантиса числа завжди записується в нормалізованому вигляді:
1, m1m2m3…
Порядок дійсного числа завжди записується в зміщеному вигляді, тому реальний порядок дорівнює числу в полі порядку мінус значення зміщення. Це дозволяє спростити порівняння чисел.
Коротке дійсне (КД): |
31 |
23 |
22 0 |
||||
S |
Порядок |
Мантиса |
- 32 розряди |
||||
Довге дійсне (ДД): |
63 |
52 |
51 |
0 |
|||
S |
Порядок |
Мантиса |
- 64 розряди |
||||
Тимчасове дійсне (ТД): |
79 |
64 |
63 |
0 |
|||
S |
Порядок |
Мантиса |
- 80 розрядів |
Рисунок 13 Формати дійсних чисел
Для обчислення реальних значень коротких дійсних чисел використовують таку формулу:
(-1)S · (1, m1m2…m23) · 2E-127 .
Наприклад, нехай задано:
S E m1m2m3m4m5…m23
-----------------------------------------------
1 01111101 1 0 1 1 0 … 0
Обчислюємо реальне значення числа:
(-1)1 · (1,1011)2 · 2125-127 = - (1,6775)10 · 2-2 = - 0,419375.
Число +1.0 представляється у вигляді:
S E m1m2m3m4m5…m23
-----------------------------------------------
0 01111111 0 0 0 0 0 … 0
У форматах короткого та довгого дійсних чисел такі величини, як +∞, -∞ та NAN (Not a Number, тобто не числа) представляються таким чином (рис. 14).
Знак S |
Порядок |
Мантиса |
Значення |
||
0 |
11 ... 11 |
00 ... 00 |
+∞ |
||
1 |
11 ... 11 |
00 ... 00 |
-∞ |
||
0 |
11 ... 11 |
11 ... 11 |
NAN |
тобто, коли в полі мантиси будь-яке ненульове число |
|
1 |
11 ... 11 |
11 ... 01 |
NAN |
||
... |
... |
... |
NAN |
||
0 |
11 ... 11 |
00 ... 11 |
NAN |
||
1 |
11 ... 11 |
00 ... 01 |
NAN |
Рисунок 14 Представлення величин +∞, -∞ та NAN
Формат десяткового числа
Двійково-десяткове число має такий формат:
79 |
72 |
0 |
S |
0000000 |
D17 d16 d15 … d1 d0 |
де d тетрада (4 двійкових розряди).
Повна система команд 8087 включає в себе 6 команд і побудована на основі команди ESC. Використовується 2 формати команди ESC.
а) Формат команди з постбайтом застосовується у тих випадках, коли операнд-джерело знаходиться в памяті або в регістрі ST(i), або коли результат необхідно переслати в память або в регістр ST(i) (рис. 15).
ESC |
|||||||||
11011 |
КОП |
mod |
КОП |
r/m |
Молодший байт |
Старший байт |
|||
Байт адресації |
Зміщення disp |
Рисунок 15 Формат команди з постбайтом
Зміщення disp може дорівнювати:
1 байт ( у цьому випадку mod = 01);
2 байти (у цьому випадку mod = 10);
бути відсутнім (тоді mod = 00 або mod = 11).
У випадку mod=11 операнд розміщується в одному з арифметичних регістрів. Виняток складають випадки, коли mod=11 і r/m=110, - тоді зміщення складає 2 байти і повністю визначає виконувану адресу.
Б) Формат команди без постбайта застосовується у тих випадках, коли операнд розташований в регістрі ST(i) або в командах управління (рис. 16).
ESC |
||||||
11011 |
КОП |
11 |
КОП |
- формат команди управління |
||
ESC |
||||||
11011 |
КОП |
11 |
КОП |
ST(i) |
- формат команди. коли операнд розташований в регістрі ST(i) |
Рисунок 16 Формат команди без постбайта
Команди керування
До команд керування відносяться 15 команд, які використовуються не для обчислень. а для виконання системних функцій. Більшість із цих команд має два варіанти (два мнемокоди). Другий мнемокод утворюється шляхом додавання до мнемокоду букви N, яка вказує, що при асемблюванні даного мнемокоду перед ним не треба розміщувати команду WAIT. Другий мнемокод використовується у програмах, які є критичними за часом виконання. До основних команд керування належать:
команда ініціалізації співпроцесора FINIT або FNINIT;
команда очікування FWAIT;
команда збільшення покажчика стека FINCSTR
(якщо ST=7, то після виконання даної команди ST=0);
команда зменшення покажчика стека FDECSTR
(якщо ST=0, то після виконання команди ST=7).
Команди передавання даних включають 4 типи команд:
До основних команд завантаження належать:
команда завантаження дійсного числа FLD src або FLD ST(0),src
(передача даних здійснюється від джерела src у вершину стека ST(0));
команда завантаження цілого числа FILD src
(число завантажується у вершину стека);
команда завантаження десяткового числа FBLD src
(число завантажується у вершину стека).
До основних команд збереження належать:
команда збереження дійсного числа FST dst або FST ST(i)
(Число завантажується з вершини стеку в память за адресою dst або в інший регістр ST(i));
команда збереження цілого числа FIST dst;
команда збереження дійсного числа з одночасним виштовхуванням зі стека FSTP dst;
команда збереження цілого числа з одночасним виштовхуванням зі стека FISTP dst;
команда збереження десяткового числа з одночасним виштовхуван- ням зі стека FSTP dst.
До команди обміну належить:
команда обміну FXCH dst
(обмінюється вміст регістра-приймача dst з вершиною стека. За замовчуванням (команда FXCH) для обміну з вершиною стека ST(0) береться dst=ST(1).
До основних команд завантаження констант належать:
команда завантаження числа +0.0 FLDZ
(число завантажується у вершину стека);
команда завантаження числа 1.0 FLD1
(число завантажується у вершину стека);
команда завантаження числа π FBLPI
(число завантажується у вершину стека);
команда завантаження числа log210 FLDL2T
(число завантажується у вершину стека).
Арифметичні команди включають 6 типів команд:
До основних арифметичних команд належать:
команда додавання дійсних чисел FADD dst, src
(Як правило, dst=ST(0), src=ST(i) або dst=ST(i), src=ST(0). За замовчуванням (команда FADD) вважається, що dst=ST(0), src=ST(1). Результат операції в ST(0));
команда віднімання дійсних чисел FSUB dst, src;
команда множення дійсних чисел FMUL dst, src;
команда ділення дійсних чисел FDIV dst, src;
Команда порівняння з нулем вершини стека FTST;
команда порівняння дійсних чисел FCOM src
Остання команда виконує віднімання вмісту src від вмісту вершини стека ST(0), формуючи значення прапорців С3 та С0 (рис. 17).
Відношення |
С3 С0 |
ST(0) > (src) |
0 0 |
ST(0) < (src) |
0 1 |
ST(0) = (src) |
1 0 |
ST(0) не може бути порівняно з (src) |
1 1 |
Рисунок 17 значення прапорців С3 та С0
Спеціальні команди для обчислень
До спеціальних команд належать:
команда обчислення кореня квадратного FSQRT;
команда обчислення функції sin FSIN;
команда обчислення функції cos FCOS;
команда обчислення функції arctg FRATAN.
Оскільки введення та виведення даних мовою Асемблер має деякі труднощі, то операції введення з клавіатури та виведення результатів обчислень на екран реалізуємо в програмі мовою Сі, а в неї вбудуємо асемблерний код, в якому власне і проведемо математичні розрахунки.
Приклад 1. Програма для обчислення виразу: result = aּx/b.
#include <stdio.h>
#include <conio.h>
void main()
{
float x,a,b,result,buf;
int cycle; b=3.0; a=4.0;
clrscr();
puts("Input x");
scanf("%f",&x);
_asm{
fld b
fld x
fld a
fld1
fmul st(0),st(1)
fmul st(0),st(2)
fdiv st(0),st(3)
fst result
}
printf("%f\n",result);
getch();
}
Приклад 2. Програма для обчислення значення функції у=ех, використовуючи розклад функції в ряд Тейлора.
#include <stdio.h>
#include <conio.h>
void main()
{
float x,a,y,i,result;
int cycle;
i=0.0; a=1.0; y=1.0;
clrscr();
puts("Input x");
scanf("%f",&x);
puts("Input cycle");
scanf("%d",&cycle);
_asm mov cx,cycle
NEXT:
_asm{
fld1
fld i
fadd st(0),st(1)
fst i
finit
fld y
fld i
fld a
fld x
fmul st(0),st(1)
fdiv st(0),st(2)
fst a
fadd st(0),st(3)
fst y
loop NEXT
fld y
fst result
}
printf("%f\n",result);
getch();
}
Лабораторна робота № 9
Керування дисплеєм
Тема: Знайомство з текстовим та графічним режимами роботи дисплеїв. Програмування графіки мовою Асемблер. Керування дисплеєм шляхом прямого доступу до відеопамяті диплея та за допомогою функцій BIOS.
Теоретичні відомості
2.9.1 Технічні особливості дисплеїв
Дисплей включає в себе екран з електронно-променевою трубкою, а також комплекс технічних засобів, що забезпечують появу на екрані зображення. В основі його роботи є багато спільного з телевізором: в результаті зіткнення пучка електронів з поверхнею екрана, покритою люмінофором, який світиться, утворюється точка - піксел, що світиться, причому інтенсивність світла залежить від енергії електронного пучка. Змінюючи енергію пучка, можна отримати різну яскравість певного піксела від темної до максимальної. Електронний промінь “оббігає” екран зліва направо і згори до низу 25 разів у секунду, послідовно формуючи множину близько розташованих пікселів, які, зливаючись один з одним, сприймаються оком як єдине ціле.
Найбільш важливою відмінністю описаного механізму від способу створення зображення на екранах звичайних телевізорів є та обставина, що програміст може керувати світінням екрана в будь-якому його місці, і навіть кожним окремим пікселем. Така можливість досягається ціною значного ускладнення електронних компонентів дисплея у порівнянні з побутовим телевізором.
Через велику кількість пікселів на екрані давати окрему команду для кожного піксела буде досить неефективно, оскільки центральний процесор буде практично постійно зайнятий регенерацією зображення.
Тому між програмою і схемою електронної розгортки зображення розміщується буферна память (відеопамять) на два входи (порти). Програма може звертатись до свого порту, щоб розмістити потрібне значення у відеопамять або прочитати з неї раніше встановлене значення так само, як це робиться із звичайною оперативною памяттю ЕОМ. Одночасно до свого порту звертаються за зчитуванням інформації з відеопамяті схеми розгортки зображення. Відносно повільна програма не поспішаючи “кладе” у відеопамять окремі фрагменти зображення, в той час як швидкі схеми розгортки безперервно формують з цих фрагментів цільне зображення.
Найбільш важливі електронні компоненти дисплея:
Ці компоненти розташовані на одній друкованій платі, яка називається відеоадаптером.
Існують такі загальноприйняті стандарти відеоадаптерів:
Існує два види інформації, що зявляється на екрані дисплея: текстова, тобто така інформація, яка складається зі знаків алфавіту, цифр та спеціальних символів; і графічна креслення, рисунки, графіки. Хоча описаний вище механізм формування зображень загальний для обох видів інформації, є суттєві відмінності у тому, яким чином використовується відеопамять. Ці відмінності настільки істотні, що говорять про два режими роботи дисплеїв текстовий та графічний. Розглянемо спочатку текстовий режим при відтворенні чорно-білої інформації.
Для найбільш розповсюджених типів дисплеїв на екран може бути виведено 25 рядків по 80 символів в кожному, тобто всього 2000 символів. Кожний символ являє собою один з 256 заздалегідь обумовлених знаків. Для розміщення символу на екрані використовується прямокутна матриця розміром 8×8 = 64 пікселів, яка називається знакомісцем.
На рис.18 показано формат екрана 25×80, а на рис.19 позиції символів на екрані, пронумеровані цілими числами
Стовпчик |
Стовпчик |
|||||||||||||||
0 |
1 |
. |
. |
. |
79 |
0 |
1 |
. |
. |
. |
79 |
|||||
Рядок |
0 |
0,0 |
0,1 |
. |
. |
. |
0,79 |
Рядок |
0 |
0 |
1 |
. |
. |
. |
79 |
|
1 |
1,0 |
1,1 |
. |
. |
. |
1,79 |
1 |
80 |
81 |
. |
. |
. |
159 |
|||
. |
. |
. |
. |
. |
. |
. |
. |
|||||||||
. |
. |
. |
. |
. |
. |
. |
. |
|||||||||
. |
. |
. |
. |
. |
. |
. |
. |
|||||||||
24 |
24,0 |
24,1 |
. |
. |
. |
24,79 |
24 |
1920 |
1921 |
. |
. |
. |
1999 |
|||
Рисунок 18 Формат екрана 25×80 |
Рисунок 19 Позиції символів на екрані |
Оскільки вигляд будь-якого символу, що виводиться, заздалегідь визначений, для зберігання інформації про нього немає необхідності використовувати матрицю 8×8, тобто 8 байтів відеопамяті. Досить лише вказати номер символу, тобто помістити в память лише 1 байт. Використовуючи цей байт як ключ, електронні схеми розгортки відшукають в ПЗП одну з 256 матриць 8×8 розрядів і, відповідно до неї, викреслять символ на екрані.
Насправді ж у відеопамяті приходиться зберігати не один, а два байти інформації про кожне знакомісце додатковий байт використовується для зберігання атрибутів символу. Атрибути забезпечують індикацію світлого символу на темному фоні (нормальне зображення) або темного символу на світлому фоні (інверсне зображення), виведення символу з підвищеною яскравістю, виведення символу, що мерехтить, виведення підкресленого
символу. Формат байта атрибутів наведений на рис.20 і в табл.5. Таким чином, для зберігання однієї “карти” (тобто, однієї сторінки) екрана в текстовому режимі при використанні двох кольорів (чорного і білого) необхідно лише 80×25×2 = 4 Кб відеопамяті. Таким є розмір відеопамяті адаптера MDA.
Значно більший розмір відеопамяті для відеоадаптера CGA: 4 текстові сторінки в режимі 80×25 символів та 8 сторінок в режимі 40×25 символів, тобто 16 Кб.
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
BL |
R |
G |
B |
I |
R |
G |
B |
Фон |
Символ |
||||||
BL=0 символ не мерехтитьBL=1 символ мерехтить |
I=0 нормальна яскравістьI=1 збільшена яскравість |
||||||
Рисунок 20 Формат байта атрибутів для відеоадаптера MDA |
Таблиця 5 Атрибути символів для відеоадаптера MDA
Вміст поля RGB для фону |
Вміст поля RGB для символу |
Атрибут |
0 0 0 |
0 0 0 |
Не відображається: чорний по чорному (можна використовувати для паролів) |
1 1 1 |
1 1 1 |
Білий прямокутник (білий по білому) |
0 0 0 |
1 1 1 |
Нормальне зображення (білий по чорному) |
1 1 1 |
0 0 0 |
Інверсне зображення (чорний по білому) |
Адаптер CGA дозволяє також відтворювати текстову інформацію в кольорі. Колір окремого символу задається за допомогою його атрибута, формат якого наведений на рис.9 та в табл.6.
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
BL |
R |
G |
B |
I |
R |
G |
B |
Колір фону |
Колір символу |
||||||
BL=0 символ не мерехтитьBL=1 символ мерехтить |
I=0 нормальна яскравістьI=1 збільшена яскравість |
||||||
Рисунок 21 Формат байта атрибутів для відеоадаптера CGA |
У відеопамяті код символу завжди міститься у байті з парною адресою, а його атрибут у байті з більшою непарною адресою. Отже, слово з парною адресою дає всю інформацію для однієї символьної позиції.
Хоча відеопамять не схожа на основну оперативну память компютера, до неї можна звертатись з програми за допомогою адрес. Для відеопамяті в компютері зарезервовані адреси з А000 по DFFF, тобто 256 Кб.
Таблиця 6 Атрибути символів для відеоадаптера CGA
Фон |
Символ |
||||
RGB |
Колір |
IRGB |
Колір |
IRGB |
Колір |
0 0 0 |
чорний |
0 0 0 0 |
чорний |
1 0 0 0 |
сірий |
0 0 1 |
синій |
0 0 0 1 |
cиній |
1 0 0 1 |
яскраво-блакитний |
0 1 0 |
зелений |
0 0 1 0 |
зелений |
1 0 1 0 |
яскраво-зелений |
0 1 1 |
синьо-зелений |
0 0 1 1 |
синьо-зелений |
1 0 1 1 |
яскраво-синьо-зелений |
1 0 0 |
червоний |
0 1 0 0 |
червоний |
1 1 0 0 |
яскраво-червоний |
1 0 1 |
малиновий |
0 1 0 1 |
малиновий |
1 1 0 1 |
яскраво-малиновий |
1 1 0 |
коричневий |
0 1 1 0 |
коричневий |
1 1 1 0 |
яскраво-жовтий |
1 1 1 |
білий |
0 1 1 1 |
білий |
1 1 1 1 |
яскраво-білий |
Відеопамять адаптера MDA починається з адреси В000 і займає 4 Кб, для адаптера CGA відеопамять починається з адреси В800 і займає 16 Кб. У табл.7 наведені адреси початку текстових сторінок для CGA-дисплеїв.
Номер сторінки |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Режим роботи 80×25 |
В800 |
В900 |
ВA00 |
ВB00 |
- |
- |
- |
- |
Режим роботи 40×25 |
В800 |
В880 |
В900 |
В980 |
ВA00 |
ВA80 |
ВB00 |
ВB80 |
Код програми, наведеної нижче, демонструє роботу дисплея у текстовому режимі у випадку безпосереднього доступу до сторінок відеопамяті. У програмі екран диплея спочатку очищається символами “пропуск” на малиновому фоні, а потім за допомогою символів псевдографіки формується зображення рамки яскраво-блакитного кольору.
NAME PROG
DB 128 DUP(?)
STACKSG ENDS
DATE SEGMENT
DATE ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATE, SS:STACKSG
START PROC FAR
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,DATE
MOV DS,AX
CALL MAIN
RET
START ENDP
MAIN PROC
MOV AH,0
mov al,03h
INT 10h
MOV AX, 0B800h ; початкова адреса текстової сторінки
MOV ES,AX
MOV DI,0
MOV AL, ' ' ; задаємо символ для відображення
MOV AH,059h ; задаємо колір: 01011001b
MOV CX,2000 ; задаємо кількість повторень символу
CLD ; скидаємо прапорець напрямку (iнкремент)
REP STOSW ; повторюємо ланцюжок символів (слово АХ)
; рисуємо лівий верхній кут
MOV DI,660
MOV AL,213
MOV AH,059h
MOV ES:[DI],AX ; розміщуємо АХ за адресою DI
; відносно початку ES сторінки
; рисуємо верх рамки (40 символів в рядок зліва направо)
MOV CX,40
MOV AL,205
M1: ADD DI,2
MOV ES:[DI],AX
LOOP M1
; рисуємо правий верхній кут
ADD DI,2
MOV AL,184
MOV ES:[DI],AX
; рисуємо праву сторону рамки (6 символів у стовпчик згори донизу)
MOV AL,179
MOV CX,6
M2: ADD DI,160
MOV ES:[DI],AX
LOOP M2
; рисуємо правий нижній кут
ADD DI,160
MOV AL,217
MOV ES:[DI],AX
; рисуємо низ рамки (40 символів справа наліво)
MOV AL,196
MOV CX,40
M3: SUB DI,2
MOV ES:[DI],AX
LOOP M3
; рисуємо нижній лівий кут
SUB DI,2
MOV AL,192
MOV ES:[DI],AX
; рисуємо ліву сторону рамки (6 символів знизу вгору)
MOV AL,179
MOV CX,6
M4: SUB DI,160
MOV ES:[DI],AX
LOOP M4
ret
MAIN ENDP
CODE ends
end start
Як відомо, в ЕОМ прийнято растровий спосіб формування зображень, тобто, будь-яка інформація на екрані дисплея являє собою сукупність точок - пікселів, що світяться. Кожний піксел визначається своїми координатами розташуванням відносно лівого верхнього кута екрана, який має координати (0,0). Програміст може керувати яскравістю та/або кольором будь-якого піксела, що дозволяє формувати на екрані будь-які зображення, у тому числі рисунки, графіки, креслення, символи.
Як і в текстовому режимі, в графічному режимі використовується буферна відеопамять, вміст якої являє собою “карту” екрана. Розмір памяті адаптера CGA (16 Кб) достатній для відображення 640×200 пікселів, якщо з кожним пікселем звязувати лише один розряд (біт) відеопамяті. Зрозуміло, що інформаційна цінність одного біта, а отже, і можливості керування пікселем в цьому випадку надзвичайно обмежені: адже один розряд може мати або нульове, або одиничне значення. В компютері прийнято вважати, що нульовий стан будь-якого розряду відеопамяті означає сигнал про відсутність світіння відповідного піксела, і, навпаки, одиничний стан сигнал висвітлити відповідний піксел.
Таким чином, обєм 16 Кб відеопамяті дозволяє отримати на екрані розміром 640×200 пікселів тільки двоколірне зображення чорний колір відповідає стану 0 біта відеопамяті, а стан 1 виведенню піксела будь-яким заздалегідь вибраним кольором. В рамках CGA-адаптера такий режим називається режимом високої роздільної здатності.
В іншому режимі адаптера CGA режимі середньої роздільної здатності на кожний піксел виділяється 2 біти відеопамяті, але досягається це ціною подвійного погіршення роздільної здатності екрана: 320×200 пікселів.
Вказані два біти відеопамяті використовуються для вибору кольору піксела.
На перший погляд, за допомогою двох бітів можна вказати лише 2 кольори. Але розробники дисплеїв прийняли інше рішення.
Одне зі значень, що запамятовується у парі бітів (значення 00), виділено окремо: воно вказує на те, що піксел має той самий колір, що і фон. Така точка сприймається як така, що не світиться.
Як раніше згадувалось, вісім основних кольорів отримуються в результаті накладання променів червоного, синього та зеленого кольорів (решта вісім кольорів це ті ж самі основні, але підвищеної яскравості). Таким чином, кольори можна розділити на дві групи, які відрізняються наявністю або відсутністю, наприклад, синьої складової.
У першій групі (параметр “палітра” дорівнює 0) синій промінь не присутній, і всі кольори утворюються сумішшю червоного і зеленого. Якщо пара бітів встановлена в стан 01, то точка загорається червоним кольором, 10 зеленим, 11 їх сумішшю, тобто жовтим (табл.8).
Колір піксела |
Код кольору |
Суміш променів |
Параметр “палітра” |
Червоний |
01 |
червоний |
0 |
Зелений |
10 |
зелений |
0 |
Жовтий |
11 |
червоний + зелений |
0 |
Фіолетовий |
01 |
червоний + синій |
1 |
Бірюзовий |
10 |
зелений + синій |
1 |
Білий |
11 |
зелений + червоний + синій |
1 |
У другій групі кольорів (параметр “палітра” дорівнює 1) синя складова обовязково присутня. Тому стану 01 відповідає фіолетовий колір, стану 10 бірюзовий і стану 11 білий колір (табл.8).
Пари бітів не вистачає для того, щоб запамятати яскравість піксела, і тому в режимі графіки середньої роздільної здатності кількість доступних кольорів обмежено числом шість.
В більш сучасних адаптерах EGA та VGA розмір відеопамяті збільшено і він складає від 64 до 256 Кб. Це дозволяє отримати на екрані з роздільною здатністю 640×350 пікселів або й більше і до 16 кольорів одночасно.
До відеопамяті мають можливість одночасного доступу як програма для переустановлення стану будь-якого піксела, так і електронні схеми розгортки зображення на екрані. Ці схеми розглядають відеопамять як один довгий рядок бітів, що зберігає команди щодо встановлення яскравості і кольору певного піксела. Електронні схеми опитують відеопамять послідовно біт за бітом у темпі електронного променя, що “оббігає” екран.
Зображення стандартного телевізійного кадру формується з двох півкадрів. У першому півкадрі промінь оббігає екран по всіх парних рядках екрана, у другому по всіх непарних. Відповідним чином зберігається і інформація у відеопамяті: в першій її половині (з меншими адресами) повинна міститися інформація про парні рядки, у другій половині (адреса початку цієї частини повинні бути кратною 1024) про непарні. Вбудовані процедури і функції, що підтримують графіку, враховують цю особливість. При прямому зверненні до відеопамяті ця функція покладається на програміста.
У графічному режимі існує можливість виведення символьної інформації. Символи будь-якої конфігурації користувач може формувати самостійно і представляти їх просто як деякі піктограми, що займають певну частину екрана (за аналогією з текстовим режимом будемо називати частину екрана, зайняту зображенням символу, знакомісцем).
Інший підхід полягає в імітації засобів, реалізованих в текстовому режимі. Нагадаємо, що у текстовому режимі використовується розташована в ПЗП таблиця графічних образів усіх символів, яка керує роботою схем генерації тексту. У графічному режимі при виведенні символів також використовується таблиця знакогенератора, але розташована в ПЗП таблиця підключається лише при виведенні першої половини символів (з кодами від 0 по 127), при виведенні другої половини символів (з кодами від 128 по 256) використовується частина таблиці, що завантажується в оперативну память. Зроблено це не випадково, оскільки друга половина ASCII-кодів використовується для формування символів національного алфавіту, у тому числі кирилиці. Реалізація цієї частини кодів за допомогою завантажуваної в память таблиці знакогенератора дуже спрощує проблему “перенавчання” компютера під будь-який національний алфавіт. На жаль, для текстового режиму можливість завантажування таблиці знакогенератора є лише на удосконалених відеоадаптерах EGA, VGA та більш сучасних. При роботі з адаптером CGA “перенавчання” компютера в текстовому режимі роботи дисплея досягається лише методом перепрограмування мікросхеми ПЗП.
У графічному ж режимі роботи адаптера CGA “заставити” компютер виводити текстові повідомлення українською мовою не складає проблеми. Для цього треба лише завантажити в оперативну память шрифт у вигляді таблиці з 128 матриць розміром 8×8 бітів і повідомити адресу початку цієї таблиці схемам розгортки. Кожна матриця 8×8 бітів (8 байтів) містить графічний образ символу, що виводиться, причому перші 8 байтів використовуються при виведенні символу з кодом 128, наступні 8 байтів символу з кодом 129 і т.д. Кожний байт матриці кодує один рядок розгортки з 8 суміжних пікселів: якщо перший біт у байті має значення 1, перший піксель цього рядка буде світитися, якщо ж 0 не буде. Стан другого піксела визначається вмістом другого біта і т.д.
2.9.5 Керування дисплеєм за допомогою функцій BIOS
Керувати дисплеєм можна також на основі загальних принципів керування периферійними пристроями.
На початку свого розвитку мікропроцесорні системи мали у своєму складі програму, що називається “монітор”. Ця програма зазвичай знаходилась в ПЗП і обслуговувала пристрої введення-виведення клавіатуру, дисплей, касетний накопичувач на магнітній стрічці та ін. Діалогова частина монітора дозволяла виконувати деякі операторські функції завантаження і запуск програми, відлагоджування в покроковому режимі, друк текстів, перегляд і редагування вмісту памяті і т.д. Але найголовніше прикладні програми, що були складені для цих систем, могли користуватись модулями монітора для роботи з периферійною апаратурою і виконувати ці операторські функції. Програма вже не містила в собі всі необхідні для її роботи модулі, а користувалась “стандартними” послугами програми-монітора. Така організація програми не тільки зменшувала розмір її завантажувального модуля, а й дозволяла програмістам зосередити свої зусилля на розвязанні основної задачі.
Механізм взаємодії програми користувача і монітора був реалізований по-різному у різних системах. У найгіршому випадку програма користувалась відомими абсолютними адресами модулів монітора, у найкращому використовувала спеціальні таблиці адрес програмних модулів. На жаль, різні системи були несумісні за складом модулів монітора і механізмом їх виклику, що сильно утруднювало їх програмну сумісність, а іноді і цілком її виключало.
У першому масовому компютері IBM PC модулі обслуговування стандартної периферії були записані в ПЗП. Сукупність цих модулів (плюс програма початкової ініціалізації і тестування) називається базовою системою введення-виведення Basic Input/Output System (BIOS).
Компютери, сумісні з IBM PC, що випускаються різними фірмами, можуть дещо відрізнятися за типом периферійного обладнання, але для досягнення сумісності з ІВМ РС модулі BIOS знімають ці відмінності, надаючи в розпорядження програми користувача стандартний набір модулів для роботи з пристроями введення-виведення.
Не буде перебільшенням сказати, що одна з причин такої популярності компютера ІВМ РС на ринку персональних компютерів це наявність добре продуманого стандартного інтерфейсу модулів BIOS і прикладних програм. Саме завдяки цьому інтерфейсу досягається майже стовідсоткова сумісність персональних компютерів даного типу, що випускаються різними фірмами, за їх програмним забезпеченням.
Для виклику відповідного модуля BIOS прикладна програма використовує команду переривання INT <n> з відповідним номером n. Програма передає параметри модулям BIOS через регістри процесора, результат роботи модуля повертається також в регістри.
Для роботи з дисплейним адаптером використовується команда переривання INT 10h. Під час виклику цього переривання, як і під час виклику багатьох інших переривань, регістр АН повинен містити номер функції, яку слід виконати. Для виконання більшості функцій необхідно мати деякі додаткові дані, які повинні бути розміщені в регістрах AL, BX, CX, DX. Надалі ми конкретно розглянемо всі функції, необхідні для керування CGA-дисплеєм. Варто зауважити, що, у порівнянні з безпосереднім доступом до відеопамяті, використання звернень до BIOS є набагато простішим інструментом, але більшість функцій BIOS характеризуються невисокою швидкодією.
Дисплей може працювати у декількох режимах. Перелік можливих режимів роботи дисплея наведено в табл.9.
Номер режиму |
Текстовий або графічний |
Колір є/немає і скільки |
Формат |
Тип адаптера |
0 |
текстовий |
немає |
40 зн. х 80 ряд. |
MDA, CGA, EGA |
1 |
текстовий |
8 кольорів |
40 зн. х 80 ряд. |
CGA, EGA, VGA |
2 |
текстовий |
немає |
80 зн. х 80 ряд. |
CGA, EGA, VGA |
3 |
текстовий |
8 кольорів |
80 зн. х 80 ряд. |
CGA, EGA, VGA |
4 |
графічний |
6 кольорів |
320 х 200 точ. |
CGA, EGA, VGA |
5 |
графічний |
немає |
320 х 200 точ. |
CGA, EGA, VGA |
6 |
графічний |
немає |
640 х 200 точ. |
CGA, EGA, VGA |
7 |
текстовий |
немає |
80 зн. х 80 ряд. |
Hercules,EGA,VGA |
0Dh |
графічний |
16 кольорів |
320 х 200 точ. |
EGA, VGA |
0Eh |
графічний |
16 кольорів |
640 х 200 точ. |
EGA, VGA |
0Fh |
графічний |
немає |
640 х 350 точ. |
EGA, VGA |
10h |
графічний |
4 або 16 кольорів |
640 х 350 точ. |
EGA, VGA |
11h |
графічний |
немає |
640 х 480 точ. |
VGA |
12h |
графічний |
16 кольорів |
640 х 480 точ. |
VGA |
13h |
графічний |
256 кольорів |
320 х 200 точ. |
VGA |
Для зручності зведемо всі функції BIOS для керування роботою дисплеїв у таблицю 10.
Таблиця 10 Функції переривання INT 10h для керування роботою дисплеїв
Номер функції |
Призначення |
Вміст регістрів |
Пояснення |
00h |
Задання режиму дисплея |
На вході: АН = 00h AL = номер режиму (табл.9) |
Функція використовується для вибору режиму роботи дисплея. |
01h |
Задання типу курсора |
На вході: АН = 01h СН = номер початкової лінії AL = номер кінцевої лінії. На виході: немає |
Функція дозволяє встановити розмір курсора. Передбачено визначення першої та останньої лінії (лінії розгортки), що обмежують область розташування символу (установлення початкової лінії вгорі області, а установлення кінцевої лінії внизу області не обовязкове, тобто курсор може бути встановлено посередині описаної області). Слід зауважити, що в графічному режимі курсор відсутній. Курсор може бути відключений шляхом установлення початкової і кінцевої лінії нижче рівня розташування курсора. |
02h |
Задання позиції курсора |
На вході: АН = 02h DH = номер рядка DL = номер стовпчика BH = номер сторінки На виході: немає |
Функція видає координати для позиціонування курсора на екрані. Рядок 0 розташований вгорі, а стовпчик 0 в лівій частині екрана. |
03h |
Зчитування позиції курсора |
На вході: AH = 03h BH = номер сторінки На виході: DH =поточний рядок DL = поточний стовпчик CH = початкова лінія курсора CL = кінцева ліні На виході: немає |
Функція дозволяє отримати координати позиції курсора на екрані та його тип. |
05h |
Задання активної сторінки екрана, тобто, який з екранів буде виведено на дисплей (за замовчуванням 0) |
На вході: AH = 05h AL = номер сторінки, що виводиться на екран дисплея На виході: немає |
Адаптер дозволяє використовувати декілька сторінок (екранів) інформації в памяті. Видимою в певний момент може бути лише одна активна сторінка. Більшість функцій можуть модифікувати екран (запис символу, побудова точки і т.д.) і вибирати сторінку, а отже вносити зміни в невидиму сторінку. Тобто на екрані може бути одне зображення, в той час як ми модифікуємо іншу сторінку (зручно при мультиплікації і виведенні слайдів). |
06h |
Прокручування (скролінг) активної сторінки вгору |
На вході: AH = 06h AL = число рядків, на яке слід “прокрутити” (0 для очистки екрана) BH = символ атрибута нових рядків CH = верхній рядок вікна CL = лівий стовпчик вікна DH = нижній рядок вікна DL = правий стовпчик вікна На виході: немає |
За допомогою цієї функції виконується прокручування тексту на екрані: рядки переміщуються знизу вгору, а внизу здійснюється вставка пустих рядків. Можуть бути визначені координати вікна, яке прокручується, оскільки лише частина екрана може підлягати прокручуванню. |
07h |
Прокручування (скролінг) активної сторінки вниз |
На вході: AH = 07h AL = число рядків, на яке слід “прокрутити” (0 для очистки екрана) BH = символ атрибута нових рядків CH = верхній рядок вікна CL = лівий стовпчик вікна DH = нижній рядок вікна DL = правий стовпчик вікна На виході: немає |
Виконується прокручування тексту на екрані: рядки переміщуються згори донизу, а вгорі здійснюється вставка пустих рядків. Функція працює таким самим чином, як і 05h. |
08h |
Зчитування атрибута і сим-волу в поточній позиції курсора |
На вході: AH = 08h BH = номер сторінки На виході: AL = ASCII-код символу AH = атрибут символу |
Функція може бути використана для зчитування символу з будь-якої сторінки. У результаті повертається символ, розташований в поточній позиції курсора вказаної сторінки і його атрибут. Атрибут являє собою один байт згідно з рис.8 і табл.6. Байт атрибута має сенс лише в текстових режимах. |
09h |
Установлення атрибута символу і запис символу в поточну позицію курсора |
На вході: AH = 09h AL = ASCII-код символу BH = номер сторінки BL = атрибут символу CX = кількість записуваних символів На виході: немає |
В графічних режимах байт атрибуту використовується для установлення кольору символу. Установлення 7-го біта байта атрибуту приводить до того, що символ накладається на поточний вміст екрана. В текстових режимах виведення більшого, ніж може поміститися, числа копій символу призведе до перенесення на наступний рядок. У графічному режимі всі символи повинні розміщатися в одному рядку. Позиціонування символу повинно виконуватись засобами програми. Виведення керуючих символів виконується як виведення звичайних символів. |
0Ah |
Запис символу у поточну позицію курсора |
На вході: AH = 0Ah AL = ASCII-код символу BH = номер сторінки CX = кількість символів, що записуються На виході: немає |
Звернення до цієї функції ідентичне зверненню до функції 09h, за винятком того, що атрибут не може бути установлений (існуючі атрибути не змінюються). |
0Bh |
Задання палітри кольорів |
На вході: AH = 0Bh BH = ідентифікатор фону або палітри кольорів BL = номер кольору На виході: немає |
При ВН = 0 у графічному режимі регістр BL визначає колір фону (значення 0-15), а у текстових режимах колір границі (значення 0-31). |
0Ch |
Запис точки |
На вході: AH = 0Ch AL = номер кольору BH = номер сторінки (лише для EGA та VGA) CX = номер стовпчика піксела (0-319 або 0-639) DX = номер рядка (0-199, 0-349 або 0479) На виході: немає |
Звернення до цієї функції застосовується для побудови точки на будь-якій сторінці в графічних режимах. Стовпчик 0 розташований зліва, а рядок 0 вгорі екрана. Якщо в регістрі AL встановлений біт 7, то новий піксел накладається на поточний вміст екрана з використанням функції “виключне АБО”. Регістр ВН (номер сторінки) CGA не підтримує. |
0Dh |
Зчитування точки |
На вході: AH = 0Dh BH = номер сторінки (лише для EGA та VGA) CX = номер стовпчика піксела (0-319 або 0-639) DX = номер рядка (0-199, 0-349 або 0-479) На виході: AL = значення кольору точки На виході: немає |
Звернення до цієї функції використовується для отримання кольору точки, розташованої на будь-якій сторінці у графічному режимі (для CGA лише одна сторінка). Стовпчик 0 розташований зліва, а рядок 0 вгорі екрана. |
2.9.7 Приклади програми для виведення зображення
у текстовому режимі з використанням функцій BIOS
Наведена нижче програма демонструє прийоми роботи з дисплеями у текстовому режимі за допомогою функцій BIOS. На екрані дисплея на чорному фоні за допомогою символів псевдографіки виводиться вікно синього кольору, в середині якого виведено рядок “Приклад 2”. NAME PROG
mov AH,02h
mov BH,0
int 10h
mov BH, 0
mov AH, 09h
int 10h
endm
DB 128 DUP(?)
STACKSG ENDS
text db "ПРИКЛАД”, 0
DATE ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATE, SS:STACKSG
START PROC FAR
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,DATE
MOV DS,AX
CALL MAIN
CALL stroka
RET
START ENDP
MAIN PROC
MOV AH,0 ; задаємо режим дисплея
INT 10h
mov dh,5 ; позиція курсора
mov DL,10
met2:
cursor ; встановлюємо курсор в задану позицію
mov cx,60 ; кількість повторень
mov al,219 ; символ псевдографіки
mov bl,059h ; задаємо колір
attr ; виводимо символ із заданими параметрами
inc dh
cmp dh,10
jne met2
ret
MAIN ENDP
; процедура для виведення рядка посимвольно
stroka proc near
mov dh,7 ; позиція курсора
mov dl,30
cursor ; встановлюємо курсор
lea si,text-1 ; завантажуємо адресу рядка
met3:
inc si
mov al,[si]
mov bl,07Ch ; атрибути символу
mov cx,1
attr ; виводимо символ
inc dl
cursor
mov al,[si]
cmp al,0 ; перевірка на кінець рядка
jne met3
mov dl,'2'
mov ah, 06h
int 21h
mov dh,22
mov dl,1
cursor
ret
stroka endp
ends
2.9.8 Приклад програми для виведення зображення
у графічному режимі з використанням функцій BIOS
Наведена нижче програма демонструє прийоми роботи з дисплеями у графічному режимі за допомогою функцій BIOS. На екрані дисплея на чорному фоні за допомогою пікселів виводиться пряма лінія синього кольору.
NAME PROG1
DB 128 DUP(?) ; резервування памяті для стека
con1 dw 100
con2 dw 50
DATE_SG ENDS
ASSUME CS:CODE_SG, DS:DATE_SG, SS:STACKSG
start proc far
push ds
sub ax,ax
push ax
call main
ret
start endp
Мov ah,00h ; установлення режиму
mov al,4h ;
int 10h
mov ah,0Bh ; установлення палітри кольорів
mov bh,1 ; для фону зображення
mov bl,1 ; номер кольору
int 10h
mov ah,0Bh ; установлення режиму
mov bh,0 ; для виведення рисунка
mov bl,6 ; номер кольору
int 10h
mov si,con2 ; кінцева координата
mov cx,con1 ; початкова координата (№ стовпчика)
mov dx,con2 ; номер рядка
met1: mov ah,0Ch ; запис точки
mov al,2 ; номер кольору
inc cx
dec si
cmp si,0
jne met1
ret
main endp
CODE_SG ends
end start
Лабораторна робота № 10
Робота з файлами
Тема: Програмування основних операцій над файлами мовою Асемблер: створення, відкриття, закриття файлів. Введення даних у файл (пристрій) і виведення даних з файла (пристрою). Програмування операцій з атрибутами файлів. Робота з дисками, каталогами, пошук файлів.
Теоретичні відомості
2.10.1 Класи функцій для роботи з файлами
В операційній системі MS DOS існують два класи функцій для роботи з файлами:
Перший клас функцій (функції 0Fh 24h) застосовувався в MS DOS версій 1.х і на даний час має чисто історичний інтерес.
Другий клас функцій (функції 39h 62h) зявився вперше в MS DOS версії 2.0 і широко використовується дотепер.
Сутність каналу (інші назви дескриптор файла, файловий індекс, логічний номер) полягає у наступному. Для того, щоб почати роботу з файлом або пристроєм, програма повинна відкрити цей файл або пристрій. Процес відкриття файла або пристрою полягає у присвоєнні йому певного номера каналу й виконання деяких інших ініціалізуючих дій.
Після закінчення роботи з файлом або пристроєм його необхідно закрити, при цьому канал, що йому відповідає, стає вільним.
Перші пять номерів каналів зарезервовані операційною системою для таких стандартних пристроїв:
0 Stdin стандартний пристрій введення (клавіатура);
1 Stdout стандартний пристрій виведення (екран диплея);
2 Stderr стандартний пристрій для виведення повідомлень про помилки (екран диплея);
3 Stdaux стандартний пристрій звязку (послідовний адаптер СОМ1);
4 Stdptr стандартний пристрій друку (перший паралельний порт LPT1).
Ці пристрої доступні прикладним програмам, їх не треба відкривати, але програми можуть закривати їх. Пристрій Stdaux може використовуватись як для введення, так і для виведення даних.
Наведені вище пристрої при початковому завантаженні операційної системи знаходяться у символьному режимі.
2.10.2 Створення файлів
Створюється файл за допомогою функції 3Сh переривання INT 21h. для виклику цієї функції необхідно помістити в регістри таку інформацію:
На вході:
AH = 3Ch.
CX = Атрибути файла, який буде створено, а саме:
00 звичайний файл;
01 тільки для читання;
02 прихований файл;
04 системний файл.
DS:DX = адреса ASCII-рядка, що містить шлях по каталогу для файла, що створюється.
На виході:
після завершення роботи функції в регістрі АХ знаходиться номер каналу цього файла або вказується код помилки, якщо файл не було створено.
Додатково ця ж функція виконує також операцію відкриття щойно створеного файла. Варто зауважити, що якщо файл із вказаним імям вже існує, він обрізається до нульової довжини. І тому, щоб випадково не знищити вміст файла з таким самим імям, як і той, що створюється, можна використовувати функцію 5Bh переривання INT 21, яка виконує перевірку наявності файла з таким іменем.
Можна для відкриття або створення файла з розширеними можливостями використовувати більш сучасну функцію 6Сh, яка зявилася в останніх версіях MS DOS (DOS 4.0++). З її появою зникає необхідність відслідковувати існування файла, що створюється. Для коректної роботи цієї функції слід лише задати потрібні значення у відповідних регістрах.
2.10.3 Відкриття файла
Відкриття існуючого файла виконується за допомогою функції 3Dh переривання INT 21h. Для виклику цієї функції необхідно розмістити в регістрах таку інформацію:
На вході:
АН = 3Dh.
AL = байт режиму доступу.
DS:DX = адреса ASCII-рядок, що містить шлях по каталогу файла, який відкривається.
На виході:
АХ містить номер каналу відкритого файла або код помилки, якщо файл не був відкритий.
Байт режиму доступу визначає правила доступу до файла. Цей байт складається з чотирьох полів, і побітово поля в ньому розподіляються таким чином, як це наведено у таблиці 11.
Таблиця 11 Вміст байта режиму доступу
Режим доступу |
Біти |
Призначення |
Можливі значення |
<I> |
7 |
прапорець успадкування |
0 файл передається породженому процесу; 1 файл являє собою власність даного процесу. |
<S> |
6,5,4 |
поле режиму розподілу |
000 спільне використання файла; 001 захист від читання і запису; 010 захист від запису; 011 захист від читання; 100 без захисту. |
<R> |
3 |
резервне поле |
0 |
<A> |
2,1,0 |
вид доступу |
000 доступ на читання; 001 доступ на запис; 010 доступ на читання і запис. |
Усі інші комбінації заборонені.
Розглянемо детальніше сутність режимів розділення й видів доступу.
Режим розділення інформує операційну систему про те, які операції над файлом є доступними іншим процесам (програмам). За замовчування (режим спільного використання) забороняється всім іншим компютерам мережі звертатись до цього файла.
Іноді виникає потреба дозволити іншим програмам виконувати читання з файла, поки наша програма працює з ним. У цьому випадку необхідно встановити захист від запису, який забороняє записувати у файл іншим процесам, але дозволяє зчитувати з нього.
Важливо також вказати, які операції програма збирається здійснювати з файлом (вид доступу). Встановлений за замовчуванням вид доступу (доступ на зчитування і запис) приводить до того, що запит на відкриття файла не дозволяється, якщо інший процес на цьому або іншому компютері мережі відкрив даний файл в режимі розділення, відмінному від режиму “без захисту”. Але якщо необхідно лише читати з файла, то можна відкрити файл, який вже відкритий іншим процесом з режимом розділення з “захистом від запису”, встановивши йому “доступ на читання” (отже, підвищується доступність файла).
Питання про використання файла декількома процесами залежить від режиму розділення та виду доступу.
2.10.4 Закриття файла
Закриття файла виконується за допомогою функції 3Eh переривання INT 21h. Для виклику цієї функції необхідно помістити у регістри таку інформацію:
На вході:
AH = 3Eh;
BX = номер каналу файла;
DS:DX = адреса ASCII-рядка, що містить шлях по каталогу файла, що закривається.
На виході:
АХ містить код помилки.
Після виконання цієї функції файл закривається, елемент каталога оновлюється, а всі системні буфери, що відведені для цього файла, звільняються.
2.10.5 Читання даних з файла або від пристрою
Для пересилання заданої кількості байтів у буфер із файла або пристрою символьної обробки (клавіатури) використовується функція 3Fh переривання INT 21h. Для виклику цієї функції необхідно помістити у регістри таку інформацію:
На вході:
AH = 3Fh;
BX = номер каналу відкритого файла;
СХ = кількість байтів, що передаються;
DS:DX = адреса буфера для даних.
На виході:
АХ = кількість переданих байтів або код помилки, якщо передача даних не відбулася.
2.10.6 Запис даних у файл або на пристрій
Для пересилання заданої кількості байтів із буфера у файл або на пристрій символьної обробки (дисплей) використовується функція INT 40h переривання 21h. Для виклику цієї функції необхідно помістити таку інформацію у регістри:
На вході:
AH = 40h;
BX = номер каналу відкритого файла;
СХ = кількість байтів, що передаються;
DS:DX = адреса буфера для даних.
На виході:
АХ = кількість переданих байтів або код помилки, якщо передача даних не відбулася.
2.10.7 Вилучення файла
Файл може бути вилучено функцією 41h переривання 21h. Специфікація цієї функції наведена нижче.
На вході:
AH = 41h;
DS:DX = ASCIІ-рядок з іменем файла;
CL = атрибути файла, що вилучається.
На виході:
якщо прапорець CF = 1, тоді AX містить код помилки:
АХ = 2 файл не знайдено;
АХ = 3 невірно задано шлях;
АХ = 5 відказано в доступі.
Функція 41h не дозволяє вилучати файли з атрибутом “тільки для читання”. В цьому випадку слід змінити атрибути файла, що вилучається, за допомогою функції 43h.
2.10.8 Приклад програми роботи з файлом
Нехай, наприклад, необхідно створити файл FILE3.DAT у підкаталозі Е:\ТОМ і записати в нього пять однорозрядних чисел, розділених пропусками.
Для розв'язання вказаної задачі необхідно спочатку створити файл, потім переслати в нього 9 символів (цифри разом із пропусками), а після цього закрити файл. Така програма буде мати вигляд, наведений нижче.
NAME PROG2
SSTACK SEGMENT STACK
DB 128 DUP (?)
SSTACK ENDS
DATA SEGMENT
ADDR DB “E:\TOM\FILE3.DAT”,0
BUF DB “3 5 7 9 1”
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:SSTACK
START PROC FAR
PUSH DS
SUB AX,AX
PUSH AX
MOV AX, DATA
MOV DS, AX
CALL MAIN
RET
START ENDP
MAIN PROC
MOV AH, 03Ch
MOV CX, 0
MOV DX, OFFSET ADDR
INT 21h
MOV BX, AX
MOV AH, 40h
MOV CX, 9
MOV DX, OFFSET BUF
INT 21h
MOV AH, 03Fh
INT 21h
RET
MAIN ENDP
CODE ENDS
END START
2.10.9 Методи доступу до файлів
Існує два основних методи доступу до файлів: послідовний і прямий.
У файлах із послідовним методом доступу (їх називають також послідовними файлами) елементи даних (рядки) можуть бути змінної довжини і розділятися між собою парою символів: спочатку символом CR повернення каретки (ASCII-код - 13), а потім символом LF переведення рядка (ASCII-код 11).
У файлах з прямим доступом заздалегідь відводять фіксоване місце під кожний елемент даних. Якщо деякий елемент не займає все відведене під нього місце, то залишок заповнюється пропусками. У цьому випадку, знаючи розмір, який відводиться під елемент даних, досить легко визначити місце розташування будь-якого елемента даних за його номером.
Для пошуку потрібного елемента даних використовується файловий покажчик, який може бути встановлений у потрібну позицію за допомогою функції 42h переривання INT 21h. Для виклику цієї функції необхідно заповнити регістри такою інформацією:
На вході:
AH = 42h;
AL = вид доступу:
0 абсолютне зміщення від початку файла;
1 зміщення від поточної позиції;
2 зміщення відносно кінця файла;
СХ = старший байт зміщення;
DX = молодший байт зміщення;
ВХ = номер каналу файла.
На виході:
DX = перший байт поточної позиції покажчика,
АХ = молодший байт покажчика або код помилки при невиконанні функції.
За допомогою цієї функції можна визначити розмір файла, що досить корисно для послідовних файлів.
2.10.10 Алгоритм запису даних у послідовний файл
Для запису даних у послідовний файл слід виконати такі дії:
BUF DB 30 DUP (?), 13, 10
(тут під елемент відводиться 30 байтів).
Для додавання даних в існуючий файл необхідно виконати такі дії:
2.10.11 Алгоритм читання даних із послідовного файла
При читанні даних із послідовного файла необхідно виконати таку послідовність дій:
Якщо потрібно здійснити операцію введення-виведення в середину послідовного файла, тоді n-й елемент даних знаходиться методом підрахунку n розділювачів CR/LF.
2.10.12 Операції читання та запису даних
у файлах прямого доступу
Операції читання та запису даних у файлах прямого доступу відрізняється від аналогічних операцій з послідовними файлами лише способом пошуку потрібного елемента даних. Позиція n-го елемента даних дорівнює добутку розміру місця, що відводиться під елемент даних, на число (n-1).
2.10.13 Приклад програми читання даних із послідовного файла
Нехай, наприклад, необхідно вивести на екран дисплея вміст файла D:\TOM\PRIM.ASM. Така програма буде мати вигляд, наведений нижче.
NAME PROG3
SSTACK SEGMENT STACK
DB 128 DUP (?)
SSTACK ENDS
DATA SEGMENT
ADDR DB “D:\TOM\PRIM.ASM”,0
BUF DB 1000 DUP (?)
HANDLE DW ?
SIZE1 DW ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:SSTACK
START PROC FAR
PUSH DS
SUB AX, AX
PUSH AX
MOV AX, DATA
MOV DS,AX
CALL MAIN
RET
START ENDP
MAIN PROC
; відкриття файла
MOV AH, 03Dh
MOV AL, 0C2h
MOV DX, OFFSET ADDR
INT 21h
MOV HANDLE, AX
; визначення розміру файла
MOV BX, AX
MOV AH, 42h
MOV AL, 2
MOV CX, 0
MOV DX, 0
INT 21h
MOV SIZE1, AX
; установлення покажчика на початок файла
MOV AH, 42h
MOV AL, 0
MOV CX, 0
MOV DX, 0
INT 21h
; пересилання даних із файла у буфер
MOV AH, 03Fh
MOV CX, SIZE1
MOV SX, OFFSET BUF
INT 21h
; виведення даних із буфера на екран дисплея
MOV BX, 1
MOV AH, 040h
MOV CX, SIZE1
MOV DX, OFFSET BUF
INT 21h
; закриття файла
MOV BX, HANDLE
MOV AH, 03Fh
INT 21h
RET
MAIN ENDP
CODE ENDS
END START
Дана програма по суті виконує команду DOS, яка видає вміст файла PRIM.ASM на екран дисплея:
TYPE D:\TOM\PRIM.ASM
2.10.14 Робота з атрибутами файлів
Операційна система дозволяє отримати для аналізу і при необхідності змінити імя файла, атрибути файла, дату і час його останньої модифікації. Для цього призначені функції 43h, 56h, 57h переривання 21h. При цьому для функції 43h підфункція 00 призначена для отримання, а підфункція 01 для встановлення слова атрибутів файла. Аналогічно для функції 57h підфункції 00 та 01 дозволяють отримати та змінити дату і час відповідно.
Отримання атрибутів файла
На вході:
AX = 4300h;
DS:DX = ASCII-рядок з повним іменем файла.
На виході:
якщо прапорець CF = 0, тоді в регістрі CX слово атрибутів файла, причому його формат такий:
7-й біт розділяється в NovellNetWare;
6-й біт не використовується;
5-й біт архівний;
4-й біт каталог;
3-й біт мітка тома;
2-й біт системний;
1-й біт прихований;
0-й біт тільки для читання.
якщо CF = 1, тоді AX містить код помилки:
АХ = 1 невірне значення в AL;
АХ = 2 файл не знайдено;
АХ = 3 вказаний шлях не існує;
АХ = 5 доступ заборонено.
Наведемо фрагмент коду, що демонструє отримання атрибутів файла.
. . .
.data
fname db "MyFile.asm"
Address dd fname
. . .
.code
. . .
lds dx, ADDRESS
mov ax,4300h ;номер функції DOS
int 21h
jc exit ;Перехід у випадку помилки
. . .
; Тепер в CX атрибути файла
. . .
exit:
. . .
Встановлення атрибутів файла
На вході:
AX = 4301h;
CX = нове слово атрибутів файла;
DS:DX = ASCII-рядок з повним іменем файла.
На виході:
якщо прапорець CF = 1, тоді AX містить код помилки:
АХ = 1 невірне значення в AL;
АХ = 2 файл не знайдений;
АХ = 3 вказаний шлях не існує;
АХ = 5 доступ заборонений.
Перейменування файла
На вході:
AH = 56h;
DS:DX = ASCII-рядок з іменем існуючого файла;
ES:DI = ASCII-рядок з іменем нового файла;
На виході:
якщо прапорець CF = 0, тоді перейменування файла виконано успішно;
якщо прапорець CF = 1, тоді AX містить код помилки:
АХ = 1 невірне значення в AL;
АХ = 2 файл не знайдений;
АХ = 3 вказаний шлях не існує;
АХ = 5 доступ заборонений;
АХ = 11h у разі, якщо пристрої для нового і старого файлів не збігаються.
Дана функція дозволяє здійснити переміщення між каталогами, не змінюючи пристрою. Наведемо фрагмент коду, що демонструє переміщення між каталогами, не змінюючи пристрою.
. . .
.data
OLDNAME db "Myfile1.asm",0
addrold dd oldname
newname db "e:\myfile1.asm",0
addrnew dd newname
. . .
.code
. . .
lds dx, addrold
les di, ADDRnew
mov ah,56h
int 21h
jc exit ;Перехід у випадку помилки
. . .
exit:
. . .
Отримання дати і часу створення або останньої модифікації файла
На вході:
AX = 5700h;
BX = дескриптор файла.
На виході:
якщо прапорець CF = 0, тоді в CX і DX інформація про час і дату (табл.12):
CX = час;
DX = дата.
якщо прапорець CF = 1, тоді AX містить код помилки:
AX = 1 заборонений номер підфункції в AL;
АХ = 6 заборонений дескриптор.
Таблиця12 Формат часу і дати створення або модифікації файла
Час |
Дата |
||
Біти |
Опис |
Біти |
Опис |
15-11 |
Години (0-23) |
15-9 |
Рік |
10-5 |
Хвилини |
8-5 |
Місяць |
4-0 |
Секунди |
4-0 |
День |
Встановлення дату і час створення або останньої модифікації файла
На вході:
AX = 5701h;
BX = дескриптор файла;
CX = новий час;
DX = нова дата.
На виході:
якщо прапорець CF = 0, тоді в CX і DX інформація про встановлені час і дату:
CX = час;
DX = дата.
якщо прапорець CF = 1, тоді AX містить код помилки:
AX = 1 недопустимий номер підфункції в AL;
АХ = 6 недопустимий дескриптор.
2.10.15 Робота з дисками, каталогами та організація пошуку файла
Під час роботи з попередніми програмами ми при вказанні імен файлів практично не вказували імен дисководів і шляхів до файлів. Операційна система має у своєму арсеналі засоби для встановлення поточного диску та каталогу, в якому виконуватимуться всі поточні операції з файлами. Та й задача пошуку потрібних файлів за їх маскою є завжди актуальною.
Отримання номера заданого за замовчуванням дисководу
На вході:
AH = 19h.
На виході:
AL = номер дисководу (00h А:, 01h В: і т.д.).
Фрагмент коду, що отримує номер поточного дисководу, може виглядати так:
. . .
.code
. . .
mov ah,19h ;номер функції DOS
int 21h
jc exit ;перехід у випадку помилки
; в al - номер поточного диска
exit:
. . .
Установлення номера дисководу
На вході:
AH = 0Еh.
DL = номер дисковода (00h А:, 01h В: і т.д.).
На виході:
AL = максимально можливий в даній системі номер дисковода (00h А:, 01h В: і т.д.), визначається на основі параметра LASTDRIVE у файлі CONFIG.SYS.
Отримання інформації про вільний дисковий простір
На вході:
AH = 36h;
DL = номер дисковода (00h А:, 01h В: і т.д.).
На виході:
AX = FFFFh - неправильний номер пристрою в DL;
Інакше (якщо дисковод вказано правильно):
AX = число секторів в одному кластері;
BX = число вільних кластерів;
CX = розмір сектора (в байтах);
DX = загальне число секторів на диску.
Таким чином, використовуючи інформацію, яку повертає функція 36h, можна підрахувати такі характеристики:
Створення нового каталога
На вході:
AH = 39h;
DS:DX = ASCII-рядок, вказує шлях до каталогу, що створюється.
На виході:
якщо прапорець CF = 1, тоді AX містить код помилки:
АХ = 3 вказаний шлях не існує;
АХ = 5 доступ заборонений.
Шлях до каталога повинен містити послідовність усіх каталогів. починаючи від кореневого (причому вони повинні існувати). Останнє імя каталога імя каталога, що створюється.
Для прикладу наведемо фрагмент коду програми, що демонструє створення каталога.
. . .
.data
dname db "c:\windows\my_dir",0
ADDR dd dname
. . .
.code
lds dx, ADDR
mov ah,39h
int 21h
jc exit
. . .
exit:
. . .
Знищення каталога
На вході:
AH = 3Ah;
DS:DX = ASCII-рядок зі шляхом до файла, що знищується.
На виході:
якщо прапорець CF = 1, тоді AX містить код помилки:
АХ = 3 вказаний шлях не існує;
АХ = 5 доступ заборонено;
AX = 10h спроба знищення поточного каталогу.
Зауважимо, що каталог, який знищується, повинен бути пустим.
Зміна поточного каталога
MS DOS дозволяє встановити поточний каталог для того, щоб не вказувати повний шлях для наступних операцій з файлами. При необхідності можна отримати повний шлях до поточного каталога у вигляді ASCII-рядка.
На вході:
AX = 3Bh;
DS:DX = покажчик на буфер. що містить повний шлях від кореневого каталога у вигляді ASCII-рядка (до 64 байт).
На виході:
якщо прапорець CF = 1, тоді AX містить код помилки:
АX = 03h шлях не знайдено.
Отримання поточного каталога
На вході:
AH = 47h;
DL = номер пристрою (00h поточний, 01h А: і т.д.).
DS:DX = покажчик на 64-байтовий буфер для запису повного шляху від кореневого каталога (ASCII-рядок).
На виході:
якщо прапорець CF = 1, тоді AX містить код помилки:
AX = 0Fh недопустимий номер дисковода.
Пошук файла за заданим шаблоном
Для пошуку в каталогах використовується пара функцій 4Eh та 4Fh. В імені файла, що розшукується, можуть бути символи шаблону * та ?. Спочатку викликається функція 4Eh. В якості параметрів їй передаються адреса ASCII-рядка, в якому міститься шлях до файла, та комбінація його атрибутів. Імя файла може бути задано у вигляді шаблону. У разі успіху (CF=0), тобто при виявленні першого підходящого до шаблону файла, функція розміщує його імя і розширення в область DTA зі зміщенням 1eh від її початку. Далі можна або відкрити файл, або продовжити пошук, але вже використовуючи функцію 4Fh.
При роботі з шаблоном функцію 4Fh можна викликати циклічно, до тих пір, поки в процесі перебору не будуть розглянуті імена всіх підходящих файлів. Про це можна дізнатися за станом прапорця CF (він прийме значення 1 у випадку, коли файлів, що задовільняють шаблон, в даному каталозі більше немає).
Для першого пошуку файла, що відповідає шаблону, використовується функція 4Eh.
На вході:
AH = 4Eh;
CX = атрибути файла (біти 0 та 5 ігноруються);
DS:DX = ASCII-імя файла (можливо, зi шляхом до нього і символами шаблона * та ?).
На виході:
якщо прапорець CF = 0, тоді в DTA повертається блок даних для першого знайденого файла.
якщо прапорець CF = 1, тоді AX містить код помилки:
АХ = 2 файл не знайдено;
АХ = 3 вказаний шлях не існує;
АХ = 12h більше файлів у каталозі немає.
Область DTA (Data Transfer Area) розташовується у префіксі програмного сегменту зі зсувом 80h від його початку і займає 128 байтів. При успішному завершені пошуку функція 4Eh (і 4Fh також) розміщує блок даних, що має формат, як це вказано у табл.13.
Після аналізу даної області в програмі приймається рішення щодо завершення або продовження пошуку.
Для того, щоб знайти наступний файл, що відповідає шаблону, використовується функція 4Fh.
На вході:
AH = 4Fh;
В області DTA повинен міститися блок даних, заповнений єдиним викликом функції 4Еh на початку пошуку.
На виході:
якщо прапорець CF = 0, тоді операцію виконано успішно;
якщо прапорець CF = 1, тоді AX містить код помилки:
АХ = 12h більше файлів у каталозі немає.
Таблиця 13 Формат і вміст області DTA
Зсув |
Розмір в байтах |
Опис |
00h |
1 |
Буква логічного диску; якщо 7-й біт дорівнює 0, то це віддалений диск |
01h |
11 |
Шаблон пошуку |
0Ch |
1 |
Атрибути пошуку |
0Dh |
2 |
Порядковий номер файла у каталозі |
0Eh |
2 |
Номер кластера початку каталога попереднього рівня |
11h |
4 |
Резерв |
15h |
1 |
Атрибути знайденого файла |
16h |
2 |
Час створення (модифікації) файла |
18h |
2 |
Дата створення файла |
1Ah |
4 |
Розмір файла |
1Eh |
13 |
ASCII-імя файла з розширенням |
Варто зауважити, що для виконання робіт, повязаних з файлами MS DOS надає користувачам можливість встановлювати свою область DTA (функція 2Fh) і встановлювати поточну область DTA (функція 1Ah). При цьому всі зміщення і дані, що формуються функціями 4Eh та 4Fh, залишаються актуальними.
2.10.16 Робота з файлами в MS DOS у випадку довгих імен
Перераховані вище функції працюють в різних версіях «чистої» системи MS DOS (включно до версії 6.22). Операційні системи Windows 95/98/Mil також підтримують свою версію MS DOS, яка має номер 7.0. Вони організують спеціальне середовище для роботи, що називається сеансом DOS, і має у своєму складі засоби для роботи з файловою системою Windows. Ця файлова система, як відомо, відрізняється тим, що повне імя файла може досягати 255 символів. розглянемо деякі засоби середовища MS DOS для роботи з файловою системою Windows.
Для визначення факту того, в якій системі працює програма, можна за результатами роботи таких функцій:
У Windows зявилися додаткові можливості як самої файлової системи, так і засобів щодо керування нею. Основне нововведення підтримка довгих імен. Будь-який файл у цій системі має два імені довге імя та його псевдонім.
Довге імя являє собою ASCII-рядок довжиною до 255 символів. Система формує псевдонім для цього імені форматом 8.3 у відповідності до таких правил: беруться перші 6 символів довгого імені, після них додається символ тильда (~), за якою ставиться деякий порядковий номер. Для першого формата 8.3 це 1. Якщо такий псевдонім вже існує, то порядковий номер чергового псевдоніма буде на 1 більшим. Розширення псевдоніма формується з перших трьох символів розширення довгого імені (якщо воно існує).
Розглянуті в попередніх підрозділах функції для роботи з файлами та каталогами не підтримують довгих імен. Для цього система Windows надає програмам MS DOS аналогічні функції, які мають інші номери. Уважно розглянувши більшість з цих номерів, видно, яким зі старих функцій вони відповідають. Нові номери складаються з 4-х цифр: перші дві 071h, останні дві номер старої функції. Для деяких з цих функцій існують особливості у їх роботі.
У таблиці 14 наведено перелік функцій переривання 21h, що працюють з файлами, які мають довгі імена.
При цьому варто розрізняти способи використання довгих імен у програмах MS DOS та у програмах Windows. Програми MS DOS отримують доступ до довгих імен файлів через додаткові функції переривання 21h. Програми Windows використовують для цього відповідні функції АРІ.
Таблиця 14 Додаткові функції переривання 21h для роботи з файлами. що мають довгі імена
Нова функція int 21h |
Стара функція int 21h |
Призначення функції |
Функція АРІ Win32 |
5704h |
Отримати дату і час останнього доступу |
GetFileTime |
|
5705h |
Встановити дату і час останнього доступу |
SetFileTime |
|
5706h |
Отримати дату і час створення |
GetFileTime |
|
5707h |
Встановити дату і час створення |
SetFileTime |
|
7139h |
39h |
Створити каталог |
CreateDirectory |
713Ah |
3Ah |
Знищити каталог |
RemoveDirectory |
713Bh |
3Bh |
Змінити поточний каталог |
SetCurrentDirectory |
7141h |
41h |
Знищити файл |
DeleteFile |
7143h |
43h |
Отримати або встановити атрибути файла |
GetFileAttributes SetFileAttributes |
7147h |
47h |
Отримати поточний каталог |
GetCurrentDirectory |
714Eh |
4Eh |
Знайти перший файл |
FindFirstFile |
714Fh |
4Fh |
Знайти наступний файл |
FindNextFile |
7156h |
56h |
Перейменувати файл |
MoveFile |
7160h |
60h |
Отримати повний шлях |
GetFullPathName |
7160h |
Отримати повний шлях з короткими іменами |
GetShortPathName |
|
7160h |
Отримати повний шлях з довгими іменами |
Відсутній |
|
716Ch |
3Ch 3Dh 5Bh |
Створити або відкрити файл |
CreateFile OpenFile |
71A0h |
Отримати інформацію про том |
GetVolumeInformation |
|
71A1h |
Завершити пошук |
FindClose |
Лабораторна робота № 11
Керування пристроєм “миша”
Тема: Знайомство з можливостями для керування пристроєм “миша”. Керування роботою миші у графічному та текстовому режимах.
Теоретичні відомості
2.11.1 Ініціалізація та визначення поточного стану драйвера
пристрою “миші”
Для керування пристроєм “миша” використовуються різноманітні функції переривання 33Н. Більшість сучасних драйверів “миші” підтримують стандарт, введений фірмою Microsoft для різних функцій переривання 33Н. Більшість систем програмування мають у своєму складі бібліотечні функції. що виконують звернення до будь-якої функції переривання 33Н. Бібліотечні функції працюють повільніше, ніж безпосереднє звернення до переривання 33Н з прикладної програми. Окрім того, програмісти часто використовують неповні або ж навіть несанкціоновані копії систем програмування, в яких бібліотеки підтримки пристрою відсутні або працюють некоректно. Тому надалі наводяться приклади безпосереднього звернення до переривання 33Н, а не бібліотечні функції.
Кожна програма, що використовує для введення інформації пристрій “миша”, повинна виконати ряд підготовчих дій, а саме:
Нижче наводиться специфікація цієї функції.
На вході: АХ = 0000h.
На виході: АХ = стан пристрою “миші” (0000h драйвер “миші” відсутній, тобто відсутня апаратура або не завантажено драйвер; FFFFh “миша” готова до роботи).
ВХ = кількість кнопок пристрою (0000h не дві кнопки;
0002h дві кнопки, режим Microsoft mode;
0003h три кнопки, режим Mouse Systems mode).
При виконанні функції АХ=0000h драйвер пристрою приводиться в стан за замовчуванням:
Якщо необхідно встановити значення, що відрізняються від значень за замовчуванням, використовуються функції установлення форми курсора, межі його переміщення, установлення значень чутливості і межі подвоєної швидкості.
При визначенні дієздатності “миші”, за допомогою функції АХ=0000h варто прийняти до відома такі зауваження:
Драйвери “миші” в текстовому режимі роботи відеоадаптера підтримують два види курсора:
Курсор “миші” в текстовому режимі переміщується по знакомісцях екрана. Вибір типу і параметрів курсора в текстовому режимі роботи відеоадаптера виконається за допомогою функції АХ=000Аh переривання 33h, специфікація якої наведена нижче.
На вході:
АХ = 000Аh установлення курсора “миші” в текстовому режимі;
ВХ вибір типа курсора (00 курсор, що програмується;
01 “жорсткий” курсор).
СХ = AND-маска (маска екрана) для курсора, що програмується, або номер верхньої скен-лінії для “жорсткого” курсора.
DX = XOR-маска (маска курсора) для курсора, що програмується, або номер нижньої скен-лінії для “жорсткого” курсора.
На виході: функція нічого не повертає.
Якщо вибрано “жорсткий” курсор, то курсор “миші” на екрані має форму звичайного текстового. Перевагою такого курсора є те, що на екрані присутній лише один звичний курсор і при виконанні будь-якої операції введення інформації з використанням функцій MS DOS (наприклад, функцій стандартного введення-виведення) курсор “миші” автоматично переміщується в поточну текстову позицію BIOSа. Це не означає, що драйвер “миші” при переміщення курсора оновлює слово поточної позиції курсора в області даних BIOSа. Тому без додаткових зусиль з боку програміста не вдається розмістити символ на екрані в позицію, на яку вказує курсор “миші”.
При формуванні текстового курсора, що програмується, використовуються:
а) слово відеопамяті, утворене символом та атрибутом знакомісця екрана, в якому знаходиться курсор пристрою (screen_word);
б) AND-маска (AND_mask); в) XOR-маска (XOR_mask). Результуюче представлення курсора на екрані формується порозрядними логічними операціями за формулою:
screen_word = screen_word AND AND_mask XOR XOR_mask .
При переміщенні курсора в іншу позицію попередній вміст відео- буфера відновлюється. Таким чином, користувач може встановлювати різні форми програмованого текстового курсора “миші”. Наприклад, якщо задати AND_mask=00FFh та XOR_mask=xx00h, то текстовий курсор буде у вигляді прямокутника, що зберігає будь-який попередній символ, атрибут якого буде хх. Молодша шістнадцяткова цифра буде задавати колір контуру символу, а старша колір фону. Але при цьому можливе “зникнення” курсора, коли атрибут символу вже був рівний хх.
Розповсюдженим є програмований текстовий курсор із такими значеннями: AND_mask = FFFFh та XOR_mask = 7700h. У цьому випадку інвертується і колір фону, і колір атрибута, що гарантує видимість курсора і не змінює символ в позиції курсора.
Неважко добитися того, щоб курсор “миші” на екрані відображався у вигляді потрібного символу. Наприклад, для того, щоб текстовий курсор набув форму “галочки” (ASCII-код символу FBh), необхідно задати такі значення масок: AND_mask = 0000h та XOR_mask = xxFBh. де хх задає атрибут символу курсора. Загальновживаною є практика зміни форми курсора для індикації натискання тієї або іншої кнопки пристрою “миші”.
У графічному режимі роботи відеоадаптера може бути описана будь-яка власна форма курсора в межах прямокутника 16×16 пікселів. Курсор у графічному режимі описується двома масками розміром 16×16 бітів кожна. Одна з масок називається AND-маскою (маскою екрана), інша - XOR-маскою (масою курсора). При переміщенні курсора попередній вміст екрана відновлюється драйвером “миші”. Маски, комбінуючись, визначають метод обробки поточного коду кольору піксела на екрані. Результати обробки представлені в таблиці 15.
Таблиця 15 Формування коду кольору пікселів відображення курсора “миші” у графічному режимі
Біт AND-маски |
Біт XOR-маски |
Колір піксела на ерані |
0 |
0 |
Колір фону |
0 |
1 |
Білий колір |
1 |
0 |
Поточний колір піксела |
1 |
1 |
Побітова інверсія поточного кольору піксела |
За допомогою різних масок можна встановити будь-яку форму курсора і добитися його видимості на будь-якому фоні. Для режимів 4, 5 та 13h використовуються тільки парні стовпчики в бітових масках: в іншому випадку курсор при використанні матриці 16×16 мав би занадто великі розміри. Для інших режимів “проріджування” стовпчиків масок курсора не виконується.
У графічних режимах, окрім форми курсора, описується так звана “гаряча пляма” (hot spot) у відносних координатах, за точку відліку яких прийнято верхній лівий кут прямокутника 16×16 пікселів. “Гаряча пляма” це той піксел, на який вказує в даний момент графічний курсор. Опис курсора “миші” у графічному режимі виконує функція АХ=0009h переривання 33h. Наведемо специфікацію цієї функції.
На вході:
АХ = 0009h установлення курсора “миші” в графічному режимі.
ВХ = номер стовпчика “гарячої плями” курсора відносно верхнього лівого кута прямокутника курсора.
СХ = номер рядка “гарячої плями” курсора відносно верхнього лівого кута прямокутника курсора.
ES:DX = покажчик на 32 слова масок: перші 16 слів утворюють AND-маску, наступні 16 слів XOR-маску. Використання бітів цих масок ілюструє табл..14.
На виході: функція нічого не повертає.
Для отримання графічного курсора, який би було видно на будь-якому фоні, поступають таким чином. Маску екрана (AND-маску) задають такою, що складається зі слів FFFFh, а маску курсора (XOR-маску) описують так, щоб у ній стояли одиниці у тих бітах, які утворюють обриси курсора, і нулі в усіх інших бітах маски. Як приклад наведемо створення курсора у вигляді нахиленої стрілки. Формування бітової карти цього курсора пояснюється на рис.22.
Відразу після ініціалізації екрана областю допустимих переміщень курсора за замовчуванням приймається весь екран. Але завжди є можливість обмежити переміщення курсора окремо по горизонталі та по вертикалі, для цього програма використовує функції АХ=0007h та АХ=0008h переривання 33h.
Бітова карта курсора |
Двійкове подання |
Шістнадцяткове подання |
|||||||||||
1000 0000 0000 0000 |
0x8000 |
||||||||||||
1100 0000 0000 0000 |
0xC000 |
||||||||||||
1010 0000 0000 0000 |
0xA000 |
||||||||||||
1001 0000 0000 0000 |
0x9000 |
||||||||||||
1010 1000 0000 0000 |
0xA800 |
||||||||||||
1011 0100 0000 0000 |
0xB400 |
||||||||||||
1011 1010 0000 0000 |
0xBA00 |
||||||||||||
1011 1101 0000 0000 |
0xBD00 |
||||||||||||
1011 1110 1000 0000 |
0xBE80 |
||||||||||||
1011 1111 0100 0000 |
0xBF40 |
||||||||||||
1011 1111 1010 0000 |
0xBFA0 |
||||||||||||
1011 1111 1101 0000 |
0xBFD0 |
||||||||||||
1011 1111 1110 0000 |
0xBFE0 |
||||||||||||
1010 1110 0000 0000 |
0xAE00 |
||||||||||||
1010 0011 0000 0000 |
0xA300 |
||||||||||||
1110 0011 0000 0000 |
0xE300 |
||||||||||||
Рисунок 12 XOR-маска зображення курсора у вигляді стрілки |
На вході:
АХ=0007h установлення вертикальних границь переміщення (обмежують горизонтальне переміщення курсора “миші” по екрану);
AX=0008h - установлення горизонтальних границь переміщення (обмежують вертикальне переміщення курсора “миші” по екрану);
CX = мінімальна границя переміщення курсора “миші”;
DX = максимальна границя переміщення курсора “миші”.
На виході: функція нічого не повертає.
При роботі у графічному режимі границі переміщення задаються у пікселах. Для текстового режиму вони задаються у віртуальних пікселах (виходять з того, що знакомісце незалежно від режиму і типу адаптера займає матрицю 8×8 умовних пікселів). Тому для текстового режиму 25×80 максимально можливими границями переміщення по вертикалі (функція АХ=0008h) є значення СХ=0 і DX=199, а по горизонталі (функція АХ=0007h) СХ=0 і DX=639. Для текстового режиму 50×80 (VGA- та MCGA-адаптери) граничні значення такі: по вертикалі (функція АХ=0008h) є значення СХ=0 і DX=399, по горизонталі (функція АХ=0007h) СХ=0 і DX= 639. У разі. коли мінімальна границя більша за максимальну, функції міняють місцями значення у регістрах CX та DX. Якщо в момент установлення нової границі курсор пристрою знаходиться поза межами заданого діапазону переміщення, він “стрибає” до найближчої з границь.
При переміщенні пристрою “миша” по столу пропорційно руху переміщається і курсор “миші”. Регулювати швидкість переміщення курсора по екрану дозволяють пороги чутливості, що визначають число “міккі”, яке необхідно прийняти драйверу для переміщення курсора на один піксел по горизонталі або по вертикалі. Менше значення чутливості робить курсор “миші” більш рухливим. Наприклад, при переміщенні курсора по вертикалі вниз з верхньої лінії до нижньої у графічному режимі 10h (350 рядків) і при чутливості 1 міккі/піксел, для стандартної “миші” 200 міккі/дюйм необхідно перемістити пристрій на 350/20025 = 44 мм. Для переміщення курсора зліва направо при тих самих параметрах необхідно переміщення “миші” по столу на 640/20025 = 80 мм. Для установлення чутливості драйвера використовується функція АХ=000Fh, специфікація якої наведена нижче.
На вході:
AX = 000Fh установлення чутливості драйвера “миші” по горизонталі та по вертикалі;
CX чутливість драйвера “миші” по горизонталі в міккі на 8 пікселів;
DX чутливість драйвера “миші” по вертикалі в міккі на 8 пікселів.
На виході: функція нічого не повертає.
Мінімальне можливе значення для CX та DX дорівнює 1, що відповідає просто “реактивній” швидкості. Навіть випадкові рухи на столі будуть приводити до переміщення курсора “миші”. Висока чутливість драйвера спрощує переміщення курсора на великі “відстані” по екрана, але одночасно утруднює установлення курсора точно в задану позицію на екрані. Наведене протиріччя між швидкістю і точністю позиціонування реалізується драйвером “миші” за допомогою алгоритму балістичного курсора. Ідея цього алгоритму полягає у наступному. Якщо “миша” переміщується по столу з високою швидкістю, то інформаційні слова в адаптер поступають з високою частотою. При досягненні “мишею” так званого порога подвоєної швидкості драйвер починає подвоювати кожний прийнятий сигнал при переміщенні. В результаті вдвічі зростає швидкість переміщення курсора пристрою на екрані. При зменшенні швидкості переміщення пристрою нижче згаданого порогу, подвоєння припиняється і курсор по екрану пересувається зі швидкістю. що визначається параметрами чутливості. Іншими словами, для “далекого” переміщення курсора по екрану треба здійснити “мишею” по столу різкий рух у потрібному напрямку, а потім повільно підвести курсор у потрібну точку. Установлення власного значення порогу подвоєної швидкості виконує функція AX=0013h.
На вході:
AX=0013h установлення значення порогу подвоєної швидкості DX поріг подвоєної швидкості курсора “миші”, міккі/с.
На виході: функція нічого не повертає.
(за замовчуванням поріг подвоєної швидкості курсора дорівнює 64 міккі/с);
Для визначення поточних параметрів чутливості і порогу подвоєної швидкості курсора “миші” використовується функція AX=001Bh.
На вході:
AX = 001Bh визначення поточних значень чутливості по горизонталі та по вертикалі;
На виході:
BX чутливість драйвера по горизонталі (міккі на один піксел);
CX чутливість драйвера по вертикалі (міккі на один піксел);
DX поріг подвоєної швидкості курсора “миші”, тобто кількість міккі в секунду, при досягненні якого швидкість переміщення курсора по екрану подвоюється (за замовчуванням поріг подвоєної швидкості курсора дорівнює 64 міккі/с).
2.11.5 Керування станом курсора “миші” (видимий та невидимий курсор)
Після проведеної ініціалізації програма повинна “включити” курсор, що робить його видимим на екрані. Ця операція деблокує секцію обробника переривань від адаптера, яка працює з відеопамяттю. Відразу після ініціалізації курсор виключений, стан курсора відслідковує спеціальна внутрішня змінна, що встановлюється після ініціалізації “миші” в 1. Керування внутрішнім прапорцем здійснюють дві функції переривання 33h:
- AX=0001h, що робить курсор видимим, тобто змінює на 1 прапорець видимості;
- AX=0002h, яка робить курсор невидимим, тобто зменшує на 1 прапорець видимості.
Якщо прапорець уже дорівнює 0, його подальше збільшення функцією AX=0001h не виконується. Але функція AX=0002h зменшує прапорець, навіть якщо він уже рівний 1. У звязку з цим відразу після ініціалізації виконується функція включення курсора і на кожну наступну операцію включення повинна приходитися рівно одна (і ніяк не більше) операція виключення. В протилежному випадку курсор “миші” не буде зявлятися на екрані після його включення.
Всі зміни інформації на екрані слід виконувати з виключеним курсором для запобігання непередбачених ускладнень. справа у тому. що зміни, проведені точно під курсором “миші”, не будуть “відомі” драйверу курсора і при переміщенні у нову позицію екрана драйвер відновить не нове, а попереднє значення відеопамяті. Після виконання змін на екрані слід знову включити курсор. Виключення курсора скидає як форму, так і установлення “гарячої плями” графічного курсора.
2.11.6 Читання позиції курсора і стану кнопок “миші”
Після того, як виконано всі необхідні підготовчі операції, програма може використовувати пристрій “миші” для введення інформації. Інформація, що вводиться, це поточна позиція курсора і стан кнопок пристрою. Періодичне введення інформації з “миші” і попадання курсора в ті або інші області екрана дозволяє виконувати потрібні дії: відкривати підменю, виконувати заливку якимось кольором та багато чого іншого. Визначення стану кнопки (натиснута, відпущена, натиснута двічі) використовується як команда на виконання програмою додаткових дій. В наш час склався певний стандарт використання кнопок “миші”. Наприклад, натискання лівої кнопки (для “правши”) означає вибір того чи іншого пункту меню або включення якогось режиму. У багатьох прикладних програмах натискання лівої кнопки аналогічне натисканню клавішi ENTER. Швидке дворазове натискання лівої або правої кнопки пристрою у деяких випадках використовується як додаткова команда на виконання будь-яких дій програми, наприклад, запуск будь-якої програми на виконання. Права кнопка, навпаки, відміняє зроблений раніше вибір, тобто часто служить аналогом клавіші клавіатури ESC.
Для визначення поточного стану пристрою використовуються функції AX=0003h; 0005h; 0006h; 000Bh.
На вході:
AX = 0003h визначення місцеположення курсора і стану кнопок пристрою.
На виході:
BL = байт стану кнопок пристрою:
біт 0: 1 натиснуто ліву кнопку, 0 не натиснуто ліву кнопку);
біт 1: 1 натиснуто праву кнопку, 0 не натиснуто праву кнопку);
біт 2: 1 натиснуто середню кнопку (для Mouse System), 0 не натиснуто;
біти 3-7 не використовуються;
CX = горизонтальна координата курсора “миші” (номер стовп-чика на екрані);
DX = вертикальна координата курсора (номер рядка на екрані).
У графічному режимі повертаються піксельні координати, а у текстовому віртуальні піксельні координати (див. опис функцій AX=0007h та AX=0008h), і для отримання номерів текстового рядка і стовпчика слід розділити значення, які повертаються у регістрах СX та DX, на число 8.
На вході:
AX = 0005h визначення кількості натискань кнопок “миші”;
AX = 0006h визначення кількості відпускань кнопок “миші”;
BХ ідентифікатор кнопки пристрою:
= 0 запит про ліву кнопку;
= 1 запит про праву кнопку;
= 2 запит про середню кнопку (для Mouse Systems).
На виході:
ВХ = кількість натискань (відпускань) кнопок пристрою з моменту останнього звернення до функцій або з моменту ініціалізації “миші”, якщо запит виконується вперше;
CX = горизонтальна координата курсора “миші” (номер стовпчика на екрані) в момент натискання вказаної кнопки;
DX = вертикальна координата курсора (номер рядка на екрані) в момент натискання вказаної кнопки.
У графічному режимі повертаються піксельні координати, а у текстовому віртуальні піксельні координати (див. опис функцій AX=0007h та AX=0008h), і для отримання номерів текстового рядка і стовпчика необхідно розділити значення, які повертаються у регістрах СX та DX, на число 8. Лічильник кількості натискань (відпускань) зберігає значення від 0 по EFFFh. Після виклику функції AX=0005h або AX=0006h відповідний лічильник занулюється.
На вході:
AX = 000Bh визначення значення лічильників сигналів міккі.
На виході:
CX = переміщення курсора миші по горизонталі в міккі з моменту останнього виклику даної функції або з моменту ініціалізації “миші”, якщо запит виконується вперше;
DX = переміщення курсора миші по вертикалі в міккі з моменту останнього виклику даної функції або з моменту ініціалізації “миші”, якщо запит виконується вперше.
Значення, що містять регістри СX та DX на виході, мають цілий тип. Відємні значення відповідають руху курсора вліво або донизу, додатні вправо або вгору. Після кожного виклику функції значення лічильників занулюються. Для перерахунку значень лічильників у пікселі графічного режиму або у віртуальні пікселі текстового режиму використовується функція AX=001Вh, яка визначає поточне значення чутливості по горизонталі та по вертикалі.
При переміщенні пристрою по столу драйвер переміщає курсор “миші” по екрана без будь-якої участі програми. Однак і прикладна програма має можливість керувати позицією курсора “миші”, для цього використовується функція AX=0004h.
На вході:
AX = 0004h установлення курсора “миші” і внутрішніх лічильників позиції в нове місце на екрані;
CX = горизонтальна координата курсора “миші”;
DX = вертикальна координата курсора “миші”.
На виході: функція нічого не повертає.
Нові координати задаються для графічного режиму в пік селах, а для текстового у віртуальних пікселах. Тому при необхідності установлення пристрою в потрібні текстовий рядок або стовпчик їх номери множаться на число 8. Дана функція не перетинає границі, встановлені функціями AX=0007h та AX=0008h. При запиті позиціонування на точку екрана поза діапазонами переміщення курсора останній “натикається” на найближчу границю, але не перетинає її.
Наявність функції керування позицією курсора “миші” дозволяє організувати керування єдиним курсором на екрані як самим пристроєм, так і з клавіатури. Така можливість керування рухами курсора часто використовується при побудові різноманітних текстових редакторів. Функція прийому клавіатурного введення постійно аналізує поточну позицію курсора “миші” і приводить у відповідність до неї позицію текстового курсора BIOSа. При натисненні клавіш клавіатури зі стрілками (Left, Right, Up, Down і ін.) виконується позиціонування курсора “миші”. Розглянуті дії приводять до того, що поточна позиція курсора, відома BIOSу для виведення інформації на екран, керується як пристроєм, так і клавішами зі стрілками.
2.11.8 Приклад програми для керування пристроєм “миша”
у текстовому режимі роботи відеоадаптера
Наведена нижче програма демонструє принципи програмування пристрою “миша” з використанням функцій переривання INT 33h.
При одночасному виконанні двох умов попаданню текстового курсора “миші” у прямокутник екрана дисплея з координатами лівого верхнього кута X1=6, Y1=1, координатами правого нижнього кута X2=25, Y2=8, та натисненні лівої клавіші “миші” на екран дисплея виводиться рядок символів *.
NAME MOUSE5
.MODEL TINY
CODE SEGMENT
ASSUME CS:CODE
ORG 100H
BEGIN: JMP MAIN
PRESS DW ?
X DW ?
Y DW ?
MAIN PROC
MOV AX,0
INT 33H
MOV AX,1
INT 33H
MOV PRESS,0
M1: MOV AX,3
INT 33H
MOV PRESS,BX
MOV X,CX
MOV Y,DX
CMP X,48
JL M1
CMP X,200
JG M1
CMP Y,8
JL M1
CMP Y,200
JG M1
CMP PRESS,1
JNE M1
CALL OUTPUT
RET
MAIN ENDP
OUTPUT PROC
MOV AH,2
MOV DH,10
MOV DL,5
MOV BH,0
INT 10H
MOV AH,9
MOV AL,'*'
MOV CX,40
MOV BL,0E1H
INT 10H
RET
OUTPUT ENDP
CODE ENDS
END BEGIN
1. Григорьев В. Л. Программирование однокристальных микропроцессоров. М.: Энергоатомиздат, 1987.
Виконання програми (або налагодження)
Завантажувач
Операційна система
Налагоджувач
Компонування програми
(створення
завантажувального
модуля)
Завантажувальний модуль .ЕХЕ або .СОМ
Карта завантаження .MAP
Cтворення обєктного модуля
(трансляція програми)
Транслятор
Файл перехресних посилань .CRF
Лістинг .LST
Обєктний модуль .OBJ
Компонувач
Введення вхідного
тексту програми
Текстовий
редактор
Вхідний модуль
.ASM
Рисунок 4 Загальна схема виконання найпростішої одномодульної програми
MOD1
MOD2
extrn var2: word
Public var1
- - - - - - - - - - - - - - - - - - - - - - - - -
… … …
var1 db 8
… … …
xtrn var1: byte
Public var2
- - - - - - - - - - - - - - - - - - - - - - - - -
… … …
var2 dw 6
… … …
Рисунок 5 Приклад взаємозвязків між зовнішніми модулями