Microprocesoul I8086 are un set de 256 vectori de întreupere, numerotati de la 0 la 255. Fiecare vector are un cod de 4 octeti care reprezinta adresa rutinei de tratarea a întreruperii (ISR).
Limbajele de nivel înalt rateaza problema gasirii acestei adrese, pe baza vectorului de întrerupere.
În tabelul urmaor se prezinta întreruperile din PC care sunt asociate cu nivele IRQ. 131p159b
INT (Hex) |
IRQ |
Utilizare |
System Timer |
||
Tastatura |
||
0A |
Redirectare |
|
0B |
Serial Com. COM2/COM4 |
|
0C |
Serial Com. COM1/COM3 |
|
0D |
Reservat/Placa de Sunet |
|
0E |
Floppy Disk Controller |
|
0F |
Paralel Com. |
|
Real Time Clock |
||
Reservat |
||
Reservat |
||
|
Reservat |
|
PS/2 Mouse |
||
Maths Co-Processor |
||
Hard Disk Drive |
||
Reservat |
Procesorul 80x86 are doua linii pe care dispozitivele externe le pot folosi pentru semnale de întrerupere INTerrupt Request si NonMaskable Interrupt.
Daca linia INTR este activa, unitatea centrala executa diferite operatii în functie de indicatorul de validare a întreruperilor IF. Daca acesta este sters (întreruperile semnalate de INTR sunt mascate sau dezactivate), unitatea centrala ignora întreruperea si executa instructiunea urmatoare. Daca IF este pozitionat, unitatea centrala recunoaste cererea de întrerupere, opreste executia normala a instructiunilor si preda controlul rutinei de tratare a întreruperilor. Indicatorul IF poate fi pozitionat sau sters din program.
Pe a doua linie sosesc întreruperi folosite pentru a anunta evenimentele critice. Acestea (NMI) nu pot fi mascate sau dezactivate si unitatea centrala le ia în considerare de fiecare data. Intervalul de timp de la sosirea unei întreruperi pâna la servirea ei depinde de numarul de impulsuri de ceas care au mai ramas sa fie executate din instructiunea curenta.
Întreruperi interne
Sunt generate în urma executiei instructiunilor INT sau INTO sau sunt generate automat de unitatea centrala în anumite conditii (împartire cu 0, executie pas cu pas ). Instructiumea INT genereaza o întrerupere imediat dupa executia sa. Timpul de întrerupere este codificat în instructiune, anuntând unitatea centrala care rutina de tratare a întreruperii sa o execute.
INTO genereaza o întrerupere de tip 4 (overflow).
Întreruperea de tip 0 este generata de unitatea centrala în cazul în care în urma unei instructiuni de împartire rezultatul este mai mare decât destinatia specificata.
Daca TF este pozitionat, unitatea centrala genereaza automat o întrerupere de tip 1 dupa executia fiecarei instructiuni. Aceasta executie pas cu pas foloseste la depanarea programelor.
Întreruperea 3 (breakpoint) este dedicata depanarii programelor.
Circuitul pentru contolul întreruperilor (8259A)
Circuitul manipuleaza pâna la 8 întreruperi si poate fi cascadata pâna la 64 întreruperi folosind circuite aditionale. Este interfatata la magistrala de date si la magistrala de control. Genereaza catre procesor semnalul INT . Primeste INTA si cererile de întrerupere pe liniile IR0-IR7.
Contine registrele :
-Interrupt Request Register (stocheaza cererile de întrerupere );
-In Service Register (stocheaza întreruperile care se servesc );
-Interrupt Mask Register (stocheaza masca de întrerupere), (21H).
Procesul de întrerupere contine urmatorii pasi :
Una sau mai multe cereri de întrerupere (IR0-7) trec pe nivelul "high" setând bitii corespunzatorii din IIR.
8259A evalueaza cererile si trimite INT catre CPU.
CPU accepta întreruperea raspunzând cu INTA.
La primirea lui INTA bitul cu cea mai mare prioritate este setat in ISR, iar bitul corespunzator din IRR este resetat. 8259 va lansa o instructiune CALL pe magistrala de date.
CALL va initia 2 semnale INTA.
Pe cele doua semnale INTA, 8259 va trimite vectorul de întrerupere.
Tabela vectorilor de întrerupere
Asocierea între tipul întreruperii si rutina de tratare a întreruperii este facuta prin tabela vectorilor de întrerupere. Aceasta ocupa prima zona din memorie pornind de la adresa fizica 0 pâna la 1K. Aceasta tabela poate avea pâna la 256 de intrari, câte una pentru fiecare întrerupere. Fiecare intrare din tabela este un pointer dublu (4 octeti ) continând adresa rutinei de tratare a întreruperii de tipul respectiv. Cuvântul de la adresa mai mare contine adresa de baza a segmentului care contine rutina, iar cuvântul de la adresa mai mica contine deplasamentul rutinei fata de începutul segmentului. Deoarece fiecare intrare are lungimea de 4 octeti, UC calculeaza locatia unei intrari, a unei întreruperi prin simpla înmultire a tipului cu 4.
La sosirea unei întreruperi, UC salveaza registrul cu indicatorii de stare si control în stiva si apoi activeaza rutina de tratare a întreruperii prin executarea unei instructiuni CALL între segmente. Adresa de la care se face saltul (adresa rutinei ) este adresa continuta în tabela vectorilor de întrerupere la locatia tip*4. UC salveaza adresa instructiunii urmatoare prin încarcarea registrilor CS si IP în stiva. Acestia sunt înlocuiti apoi cu primul, respectiv cu al doilea cuvânt al adresei din tabela. În acelasi timp sunt initializati TF si IF. Daca se doreste reactivarea întreruperilor în timpul rutinei de tratare a întreruperii, acesti indicatori trebuiesc repozitionati.
Este bine ca rutina de tratare a întreruperii sa activeze întreruperile externe, cu exceptia secventelor critice. Întreruperile externe dezactivate un timp prea lung se pot pierde.
End Of Interrupt reseteaza bitul setat în ISR (20H).
Rutinele de tratare a întreruperilor trebuie sa se termine cu instructiunea IRET. Ea va descarca de pe stiva IP, CS si indicatorii de stare si control (adresa instructiunii urmatoare si indicatorii, înainte de activarea rutinei de tratare a întreruperii ).
Programarea întreruperilor
Borland Turbo C are doua fuctii de biblioteca pentru citirea si modificarea unui vector de întreruperi. Acestea sunt: setvect() si getvect(). ( iar Microsoft C: _dos_getvect() si _dos_setvect(). )
getvect() are prototipul:
void interrupt(*getvect(int interrupt_no))();
setvect() are prototipul:
void setvect(int interrupt_no, void interrupt(*func)());
Un program care citeste si salveaza adresa unei întreruperi existente foloseste getvect() astfel:
/* Declara variabila pentru citirea întreruperii vechi */
void interrupt(*old)(void);
main()
Unde 0x1C este vectorul cautat
Pentru a aloca vectorul de întrerupere la o noua adresa, care este propria noastra functie, folosim setvect():
void interrupt new(void)
main()
Observatii:
Daca întreruperea e apelata de evenimente externe, înainte de a modifica vectorul, este obligatorie invalidarea întreruperilor prin disable() si apoi revalidarea întreruperilor dupa schimbarea vectorului folosind enable().
Înaintea terminarii programului e obligatorie stergerea oricaror modificari facute asupra vectorilor de întrerupere.
Mascarea
Programatorul poate masca întreruperi, folosind portul 0x21. Pentru a valida o anumita întrerupere, se scrie '0' în bitul corespunzator.
mask=inportb(0x21) & ~0x80;
//Citeste masca curenta. Pune bitul 7 pe '0'
//Lasa ceilalti biti nemodificati
outportb(0x21, mask);
Utilizatorul poate folosi întreruperea IRQ7. El poate scrie propria sa rutina de tratare a întreruperii, dar e obligat sa insereze secventa:
outportb(0x20, 0x20);
(EOI )informând ca întreruperea a fost tratata.
Exemplu
/* ** Program test interfata seriala **
Folosese o rutina de tratare a intreruperii
Intreruperea e determinata de transmisie
Notam ca am considerat portul serial COM1, 3F8h si am asociat IRQ4.
Nume Adresa in tabel **
IRQ2 0x0a
IRQ4 0x0c
IRQ5 0x0d
IRQ7 0x0f ** */
#include <stdio.h>
#include <bios.h>
#include <dos.h>
#include <conio.h>
#include <string.h>
#define DATA 0x03F8
#define IER DATA+1
#define IIR DATA+2
#define LCR DATA+3
#define MCR DATA+4
#define LSR DATA+5
#define MSR DATA+6
void close_intserv(void);
void int_processed(void);
void open_intserv(void);
void interrupt far intserv(void);
int intlev=0x0c; /* interuperea asociata cu IRQ4 */
int int_occurred = 0 ;
void interrupt far (*oldfunc)();
/* Definitii globale */
int main(void)
close_intserv();
return(0);
void interrupt far intserv(void)
/* Este rutina de tratare a intreruperii */
int_processed();
int_occurred=1;
enable();
void open_intserv(void)
/* valideaza IRQ4. In caz de intrerupere salt la intserv.
** toate intreruperile se invalideaza pe durata acestei functii
Validarea se face la iesire. */
void close_intserv(void)
/* invalideaza IRQ4 */
void int_processed(void)
/* EOI */
Scrieti programul de test din laboratorul precedent, folosind întreruperile.
|