Scrigroup - Documente si articole

     

HomeDocumenteUploadResurseAlte limbi doc
AccessAdobe photoshopAlgoritmiAutocadBaze de dateC
C sharpCalculatoareCorel drawDot netExcelFox pro
FrontpageHardwareHtmlInternetJavaLinux
MatlabMs dosPascalPhpPower pointRetele calculatoare
SqlTutorialsWebdesignWindowsWordXml

Intreruperi

calculatoare



+ Font mai mare | - Font mai mic



Intreruperi

Notiunea de intrerupere presupune (asa cum ii arata si numele) intreruperea programului in curs de executie si transferul controlului la o anumita rutina specifica, numita rutina de tratare, dictata de cauza care a generat intreruperea. Mecanismul prin care se face acest transfer este, in esenta, de tip apel de procedura, ceea ce inseamna revenirea in programul intrerupt, dupa terminarea rutinei de tratare.



1 Intreruperi hardware si software. Tabela de intreruperi

Intreruperile se pot clasifica dupa mai multe criterii, rezultand tipurile ilustrate in

Figura 2.7.

Figura 2.7 Clasificarea intreruperilor

Intreruperile software apar ca urmare a executiei unor instructiuni, cum ar fi INT, INTO, DIV, IDIV;

Intreruperile hardware externe sunt provocate de semnale electrice care se aplica pe intrarile de intreruperi INT si NMI ale procesorului;

Intreruperile hardware interne apar ca urmare a unor conditii speciale de functionare a procesorului (cum ar fi executia pas cu pas a programelor);

Intreruperile dezactivabile sunt provocate de semnalul electric aplicat pe linia (intrarea) INT si sunt luate in considerare numai daca bistabilul IF este 1.

Intreruperile nedezactivabile sunt provocate de semnalul electric aplicat pe linia NMI si sunt totdeauna luate in considerare.

Intreruperile hardware dezactivabile sunt controlate de unul sau mai multe circuite specializate (controlere de intreruperi 8259A), care accepta fiecare cel mult opt cereri de intreruperi, pe care le transmit catre linia INT a procesorului. Daca bistabilul IF este 1, procesorul raspunde printr-o secventa de semnale electrice INTA (Interrupt Acknowledge), asemanatoare unei secvente de citire a codului unei instructiuni. Pe durata unuia din aceste semnale, controlerul care a initiat cererea de intrerupere plaseaza pe magistrala de date octetul care identifica nivelul intreruperii. Un asemenea sistem se numeste sistem vectorizat de intreruperi (vezi Figura 2.8).

Figura 2.8 Intreruperi hardware vectorizate

Intr-un sistem cu procesor 8086, pot exista maxim 256 de intreruperi (nivele) distincte. Fiecare din aceste nivele poate avea asociata o procedura de tip far, numita rutina de tratare. Adresele acestor rutine sunt trecute intr-o asa numita tabela de intreruperi, aflata la adresele fizice 00000 - 003FFH, ocupand deci 1024 de octeti. Fiecare nivel ocupa 4 octeti, primii reprezentand offset-ul, iar urmatorii adresa de segment a procedurii (vezi Figura 2.9).

La aparitia unei intreruperi, au loc urmatoarele actiuni:

. se salveaza in stiva registrele FLAGS, CS si IP (in aceasta ordine);

. se sterg bistabilii IF si TF;

. se furnizeaza procesorului un intreg pe 8 biti (deci in gama 0 - 255), numit si vector de intrerupere, care identifica nivelul asociat intreruperii;

. se executa un salt indirect intersegment la adresa de inceput a rutinei de

tratare, prin intermediul tabelei de intreruperi.

Vectorul de intrerupere poate fi furnizat procesorului in urmatoarele moduri:

. in cazul intreruperilor hardware interne, nivelul este implicit; de exemplu, pentru intreruperea de executie pas cu pas (generata daca bistabilul TF=1). se utilizeaza totdeauna nivelul 1;

. in cazul intreruperilor hardware externe, nivelul este plasat pe magistrala de date, in cadrul ciclului masina (Interrupt Acknowledge), care urmeaza dupa luarea in considerare a intreruperii de catre dispozitivul care a generat intreruperea;

. in cazul intreruperilor software, nivelul este continut in instructiune.


Figura 2.9 Tabela de intreruperi

Se observa ca, exceptand salvarea flagurilor si stergerea bistabililor IF si TF, secventa de tratare a unei intreruperi se reduce la un apel indirect de procedura far, prin intermediul tabelei de intreruperi.

2 Instructiuni specifice intreruperilor (INT, IRET, INTO)

Instructiunea INT (Interrupt - Intrerupere software)

Are forma generala:

INT n

unde n este o constanta intreaga in gama 0 - 255.

Semnificatia este urmatoarea:

(SP) <- (SP) - 2

SS:((SP) + 1 : (SP)) <- (FLAGS)

IF <- 0, TF <- 0

(SP) <- (SP) - 2

SS:((SP) + 1 : (SP)) <- (CS)

(CS) <- (4*n + 2)

(SP) <- (SP) - 2

SS:((SP) + 1 : (SP)) <- (IP)

(IP) <- (4*n)

Se incarca, deci, in CS si IP continutul de la adresele fizice 4*n+2 si 4*n, adica cei patru octeti corespunzatori nivelului n din tabela de intreruperi.

Instructiunea IRET (Interrupt Return - Revenire din intrerupere)

Datorita actiunilor care au loc la aparitia unei intreruperi, o procedura de tratare nu se poate incheia cu o instructiune RETF, deoarece trebuie refacut si registrul de flaguri. Ca atare, procedurile de tratare a intreruperilor se incheie totdeauna cu instructiunea IRET.

Instructiunea, care este fara operanzi, are semnificatia urmatoare:

(IP) <- SS:((SP) + 1 : (SP))

(SP) <- (SP) + 2

(CS) <- SS: ((SP) + 1 : (SP))

(SP) <- (SP) + 2

(FLAGS) <- SS:((SP) +1 : (SP))

(SP) <- (SP) + 2

Se observa ca bistabilii IF si TF, care au fost stersi la aparitia intreruperii, sunt refacuti asa cum erau inainte de intrerupere, o data cu ceilalti bistabili din registrul FLAGS.

Instructiunea INTO (Interrupt if Overflow - Intrerupere in caz de depasire)

Instructiunea care este fara parametri, are semnificatia urmatoare:

. daca OF = 1, atunci se executa secventa corespunzatoare unei instructiuni

INT 4.

Codificarea instructiunilor INT este pe doi octeti, cu exceptia instructiunii INT 3, la care codificarea este pe un singur octet. Acest fapt nu este intamplator, deoarece nivelele 2 si 3 sunt, in general, utilizate de programele de depanare (debuggere).

Astfel, rularea pas cu pas a unui program se face setand bistabilul TF si scriind pe nivelul 1 al tabelei de intreruperi adresa unei rutine proprii de tratare. La executia fiecarei instructiuni, se va da controlul rutinei proprii, care va afisa corespunzator starea programului. Rularea pana la o adresa data (breakpoint) se realizeaza prin inlocuirea octetului de la adresa respectiva cu codul unei instructiuni INT 3. Astfel, cand programul care se executa ajunge la acea adresa, se da controlul rutinei de tratare pe nivelul 3.

Nivelele predefinite de intrerupere sunt, deci:

. 0 - depasire la impartire (cauze posibile; instructiunile DIV sau IDIV);

. 1 - executie pas cu pas (cauza posibila: bistabilul TF = 1;

. 2 - intrerupere externa nedezactivabila (cauza posibila: semnal electric pe linia de

intrerupere nedezactivabila NMI);

. 3 - executie pas cu pas (cauza posibila: instructiunea INT 3);

. 4 - depasire (cauza posibila: instructiunea INTO).

La calculatoarele de tip IBM-PC, se mai pot cita intreruperile hardware de la ceasul de timp real (nivelul 8) si de la tastatura (nivelul 9).

Intreruperile software in gama 20H - 2FH sunt folosite de sistemul de operare DOS, iar cele in gama 10H - 1AH de catre subsistemul de intrari - iesiri BIOS.

2.6 Instructiuni pentru controlul procesorului

Toate instructiunile de acest gen sunt fara operanzi.

O prima categorie de instructiuni se refera la controlul explicit al unor bistabili de conditie (CLC, STC, CMC, CLD, STD, CLI si STI).

Instructiunile CLC (Clear Carry Flag), STC (Set Cary Flag) si CMC (Complement Carry Flag) efectueaza operatiile de stergere, setare si, respectiv, complementare a bistabilului CF.

Instructiunile CLD (Clear Direction Flag) si STD (Set Dinction Flag) sterg, respectiv, seteaza bistabilul DF.

Instructiunile CLI (Clear Intrerrupt Flag) si STI (Set Interupt Flag) sterg, respectiv, seteaza bistabilul IF. Cand IF = 0, intreruperile externe nedezactivabile nu sunt luate in considerare. Astfel, o asa numita secventa critica de program (care nu dorim sa fie intrerupta) se protejeaza printr-o instructiune CLI inainte si o instructiune STI dupa. O secventa critica tipica este modificarea explicita a tabelei de intreruperi.

O alta serie de instructiuni (HALT, LOCK, WAIT) realizeaza unele operatii speciale asupra procesorului.

Astfel, instructiunea HALT (Oprire procesor) forteaza procesorul intr-o stare speciala de inactivitate, din care se poate iesi doar prin intreruperi externe sau prin reset general.

Prefixul LOCK (Blocare magistrala) se poate folosi inaintea oricarei instructiuni, efectul fiind ca pe durata instructiunii, accesul unui alt dispozitiv la magistrala sistemului hardware este blocat. intr-un sistem multiprocesor, nu este suficient sa protejam secventele critice prin instructiuni (LI/STI, deoarece controlul magistralei ar putea fi preluat de un alt procesor De aici, utilitatea prefixului LOCK.

Instructiunea WAIT (Asteapta) este folosita pentru a sincroniza activitatea procesorului cu cea a unui alt dispozitiv, de obicei un coprocesor matematic.

Executia unei instructiuni matematice este preluata de coprocesor; totusi, procesorul de baza nu poate continua programul pana nu primeste un semnal de la coprocesor, prin care se anunta sfarsitul operatiei executate. Aceasta sincronizare se realizeaza printr-un semnal electric aplicat pe linia TEST a procesorului de baza. Ca atare, instructiunea WAIT va forta procesorul de baza intr-o stare de inactivitate, pana la aparitia unui semnal electric pe linia TEST.

In fine, exista si o instructiune care nu face nimic: instructiunea NOP (No Operation). Scopul unei asemenea instructiuni este de a introduce o intarziere in program. Asamblorul recunoaste mnemonica NOP, dar codificarea interna este aceeasi cu a instructiunii XCHG AX, AX, care, evident, nu face nimic.

2.7 Dezvoltarea programelor in limbaj de asamblare

Acum, dupa ce am parcurs setul de instructiuni al procesorului, putem trece la prezentarea unui cadru de dezvoltare al programelor in limbaj de asamblare. Contextul ales este cel al calculatorului de tip IBM-PC sub sistemul de operare DOS si al produselor software Borland: asamblorul TASM (Turbo Assembler), link-editorul TLINK (Turbo Linker), bibliotecarul TLIB (Turbo Librarian) si depanatorul interactiv TD (Turbo Debugger).

Vom utiliza extensiile implicite ale fisierelor: .ASM pentru fisiere sursa, .OBJ pentru fisiere obiect, .EXE sau .COM pentru fisiere executabile.

O problema specifica limbajului de asamblare este absenta unor instructiuni de

Intrare - iesire de nivel inalt. Pentru asemenea operatii, va trebui sa ne scriem propriile rutine. In acest curs, vom utiliza o serie de proceduri si macroinstructiuni, implementate in fisierul IO.H si in fisierul IO.ASM. Aceste fisiere asigura (intre altele) suport pentru urmatoarele operatii de baza:

. introducerea de caractere de la consola;

. afisarea de caractere la consola;

. introducerea de siruri de caractere de la consola;

. afisarea de siruri de caractere la consola;

. afisarea unor mesaje imediate la consola;

. introducerea de intregi pe 16 biti cu sau fara semn de la consola;

. afisarea de intregi pe 16 biti cu sau fara semn la consola;

. initializarea registrelor DS si ES la intrarea in program;

. terminarea programului cu iesire in sistemul DOS. Se vor utiliza directivele de definire simplificata a segmentelor. Sablonul de dezvoltare al unui program ASM care contine un modul executabil va fi urmatorul:

.model  MMMMM

include  io.h

.stack  NNNNN

.data

; Definitii de date

.code

; Definitii de proceduri

start:

init_ds_es

; Program principal

exit_dos

end  start

unde:

. MMMMM este modelul de memorie, care poate fi tiny, small, medium, compact, large sau huge; modelele uzuale sunt small si large, in care toate adresele, procedurile, apelurile, salturile si revenirile din procedura sunt implicit de tip NEAR, respectiv de tip FAR;

. NNNN este dimensiunea rezervata segmentului de stiva; o valoare uzuala este 1024;

. include io.h este o directiva care include in textul sursa fisierul io.h, care trebuie sa se gaseasca in acelasi catalog (director) cu fisierul sursa;

. init_ds_es este o macroinstructiune (definita in io.h) care initializeaza registrele DS si ES cu adresa segmentului de date; registrele SS si CS sunt initializate automat la incarcarea programului executabil de pe disc.

. exit_dos este o macroinstructiune (definita in io.h) care provoaca terminarea programului si revenirea in sistemul DOS;

. start este o eticheta care marcheaza punctul de inceput al programului principal;

. end start este o directiva care precizeaza ca modulul curent este modul de

program principal, avand punctul de intrare !a eticheta start. O alta varianta este scrierea programului principal sub forma unei proceduri (avand numele, de exemplu, _main) si precizarea punctului de start prin numele procedurii:

.model  MMMMM

include  io.h

.stack  NNNN

.data

; Definitii de date

.code

; Definitii de proceduri

_main proc

init_ds_es

; Program principal

exit_dos

_main endp

end  _main

Un modul de program care nu este modul de program principal (deci contine definitii de date si / sau proceduri) nu are eticheta in directiva end. Intr-o aplicatie dezvoltata modular (in mai multe fisiere sursa), un singur modul poate fi modul de program principal.

Asamblorul nu face distinctie intre simboluri scrise cu litere mici sau mari. De acum incolo, vom scrie de regula programele cu litere mici, iar cu litere mari unele directive si tipuri de date definite de utilizator, pentru a le scoate in evidenta.

Asamblarea unui fisier sursa NUME.ASM se face cu una din comenzile:

C:> tasm nume.asm

C:> tasm nume

in urma careia rezulta un fisier obiect NUME.OBJ.

Daca se doreste si fisier listing, se da comanda:

C:> tasm nume ,,nume

in urma careia rezulta si un fisier NUME.LST.

Daca se doreste o depanare simbolica ulterioara, trebuie introdusa optiunea  /zi:

C:> tasm nume /zi

Operatia de asamblare se face pentru fiecare fisier sursa in parte. Legarea modulelor se face cu comanda:

C:> tlink nume_1 nume_2 [, nume_bin ] [/v]

in care parantezele drepte indica parametrii optionali; nume_1, nume_2 sunt numele modulelor obiect, nume_bin este numele fisierului executabil rezultat (daca lipseste, se considera numele primului modul obiect), iar /v este o optiune de depanare simbolica (se introduce daca vrem sa executam programul sub controlul depanatorului TD). In urma comenzii, rezulta un fisier executabil.

O situatie tipica este cea a unui singur modul sursa, caz in care comanda de legare va fi:

C:> tlink nume io

prin care se leaga si modulul io.obj (care contine procedurile de intrare - iesire descrise mai sus).

Peste tot in cuprinsul cursului vom considera ca sirurile de caractere sunt terminate cu octetul 0 binar. Definitia unui sir constant sau rezervarea de spatiu pentru un sir variabil se pot face prin directiva Define Byte (constantele simbolice cr si lf sunt definite in fisierul io.h). Definitia unui intreg sau rezervarea de spatiu pentru un intreg se poate face cu directiva Define Word. Definirea de spatiu la nivel de caracter se face cu directiva Define Byte.

.data

sir_1  db 'Un sir de caractere', cr, lf, 0

sir_2  db 80 dup (0)

i_1  dw -200

i_2  dw ?

u_1  dw OFFFFH

u_2  dw -1

c_1  db 'A'

c_2  db ?

Afisarea unui sir de caractere la consola se poate face prin macroinstructiunea puts (Put String), in una din formele:

puts  sir_1 ; O prima forma de invocare

lea  si, sir_1 ; O a doua

puts  [si] ; forma de invocare

Citirea unui sir de caractere de la consola se poate face cu macroinstructiunea gets (Get String), in una din formele:

gets  sir_2 ; O prima forma de invocare

lea  bx, sir_2 ; O a doua

gets  [bx] ; forma de invocare

Afisarea unui sir constant de caractere (mesaj fa consola) se poate face cu macroinstructiunea putsi (Put String Immediate), care nu necesita definirea sirului si nici prezenta explicita a terminatorului 0:

putsi  <'Introduceti un sir de caractere', cr, lf>

gets  sir_2

putsi  <'Sirul introdus este:', cr, lf>

puts  sir_2

putsi  <cr,lf>

Introducerea unui intreg cu sau fara semn se poate face cu macroinstructiunile geti (Get Integer), fara parametri, care intoarce intregul citit in registrul AX.

Afisarea unui intreg cu sau fara semn se poate face cu macroinstructiunile puti (Put Integer) sau putu (Put Unsigned), in una din formile:

geti  ; Citeste intreg in AX

puti  ax ; Afiseaza intregul din AX

mov  i_1, ax ; Depune

puti  i_1 ; Afiseaza intreg cu semn din memorie

putu  u_1 ; Afiseaza ca numar fara semn

lea  di, i_2

puti  [di] ; Afiseaza ca numar cu semn

putu  [di] ; Afiseaza ca numar fara semn

Introducerea unui singur caracter de la consola se poate face cu macroinstructiunea getc (Get Character), care intoarce caracterul in registrul AL, iar afisarea unui caracter se poate face cu macroinstructiunea putc (Put Character), in una din formele:

putc  'A'

putc  car_1

lea  bx, car_2

putc  [bx]

Toate macroinstructiunile de mai sus conserva registrele procesorului, deci nu e nevoie de salvari si restaurari explicite.

Sa consideram un exemplu de program, in care se fac urmatoarele operatii:

. se citesc de la consola cel mult 20 de intregi cu semn;

. se afiseaza valorile introduse;

. se sorteaza crescator aceste valori;

. se afiseaza valorile sortate.

Consideram modelul de memorie large, adica toate adresele sunt implicit de 32 de biti. Pentru sortare, vom folosi un algoritm elementar (metoda bulelor), descris mai jos

(se considera ca indicii din tabloul a variaza de la 0 la n-1):

for i = 1 to n-1

for j = n - 1 downto i

if ( a[j-l] > a[j] )

schimba a[j] cu a[j-l]

Implementarea intregului program este urmatoarea:

.model  large

include  io.h

.stack  1024

. data

vec  dw 20 dup (?)

n  dw ?

. code

tipvec proc far

Procedura de afisare vector.

Date de intrare:

ds:si = adresa vector de intregi

cx = numar de elemente

jcxz  tipend ; Nu avem ce afisa

tip:

puti  [si] ; Afisare intreg cu semn

putsi  <' '> ; Spatiu

add  si, 2 ; Actualizare adresa

loop  tip ; Bucla dupa CX

tipend:

ret

tipvec endp

bubble proc far

procedura de sortare

Date de intrare

ds:bx = adresa tablou de intregi

cx = dimensiune tablou

Variabila i : asignata la si

Variabila j : asignata la di

Adresa de inceput a tabloului: asignata la bx

cmp  cx, 1

jbe  algend ; Nu avem ce sorta

mov  si, 1 ; i = 1

fori:

mov  di, cx

dec  di ; j = n-1

forj:

shl  di, 1 ; intregii pe 2 octeti

mov  ax, [bx][di-2] ; a[j-1]

cmp  ax, [bx][di] ; Compara cu a[j]

jle  nextj ; Mai mic sau egal

xchg  ax, [bx][di] ; Schimba a[j]

mov  [bx][di-2], ax ; cu a[j-1]

nextj:

shr  di, 1 ; Refacere indice

dec  di ; Ciclu downto

cmp  di, si

jae  forj ; Cat timp j >= i

nexti:

inc  si ; Ciclu to

cmp  si, cx

jb  fori ; Cat timp i < n

algend:

ret

bubble endp

Programul principal

start:

init_ds_es

putsi  <'Introduceti datele',cr,lf>

mov  cx, 20 ; Numar maxim

;de elemente

lea  bx, vec ; Adresa tablou

iar:

geti  ; Citire intreg cu semn

test  ax, ax ; Este 0 ?

jz  gata ; Daca da, gata

mov  [bx], ax ; Depunere in tablou

add  bx, 2 ; Actualizare adresa

loop  iar ; Bucla dupa CX

gata:

mov  ax, 20 ; Calcul numar de

sub  ax, cx ; elemente introduse

mov  n, ax

putsi  <'Vector nesortat', cr, lf>

lea  si, vec ; Adresa tablou

mov  cx, n ; Numar de elemente

call  tipvec ; Afisare tablou

; nesortat

lea  bx, vec ; Adresa tablou

mov  cx, n ; Numar de elemente

call  bubble ; Sortare tablou

putsi  <cr,lf,'Vector sortat', cr, lf>

lea  si, vec

mov  cx, n

call  tipvec ; Afisare tablou sortat

exit_dos  ; iesire in DOS

end  start

In segmentul de date, se rezerva spatiu pentru tabloul vec de cel mult 20 de intregi si pentru dimensiunea n a acestuia.

Procedura TIPVEC primeste in SI adresa unui tablou si in CX numarul de elemente, realizand afisarea la consola a elementelor, considerate intregi cu semn. Se observa forma standard a unei bucle de program implementata cu instructiunea LOOP.

Procedura BUBBLE implementeaza algoritmul de sortare. Indicii i si j din descrierea algoritmului sunt asignati la registrii SI si Dl. Indicii sunt incrementati sau decrementati cu 1, dar intregii sunt pe doi octeti. De aceea, in secventa de adresare a memoriei, se inmulteste temporar Dl cu 2, pentru a accesa corect elementele tabloului. Astfel, elementul de indice 0 se va afla la deplasament 0, elementul de indice 1 la deplasament 2 etc. Inmultirea si refacerea se realizeaza prin deplasari logice. Se observa secventa standard de interschimbare a doua elemente din memorie (doua MOV-uri si un XCHG). Trebuie remarcat modul in care se fac comparatiile diverselor elemente: indicii sunt considerati fara semn, deci testele se fac cu instructiuni de salt conditionat de tip "Above' sau "Below'. In schimb, tabloul este cu semn, deci comparatiile intre elemente se fac cu instructiuni de salt conditionat de tip "Greater' sau "Less'. Programul principal incepe printr-o bucla de citire a datelor. Introducerea se poate opri mai devreme de 20 de elemente daca se introduce valoarea 0. La iesirea din bucla, se calculeaza numarul de elemente efectiv introduse, ca diferenta dintre numarul maxim admis (20) si valoarea curenta a lui CX. Acest numar se depune in variabila n, pentru utilizari viitoare. In continuare, vom avea secvente de apel ale procedurilor TIPVEC si BUBBLE. Se observa incarcarea corespunzatoare a parametrilor (adresa tabloului si numarul de elemente) in registrele desemnate in acest scop pentru fiecare procedura. Exemplul prezentat ilustreaza modul de utilizare a macroinstructiunilor prezentate, ca si schema generala de dezvoltare a unui program.



Politica de confidentialitate | Termeni si conditii de utilizare



DISTRIBUIE DOCUMENTUL

Comentarii


Vizualizari: 2808
Importanta: rank

Comenteaza documentul:

Te rugam sa te autentifici sau sa iti faci cont pentru a putea comenta

Creaza cont nou

Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved