Переривання – це деяка особлива подія, яка потребує швидкої реакції процесора. Переривання бувають апаратні та програмні. В процесі роботи в будь-який момент (асинхронно) може виникнути апаратне переривання - з’явитися сигнал про якусь подію в тому чи іншому пристрої (була натиснута клавіша або віддруковано символ на принтері). Комп’ютер складається з декількох пристроїв, які працюють з різною швидкістю. Якраз обробка переривань дозволяє сполучити повільно та швидко працюючі пристрої. При виконанні програм виникають заплановані чи не заплановані переривання. Так програміст може перевірити готовність принтера до роботи (це заплановане переривання). При обчислені виразу може виникнути ситуація ділення на 0 (незаплановане переривання). При виникненні переривання виконання поточної програми зупиняється, і процесор приступає до виконання спеціальної програми його обробки. Кожне переривання має свій номер від 0 до 255. Щоб зв’язати номер переривання з відповідною підпрограмою його обробки, використовується таблиця векторів переривань. Таблиця розміщується на початку оперативної пам’яті (від адреси 0000:0000 до 0000:03ff) і складається з 256 елементів, кожен з яких адреса відповідної підпрограми. Ця таблиця формується після тестування апаратури при завантаженні операційної системи. Після обробки переривання відновлюється виконання поточної програми так, неначе його й не було. В програмах можуть бути так звані критичні ділянки – такі послідовності команд, які повинні бути обов’язково виконані. Щоб переривання не зупинило ці команди, треба зупинити обробку переривання на цей час. Це можна зробити командою Асемблера CLI, а для відновлення обробки переривань вживають команду STI. Таку операцію називають маскуванням переривань. Але не всі переривання можна маскувати (тобто тимчасово не виконувати їх обробку).
Команда CLI забороняє виконання всіх маскованих переривань. Це не завжди зручно, тому є можливість заборонити виконання тільки деяких переривань, скориставшись послугами контролеру переривань.
У апаратних переривань має місце одна особливість – їх можна виконувати відразу декілька. Щоб процесор зумів розібратися, яке з них виконувати першим, існує спеціальна схема приорітетів. Кожне переривання має свій рівень приорітетності, процесор в першу чергу обробить переривання з найбільшим приорітетом, а вже потім інші. Нижче перелічені переривання розміщені в порядку зменшення приорітету. Переривання від таймеру, клавіатури, контролера дисплея, математичного сопроцесора, твердого диску, послідовного порта СОМ1, принтера. Застосування механізму переривання дозволяє створити достатньо гнучкі програми від постого тестування пристроїв до розробки резидентних програм. Мова ТР придатна для таких задач, хоча іноді доводиться вживати деякі команди Асемблера. Модуль DOS бібліотеки turbo.tpl має декілька конструкцій для роботи з перериваннями. В ньому описано спеціальний тип Registers для доступу до регістрів центрального процесора комп’ютера.
Type registers=record
Case integer of
0: (AX,BX,CX,DX,BP,SI,DI,DS,ES,FLAGS:word);
1: (AL,AH,BL,BH,CL,CH,DL,DH:byte);
end;
Змінні такого типу дозволяють звертатися до 16 або 8 розрядних регістрів під час роботи з перериваннями. Якщо описати зміну var reg:registers; то це дозволить вживати складені імена REG.AX, REG.BX для передачі даних до відповідного регістру або для того, щоб витягти з них дані. Першу з вказаних операцій можна виконати у звичайному операторі присвоєння:
Reg.AH:=$1A {шістнадцятирічне число записане до АН}
Витягти дані з регістру іноді непросто. Доводиться вживати штучні засоби. Вказані операції використовуються при виклику спеціальних підпрограм. Підпрограма Intr (Nom:byte:var reg: registers) активізує програмне переривання за номером Nom, допоміжна інформація зберігається в деяких регістрах змінної Reg. Перед викликом підпрограми в окремі регістри записуються потрібні данні, а після виклику потрібно проаналізувати відповідний регістр. В який регістр що записати і в якому регістрі шукати результати обробки переривань, залежить від конкретного номеру переривання. Відомості про це можна знайти:
1 Джордейн „ Справочник програмиста персон. комп-ов IBM PC”.
2 Рудаков, Финогенов „ Язык асемблера: уроки програмир.”.
Розглянемо приклади застосування переривань, пов’язаних з різними пристроями ЕОМ.
Uses dos;
Var reg:registers;
Pam:integer
Begin
Intr($12,reg);
Pam:=reg.AX;
Writeln(‘пам’ять=’,pam);
End.
Щоб дізнатись обсяг оперативної пам’яті комп’ютера, достатньо викликати переривання за номером ($12), результат обробки буде повернуто до регістру АХ. Після виконання такої програми на екрані буде відображено текст пам’ять=639 (зрозуміло, що число може бути іншим).
Розглянемо особливості використання переривання за номером $17 (обслуговування принтера). Воно може виконати одну з трьох операцій в залежності від коду, записаного до регістру АН перед викликом переривання. Для друкування одного символу в цей регістр треба записати код $0. Для ініціалізації принтера до регістру АН записують код $01 (це значить, що будуть активізовані схеми, які відповідають за зв’язок з принтером). Після виконання переривання можна проаналізувати окремі розряди цього ж регістру. Якщо перед викликом переривання в регістрі АХ записати код $02, то в цьому регістрі буде повернуто статус принтера. Розряд з номером 0 буде встановлено в 1, якщо виникне ситуація Time Out, тобто за деякий час (достатній для переміщення однієї сторінки паперу) принтер не зміг виконати команду. Розряд з номером 3 буде рівним 1, якщо виникла помилка друкування (на пристрій поступив код управління незрозумілий для цього типу принтера). Якщо принтер в змозі прийняти данні з комп’ютера, то четвертий розряд буде установлено в 1. В тому випадку, коли в принтері немає паперу (або він встановлений так, що не спрацював датчик), розряд з номером 5 буде рівним 1. Якщо принтер підключено до комп’ютера, в розряд номер 6 записується 1. В сьомому розряді буде 1,якщо принтер готовий до друкування. Інші розряди не використовуються. Крім того, в регістр DX треба записати номер принтера (0,1 або 2). Це значить, що до комп’ютера може бути підключено до 3-х пристроїв друкування. Якщо є тільки 1 принтер, то вказується число 0.
Приклад: Написати програму, яка перевіряє статус принтера (процедура Star Print) і ставить вимогу: поставити папір в принтер.
Uses crt,dos,printer;
Var r:registers;
Procedure statprint;
Begin
r.ah:=$2;
r.dx:=0;
intr($17,r);
end;
begin
statprint;
with r do begin
if (ah and $20)=$20 then
begin
clrscr;
repeat
writeln(#7,#7,’поставте вірно папір та натисніть Enter’);
readln;
statprint;
until (ah and $20) <> $20;
end;
end;
writeln (lst,’контрольне друкування’);
end.
Пояснення:
Після першого виклику StatPrint аналізується зміст регістру АН шляхом накладання маски $20. Маску вибрано так, що в ній установлено в одиницю тільки розряд з номером 5 (інші розряди дорівнюють нулю).
РЕКУРСИВНА ОБРОБКА СПИСКІВ.
Рекурсивне визначення списку таке:
Список може бути або порожнім, або складатися із вузла, що має зсилку на список.
Для обробки списків можна написати рекурсивну процедуру. Її
структура буде відповідати визначенню в тому ceнci, що вона
повинна містити умовний оператор, одна гілка якого виконує дії, що відповідають обробці порожнього списку, в той час як друга перетворює інформацію, що міститься в одиночному вузлі, а для обробки тої частини, що залишилася, процедура рекурсивно звертається сама до себе.
В пpoгpaмi, що приводиться нижче, використовують дві рекурсивні процедури - одна для читання послідовності символів, а друга – для друку.
(Можливо примінити i більш простий метод, але ми демонструємо можливості рекурсивної обробки списку)
Program K1;
Туре
Зв 'язок = ^об’єкт;
Об 'єкт = record
наступ: зв 'язок;
данні: сhar;
end;
Var початок: зв 'язок; {на почат. списку}
Procedure додати (зсилка :зв 'язок);
Begin
If зсилка = NIL then
Begin
NEW (зсилка);
зсилка^. наступ: =NIL; read(зсилкa^. дані);
end
else
додати(зсилка^. наступ);
end;
Procedure друкувати (зсилка :зв'язок);
Begin
If зсилкa<>NIL then
Begin
Write(зсилка^. дані);
друкувати(зсилка^. наступ);
end;
end;
Begin
Початок :=NIL;
While NOT EOF do
додати (початок);
друкувати (початок);
end.
1). Описати функцію або процедуру, що перевіряє, чи упорядковані елементи списку L за алфавітом.
Program L_8_1;
uses crt;
type spisok=^spis;
spis=record
d:char;
s:spisok;
end;
var sp:spisok;
d,z:char;
i,n:integer;
procedure int(var l:spisok;d:char);
var p,q:spisok;
begin
new(q);
q^ .s:=nil;
q^ .d:=d;
if l=nil then l:=q
else begin p:=l;
while p^ .s<>nil do p:=p^ .s;
p^ .s:=q;
end;
end;
procedure proverka;
begin
while sp<>nil do
begin
if sp^ .d<>#27 then
begin
if sp^ .d>=z then z:=sp^ .d
else
begin
Writeln (’Список не упорядочен по алфавиту’);
exit;
end;
end;
sp;=sp^ .s;
end;
Writeln(’Список упорядочен по алфавиту’);
end;
begin
clrscr;
z:=’a’;
Writeln(Введите элементы списка’’);
repeat
d:=readkey;
Writeln(d);
inp (sp,d);
until d=#27;
proverka;
end.
Задача: виключити зі списку елементи, які відносяться до студентів, у яких одна оцінка ”3”, а останні ”4” та ”5”. Роздрукувати одержаний список.
Program Pasl_8;
Type Rec=^ struct;
Struct=record
fio:string;
x:array [1…3] of integer;
next: rec;
pred: rec;
end;
Var fam:string;
ptr, test, tmp:rec;
i, j, n, t, y, kol:integer;
Procedure AAA;
begin
New (ptr);
Writeln(’Name’);
Readln(fam);
ptr^ .fio:=fam;
Writeln(fam,’ ‘s marks:’);
For kol:=1 to3 do
begin
Readln(n);
ptr^ .x[kol]:=n;
end;
if test=nil then
begin
test:=ptr;
ptr^ .pred:=nil;
ptr^ .next:=nil;
end
else
begin
ptr^ .pred^ .next:=ptr;
ptr^ .pred:=test;
test:=ptr;
ptr^ .next:=nil;
end;
end;
Procedure dis;
begin
ptr^ .pred^ .next:=ptr^ .next;
ptr^ .next^ .pred:=ptr^ .pred;
end;
procedure first;
begin
while(ptr^ .pred<>nil) do
ptr:+ptr^ .pred;
end;
Procedure SSS;
begin
first;
Repeat
Writeln(ptr^ .fio);
For i:=1 To 3 Do
Writeln(’ ’ ,ptr^ .x[i]);
Writeln;
ptr:=ptr^ .next;
if (ptr=nil) then exit;
Until ptr=nil;
end;
Procedure TTT;
begin
first
Repeat
tmp:= ptr^ .next;
For i:= 1 To 3 Do
begin
if ptr^ .x[i] <=3 then
begin
dis;
i:=3;
end;
end;
if (tmp<>nil)then ptr:=tmp;
Until tmp=Nil;
end;
begin
Writeln(’Vvedit kilkist stydentiv.’);
Readln(j);
For i:=1 To j Do AAA;
TTT;
Writeln(’Rezyltat:’);
SSS;
Readln;
end.
ДВОЗВ'ЯЗАНІ К1ЛЬЦЯ.
Дещо змінивши структуру списку, можна в кожній компоненті списку зберігати дві зсилки: одну на попередню компоненту, а другу на наступну. Для повної симметрії можна зв'язати першу i останню зсилку між собою i одержати двузв'язне кільце.
початок
Процедури двузв'язного кільця працюють завжди чітко, однак компоненти кільця стали великих розмірів, так як з'явилася друга зсилка, тому процедури стали працювати повільніше, однак, двузв'язне кільце являє собою елегантну структуру, а прості операції над кільцями не вимагають послідовних переглядів.
ДЕРЕВА.
Зсилки можна використовувати не лише для представлення простих списків i кілець, але i для представлення структур більш загального вигляду. Нехай ми маємо деяку структуру, яка складається з записів,
що зв'язані між собою системою зсилок, причому кожен запис може
містити зсилки на кілька іньших записів. Так представляються направлені
графи. Вершинами або вузлами графа є записи. Зсилки відіграютъ роль ребер. Частковим випадком графу являється дерево, яке мае такі властивості: підструктури, що зв'язані з деяким вузлом, не зв'язані між собою; кpiм того, існує вузол, що називається коренем. Із нього переглядом кінцевого числа ребер можна досягти любого вузла дерева.
Дерево з коренем А
Вузли Г, Д, Є, Ж, I, К, Л називаються терміналъними вузлами або листками дерева.
Дерево е рекурсивною структурою. Його можна визначити так: дерево або порожнє, або складається з вузла, що містить зсилки на вузли, які не перетинаються. Це визначення дуже схоже на рекурсивне визначення списку. Списки можна легко опрацьовувати як з допомогою рекурсії, так i з допомогою iтерації, а дерева простіше опрацьовувати за допомогою рекурсивних алгоритмів
ДВІЙКОВЕ ДЕРЕВО.
Кожен вузол двійкового дерева має не більше двох вузлів - відростків. Якщо у вузла два відростка, то вони називаються лівим i правим, відростками. Такі відростки в двійкових деревах не являються взаємозамінними.
Для представлення вузла двійкового дерева в мові Паскаль зручно користуватися записами:
Туре зв 'язок = ^вузол;