Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Книга. Гуржій. 1.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
3.53 Mб
Скачать

Заняття 8. Особливості практичного використання апаратних та програмних переривань

Тема заняття

Вимоги до розробки оброблювачів переривання програм.

Мета заняття

Зрозуміти та засвоїти відмінності в розробці рези­дентних та нерезидентних оброблювачів переривання.

Навчитись коректно змінювати таблицю векторів переривання.

Вивчити методи використання свопінгу в резидент­них програмах.

Засвоїти спосіб визначення "безпечного" моменту часу для використання дисків при свопінгу.

Написання власного оброблювача переривання

Існує кілька причин для написання власного перериван­ня. Наприклад, багато Ваших програм можуть використо­вувати процедуру, що формує на екрані дисплея вертикальні рядки символів. Замість того, щоб включати її в кожну програму в якості процедури, Ви можете встановити її як переривання, написавши програму, яка стане резидентною в пам'яті та буде викликатися за необхідністю різними програмами.

Якщо Ваш програмний комплекс повинен працювати в реальному часі, відстежуючи деякі події, Вам не обійтись без використання якого-небудь окремого апаратного пере­ривання, в якості зміни вектора переривання для замі-нення стандартного оброблювача своїм.

Часто виникає необхідність написання переривань, які повністю замінюють або модифікують ту чи іншу процедуру операційної системи, пристосовуючи її до умов конкретних програм користувача.

Зміна таблиці векторів переривань

Вашій програмі може знадобитись організувати оброб­ку деяких переривань. Для цього програма повинна пере назначити вектор на свій оброблювач. Це можна зробити, змінивши вміст відповідного елемента таблиці векторів переривань. Дуже важливо не забути перед завершенням роботи відновити вміст змінених векторів у таблиці переривань, так як після завершення роботи програми пам'ять, яка була їй розподілена, вважається вільною та може бути використана для завантаження іншої програми. Якщо ви забули відновити вектор і прийшло переривання, то система може зруйнуватись, так як вектор тепер вказує на область, яка може містити що завгодно.

Тому послідовність дій для нерезидентних програм, що бажають обробляти переривання, повинна бути такою:

прочитати вміст елемента таблиці векторів пере­ривань для вектора з потрібним Вам номером;

запам'ятати цей вміст (адреса старого оброблювача переривання) в області даних програми;

встановити нову адресу в таблиці векторів перери­вань так, щоб вона відповідала початку Вашої програми обробки переривання;

перед завершенням роботи програми прочитати з об­ласті даних адресу старого оброблювача переривання та записати його в таблицю векторів переривань.

Крім цього, операція зміни вектора переривання повинна бути безперервною в тому розумінні, що під час зміни не повинно відбутися переривання з номером, для якого здійснюється заміна програми обробки. Якщо Ви, наприклад, запишете нове значення зміщення, а сегментну адресу поновити не встигнете, то за якою адресою буде передано керування у випадку переривання і що при цьому відбудеться? Про це можна тільки здогадуватись.

Для полегшення роботи після заміни переривання DOS надає у Ваше розпорядження спеціальні функції для читання елемента таблиці векторів переривання та для запису в неї нової адреси. Якщо Ви будете використовувати ці функції, DOS гарантує, що операція після заміни вектора буде виконана правильно. Вам не потрібно турбуватись про безперервність процесу заміни вектора переривання.

Для читання вектора використовуйте функцію 35h переривання 21h- Перед її викликом регістр AL повинен містити номер вектора в таблиці. Після виконання функції в регістрах ES:BX буде шукана адреса оброблювача переривання.

Функція 25h переривання 21h встановлює для вектора з номером, що знаходиться в AL, оброблювач переривання DS:DX.

Звичайно, Ви можете безпосередньо звертатись до таблиці векторів переривань, але тоді під час запису необхід­но замаскувати переривання командою CLI, не забувши дозволити їх після запису командою STI.

Для користувачів мови Сі бібліотека Quick C містить функції _dos_getvec(), _dos_setvect(). Перша функція отримує адресу з таблиці векторів переривань, друга встановлює нову адресу.

Якщо Вам треба додати які-небудь власні дії до тих, що виконує стандартний оброблювач переривання, то можна організувати ланцюг переривань.

Для організації ланцюга переривань Ви записувати­мете у векторну таблицю адресу свого оброблювача, не забувши зберегти попередній вміст таблиці. Ваш оброблю­вач отримує керування по перериванню, виконує будь-які дії, далі передає керування стандартному оброблювачеві.

Можна зробити це інакше: Ваш оброблювач викликає стандартний як підпрограму, після повернення зі стандартного оброблювача виконує додаткові дії, тобто Ви можете вставити додаткову обробку як до виклику стандартного оброблювача, так і після його виклику.

У бібліотеці Quick C є функція для організації ланцюга переривань _chain_intr().

Розглянемо детальніше можливості бібліотеки інте­грованого середовища Quick C, призначеного для роботи з перериваннями.

Модифікатор interrupt (_interrupt для Quick C 2.5 та С 6.0) описує функцію, яка є оброблювачем переривання. Така функція завершується командою повернення з обробки переривання IRET, та для неї автоматично генеруються команди збереження регістрів на вході та їх відновлення при виході з оброблювача переривання. Приклад використання модифікатора для опису функції обробки переривання: void interrupt far int_funct(void) {

// Тіло оброблювача переривання

Функція обробки переривання повинна бути FAR функцією, так як таблиця векторів переривання містить повні адреси у вигляді сегмент: зміщення.

Ключове слово interrupt використовується також для опису змінних, що призначені для зберігання векторів переривань: void (_interrupt _far *oldvect)(void); Модифі­катори _interrupt та _far для Quick C 2.5 та С 6.0 є синонімами відповідно interrupt та far.

Які вимоги висувають до програми обробки пере­ривання?

Якщо переривання здійснюються часто, то їх обробка може сильно уповільнити роботу прикладної програми. Тому оброблювач переривання повинен бути короткою швидко працюючою програмою !!!, яка виконує тільки найнеобхідніші дії. Наприклад, зчитати черговий символ з порту принтера та помістити його в буфер, збільшити значення якого-небудь глобального лічильника переривань.

Для встановлення свого оброблювача переривань використовуйте функцію _dos_setvec. Ця функція має два параметри: номер переривання та покажчик на нову функцію обробки переривання.

Наприклад: dos_setvect(0xl6, my_key_intr);.

У цьому прикладі для клавіатурного переривання з но­мером 16h встановлюється новий оброблювач переривання my_key_intr.

Якщо Вам потрібно взнати адресу старого оброблю­вача переривання за його номером, найкраще скористатися функцією _dos_getvect, яка приймає в якості параметра номер переривання та повертає покажчик на оброблювач відповідний цьому номеру в таблиці векторів переривань. Наприклад: old_vector = _dos_getvect(0xl6); .

Для організації ланцюга переривань використовуйте функцію _cha in_intr. В якості параметра ця функція приймає адресу старого оброблювача переривань.

Наступний простий приклад ілюструє застосування всіх трьох функцій, призначених для роботи з перериваннями.

Ця програма встановлює власний оброблювач переривання таймера, який буде викликатись приблизно 18,2 рази за секунду. Цей оброблювач переривання рахує тіки таймера, і якщо значення лічильника кратне 20, на динамік комп'ю­тера видається звуковий сигнал. У кінці роботи нова програма обробки переривання таймера викликає старий оброблювач за допомогою _chain_intr.

Після встановлення нового оброблювача переривання таймера основна програма чекає натискання будь-яких клавіш клавіатури, далі вона відновлює старий вміст вектора переривання. #include <dos.h> #include <stdio.h>

#include <stdlib.h> //Вимикаємо перевірку стека

#pragma check_stack( off ) //та покажчиків #pragma check_pointer ( off )

//Це макро використовується для видачі сигналу //на внутрішній динамік комп'ютера. Використовується //вивід у форматі TTY символу BELL (7) через //переривання BIOS 10h #define BEEPO _asm { \

_asm mov bx,0 \

_asm mov ax, 0E07h \

_asm int lOh \

}

void main(void);

//Оголошення програми обробки переривання void _interrupt _far timer(void);

//Ця змінна призначена для зберігання старого //значення вектора переривання таймера. Вона //повинна бути глобальною void (_interrupt _far *oldvect)(void);

//Змінна для підрахунку тіків таймера