Lucrarea nr. 11 Scopul lucrării
Lucrarea de faţă îşi propune familiarizarea utilizatorului cu folosirea funcţiilor coprocesorului matematic, utilizarea instrucţiunilor de lucru cu numere reale şi a altor funcţii ale coprocesorului.
Consideraţii teoretice
Cu toate că procesorul 8086 respectiv 80286, 80386 şi 80486 au o serie de instrucţiuni aritmetice puternice (care există în repertoriul microprocesoarelor de generaţia a doua, cum sunt înmulţirea şi împărţirea binară) nu sprijină operaţiile aritmetice cu numerele reprezentate în virgula flotantă sau pentru numerele întregi reprezentate pe mai mulţi octeţi. Dacă vrem sa efectuăm astfel de operaţii atunci aceste operaţii trebuie sa fie realizate prin biblioteci de macrouri sau prin subrutine. O cale mai simla este utilizarea limbajelor de nivel înalt, în aceste limbaje operaţiile de mai sus fiind realizate prin biblioteci.
Pentru evitarea greutăţilor amintite firma INTEL a dezvoltat coprocesorul aritmetic INTEL 8087 (80287, 80387). Acestea după cum arată şi numele sunt “co”-procesoare, care cooperează cu procesorul principal al calculatorului. Coprocesorul nu poate lucra independent de procesor. Coprocesorul nu poate să extragă singur instrucţiunile din memorie, acesta fiind realizat de procesor.
Principiul de funcţionare
Coprocesorul se iniţializează odată cu activarea semnalului RESET, general în sistemul de calcul. În urma acestui semnal coprocesorul este adus intr-o stare iniţială (cu mascarea erorilor, ştergerea registrelor, iniţializarea stivei, rotunjirea implicită, etc. ). Dupa prima instrucţiune executată de procesor coprocesorul poate detecta cu ce procesor lucrează (dacă este 8086 pe pinul 34 va fi 0 logic-semnalul / BHE-iar dacă este 8088 va fi 1 logic-semnalul/SS0). În funcţie de tipul procesorului, coprocesorul se configurează corespunzător.
Coprocesorul se conectează pe magistrala locală a procesorului prin liniile de adrese/date, stare, ceas, ready, reset, test şi request/grant. Fiind conectat la magistrala locală microprocesorul permite coprocesorului accesul la toată memoria şi resursele de intrare/ieşire, prin intermediul cererii de magistrală request/grant.
Cele două procesoare lucrând în paralel este nevoie de sincronizarea proceselor care rulează în ele.
De regulă sincronizarea erorilor şi a instrucţiunilor este rezolvată de compilatoare sau asambloare, iar sincronizarea datelor trebuie să o facă utilizatorul care lucrează în limbajul de asamblare.
Responsabilitatea controlului programului o are microprocesorul. Operaţia cu microprocesorul este iniţiată cu o instrucţiune specială ESCAPE în felul următor: coprocesorul “supraveghează” fluxul de instrucţiuni de la memorie spre procesor. Din decodificarea semnalelor S0, S1 şi S2 coprocesorul ştie când se încarcă în coada de instrucţiuni a procesorului instrucţiuni şi memorează aceste instrucţiuni în propria coadă. Din semnalele de stare a microprocesorului (QS0 şi QS1) coprocesorul va cunoaşte când se extrage din coada de instrucţiuni primul octet din instrucţiune. Dacă coprocesorul detectează pe baza informaţiilor din propria coadă şi pe baza semnalelor de stare că procesorul urmează să execute (deci se va extrage din coada de instrucţiuni) o instrucţiune ESC, coprocesorul se activează.
Codul instrucţiunii ESC este următorul:
-
Semnificaţia simbolurilor x este: indiferent. Rezultă că toate instrucţiunile care au codul operaţiei cuprins între D8-DF sunt interpretate ca instrucţiuni ESC. Împreună cu cei trei biţi din octetul doi permit în total 64 de instrucţiuni pentru coprocesor.
Microprocesorul execută instrucţiunea ESC calculând o adresă de memorie (din mod şi r/m) şi executând un ciclu de magistrală de a citi datele de la adresa calculată (dacă mod este 11 nu se execută nici un ciclu magistrală). Nu se citesc efectiv datele aduse din memorie, numai se generează un ciclu magistrală (deci apare ca o instrucţiune fără efect – NOP). Coprocesorul fiind activat de codul instrucţiunii ESC, decodifică cei sase biţi din instrucţiunea ESC şi poate captura adresa şi/sau datele prezente în locaţia de memorie selectată de instrucţiune. Acest mecanism permite programatorului de a trata instrucţiunea ESC (definită pentru coprocesor) ca o instrucţiune obişnuită cu toate modurile de adresare. Se permite transferul unei adrese ca parametru pentru coprocesor. Dacă coprocesorul are nevoie de mai multe date din memorie, el poate să ceară preluarea controlului de la microprocesor. Este de reţinut că toate informaţiile pentru procesor sunt în memorie, registrele microprocesorului nefiind accesibile. În timpul execuţiei activităţii proprii coprocesorul ţine linia / TEST la nivel înalt pentru a arăta procesorului că este ocupat.
În interiorul coprocesorului avem o memorie de 80 de octeţi organizată sub forma unei stive de opt elemente de 10 octeţi fiecare. Pe cei zece octeţi numerele în virgulă mobilă se reprezintă sub format intern, cu precizie extinsă. Coprocesorul poate accesa memoria calculatorului, cu orice mod de adresare cunoscut de 8086, orice dată de format legal. Datele aduse din memorie se convertesc în formatul intern al coprocesorului şi se pun la vârful stivei. La scrierea în memoria principală se face conversia din formatul intern în formatul specificat de utilizator.
Condiţia pentru efectuarea operaţiilor în virgulă flotantă în coprocesor este ca operandul (pentru operaţii cu doi operanzi, cel puţin unul din operanzi) să fie în vârful stivei. Deci cu ajutorul coprocesorului putem efectua următoarele operaţii:
- citirea datelor în memoria internă a coprocesorului (pe stivă) din memoria calculatorului
- efectuarea operaţiilor aritmetice necesare
- scrierea rezultatului în memoria calculatorului.
Tipurile de date cunoscute de INTEL 8087
Marele avantaj al coprocesorului este faptul că nu lucrează doar cu numere în virgulă flotantă, ci şi cu numere întregi şi recunoaşte şi tipuri de date zecimale împachetate. Deci dacă avem o operaţie complicată de efectuat între numere întregi şi ea trebuie să fie foarte rapidă şi acest lucru de poate realiza cu ajutorul coprocesorului, nu avem nevoie de conversie, costisitoare în timp, din întreg în virgulă flotantă şi după aceea invers doar pentru ca coprocesorul să poată lucra cu ele.
Tipuri de date în virgulă flotantă
Real scurt-număr reprezentat în virgulă flotantă pe 32 de biţi. Numărul se reprezintă descompus pe mantisă şi caracteristică. Caracteristica se reprezintă pe 8 biţi dintre care cel mai semnificativ este bitul de semn, interpretat special. Lungimea fizică a mantisei este de 23 de biţi. Semnul numărului real este dat de bitul cel mai semnificativ:
31 30 23 22 0
s
| Caracteristică |
Mantisă (începe cu 1)
|
|
se consideră implicit un bit 1
Această reprezentare a numerelor în virgulă flotantă lucrează întotdeauna cu numere normalizate, deci primul bit al mantisei este întotdeauna 1, acesta nu se scrie considerându-se implicit. Deci lungimea reală a mantisei este de 24 de biţi.
Este important să cunoaştem precizia practică. Mantisa înseamnă 6-7 cifre zecimale, pe când caracteristica prin cei 8 biţi ai săi creşte numărul până la ordinul de mărime ~10 la puterea 38 (numărul exact nu se poate stabili deoarece depinde de mantisă). Cel mai mare număr este aproximativ 1, 7*10la puterea 38, iar cel mai mic număr real pozitiv este în jur de 10 la puterea –38.
Real lung-numărul în virgulă reprezentat pe 64 biţi. Este reprezentat descompus în mantisă şi caracteristică. Caracteristica are lungime de 11 biţi din care cel mai semnificativ este bitul semn special al caracteristicii. Mantisa are lungime fizică de 52 biţi. Semnul numărului este dat de bitul cel mai semnificativ :
63 62 52 51 0
s
|
caracteristică
|
Mantisă (începe cu 1)
|
|
se consideră un 1 implicit
Ca şi în cazul anterior şi aici avem un bit implicit, deci lungimea efectivă a mantiseieste 53 de biţi. Pe aceşti 53 de biţi se pot reprezenta aproximativ 15-16 cifre, iar reprezentarea numerelor mici este foarte exactă.
Real cu precizie ridicată-număr în virgulă flotantă reprezentat pe 80 de biţi. Este reprezentat descompus pe mantisă şi caracteristică. Lungimea caracteristicii este de 15 biţi dintre care cel mai semnificativ este bitul de semn. Lungimea mantisei este de 64 de biţi. Semnul numărului este dat de cel mai semnificativ bit.
79 78 64 63 0
-
s
|
caracteristică
|
1
|
mantisă
|
Numerele flotante cu precizie ridicată nu sunt întotdeauna normalizate, motiv pentru care numărul nu începe obligatoriu cu un bit de 1. Deci lungimea mantisei, în acest caz, este doar de 64 de biţi. Mantisa normalizată pe 64 de biţi a numerelor reale cu precizie ridicată reprezintă aproximativ 19 cifre zecimale. Caracteristica are o lungime de 15 biţi. Deoarece numărul nu este reprezentat întotdeauna normalizat cel mai mic număr reprezentabil este mult mai mic decât cel la care ne aşteptăm: este în jur de 10 la puterea –4932. Acest mod de reprezentare este foarte sensibil la faptul dacă numărul este diferit sau nu de 0.
Complementul faţă de doi
Principiul metodei: ne lipsim de unul din biţii care ne stau la dispoziţie (cel mai semnificativ) acesta va reprezenta semnul. Numărul zero este reprezentat de un şir de biţi de 0. Pornind de aici obţinem numerele pozitive prin mărire. Numerele negative se obţin prin scădere. Pentru un număr de opt biţi avem:
nr. zecimal nr. binar
-
0
1
2
122
127
|
0000 0000
0000 0001
0000 0010
...... ......
0111 1010
0111 1111
|
-1
-2
...
-122
-128
|
1111 1111
1111 1110
.... ...
1000 0110
1000 0000
|
Pentru orice număr de biţi, semnul numărului este conţinut în cel mai semnificativ bit. Dacă acest bit este zero numărul este pozitiv şi dacă e unu numărul e negativ. Să reţinem cel mai simplu algoritm de conversie:
Să inversăm toate cifrele binare şi să adunăm 1 la rezultat. Să nu ţinem cont de depăşire.
Primul mod este utilizarea instrucţiunii NEG caz în care procesorul efectuează conversia. Un alt mod este utilizarea instrucţiunilor NOT (care ne dă complementul faţă de unu şi INC. Cele două căi diferă prin efectele laterale, vor exista cazuri în care după calculul complementului faţă de doi cu cele două metode, ”flag”-urile vor fi poziţionate în mod diferit pentru cele două cazuri. Pentru conversia unor întregi mai lungi avem o singură metodă: aplicăm NOT pentru fiecare octet apoi octetul cel mai puţin semnificativ îl incrementăm cu unu asigurând transportul prin tot numărul:
VERYLONG DQ ? ;întreg foarte lung
NOT WORD PTR VERYLONG ;inversăm
NOT WORD PTR VERYLONG+2 ;atent
NOT WORD PTR VERYLONG+4 ;toţi
NOT WORD PTR VERYLONG+6 ;biţii
ADD WORD PTR VERYLONG, 1 ;incrementăm
ADC WORD PTR VERYLONG, 0 ;numărul
ADC WORD PTR VERYLONG, 0 ;cu unu
ADC WORD PTR VERYLONG, 0 ;
Următoarea problemă este reprezentarea numerelor în BCD împachetat. După cum urmează să vedem vom putea utiliza numerele BCD foarte comod nu numai cu ajutorul coprocesorului ci şi din program. Dar operaţiile cu numerele BCD cu semn introduc unele probleme In care vor ieşi la iveală adevăratele avantaje ale reprezentării în complement faţă de doi.
După cum s-a mai descris, un număr BCD ocupă 10 octeţi, are 18 cifre şi bitul cel mai semnificativ este bitul de semn. Să vedem un astfel de număr BCD creat de asamblor. Prezentăm o parte dintr-un program exemplu:
0000 56 34 12 00 00 00 00 00 00 BCD1 DT 123456
000A 56 34 12 00 00 00 00 00 80 BCD2 DT -123456
Această bucată de segment de date conţine doi operatori DT, valorile lor iniţiale fiind opuse. se vede că cifrele ocupă 4 biţi şi cifra cea mai semnificativă va fi reprezentată pe cei 4 biţi mai puţin semnificativi ai zonei de 10 octeţi. Semnul numărului este în cei mai semnificativi 4 biţi şi din aceştia cel mai semnificativ bit.
După cum se cunoaşte, operaţiile adiţionale (adunarea şi incrementarea respectiv scăderea şi decrementarea) se pot efectua simplu cu numere reprezentate în BCD. Dar deşi înmulţirea şi împărţirea în BCD sunt susţinute de codul maşină, în limbaj de asamblare aceste operaţii ne creează dificultăţi. Să ne gândim la faptul că unul din cei mai complicaţi algoritmi ai matematicii elementare este împărţirea. Împărţirea binară este mult mai simplă decât împărţirea numerelor zecimale deoarece nu trebuie să “nimerim” câtul, însă “a aduce următoarea cifră” este forte greu de realizat în limbaj de asamblare.
Totuşi algoritmul împărţirii binare este mult mai simplu decât cel în BCD deoarece în BCD, din punct de vedere algoritmic numerele sunt descrise în zecimal şi nu în binar. Dacă admitem însă şi reprezentarea numerelor zecimale în BCD obţine o reprezentare mai exactă: această reprezentare nu face rotunjiri şi numărul 58. 3 se poate reprezenta exact.
Să vedem în continuare problema reprezentării numerelor în virgulă flotantă. Este clar că numărul 0. 0000 este reprezentat doar cu biţi de 0. Reprezentarea numărului 1. 0000 (eticheta lui este FL1). După cum s-a observat în prezentarea scurtă anterioară primul bit al mantisei este obligatoriu 1. Avem deci reprezentarea:
1. 0000x2
La valoarea FL1 (citind de sus în jos 3F 80 00 00). Valoarea mantisei este un şir de 0-uri deoarece primul 1 este considerat implicit. Caracteristica este FFH, dar de ce? Răspunsul este caracteristica trebuie reprezentată mărită cu FFH pentru ca în operaţiile cu caracteristici să nu trebuiască să operăm cu reprezentarea în complement faţă de doi. De aici avem deja clar reprezentarea numărului 2. 0
1. 00000x2
unde mantisa este un şir de zerouri, iar caracteristica 80H. (FFH+1)
Avem acest lucru în numărul FL2 reprezentat prin 40 00 00 00.
Puterile mai mari a lui doi se tratează identic, cu mărirea continuă a caracteristicii, iar valorile negative se tratează simplu prin poziţionarea pe 1 a bitului cel mai semnificativ. De aici şi citirea corectă a numărului 2. 00000 este 0[bit semn], 80[caracteristică] şi 23 de 0[mantisă].
Pentru următorul exemplu pornim de la numărul 1. 00000, dar de data aceasta nu se înmulţeste ci se împarte cu doi. Nici în acest caz nu avem o schimbare semnificativă în mantisa numerelor, ea va rămâne în continuare 23 de 0. Ca urmare a împărţirilor repetate caracteristica începe să se descarce.
După cum se poate observa din numărul FLO5 lipseşte valoarea 80 a celui de-al doilea octet, deci caracteristica scade de la 7FH la 7EH s. a. m. d. Pentru variantele negative, bitul cel mai semnificativ se poziţionează pe 1, simbolizând semnul negativ.
În pasul următor se folosesc cu numere care nu sunt puteri ale lui doi. Valorile numerice sunt: 3. 00000 înmulţit cu puteri ale lui doi.
Prima observaţie este că numărul 3. 00000 diferă doar printr-un singur bit de numărul 2. 00000. Acest bit se află în al doilea octet pe poziţia 6. Acesta este de fapt bitul cel mai semnificativ al mantisei. Adăugând bitul cel mai semnificativ, implicit al mantisei, rezultă mantisa “1100” în care punctul se înţelege între cei doi biţi unu. Valoarea caracteristicii este desigur 1.
Valorile negative corespunzătoare numerelor de mai sus se obţin identic ca în cazurile anterioare, deci nu se vor trata.
Valoarea aproximativă a lui 1/3 (este o fracţie infinită deci se poate reprezenta doar trunchiat) este următoarea: 0[bit semn], 7D[caracteristică], apoi pe 23 de biţi secvenţa 0101.... Valoarea 7D a caracteristicii “valorează” –2, deoarece numărul este mai mic decât ½.
0064 AA AA AA 3E FL03 DD 0. 333...
In final numerele reprezentate în dublă precizie şi în precizie ridicată. se propune în această parte să prezentarea definiţiilor utilizate.
Caracteristica numărului în dublă precizie este de 12 biţi, valoarea complementară e 3FFH. Citirea reprezentarii în dublă precizie a numărului 1. 00000:
0[bit semn] 3FFH[caracteristică, cu bitul semn 0] 52 buc de biţi 0 (din care rezultă 53 de biţi adăugând 1 implicit).
La numerele reprezentate în precizie ridicată caracteristica este de 15 biţi; cel mai semnificativ bit al celui de-al treilea octet pornind de la cel mai semnificativ este parte a mantisei.
Înainte de a termina analiza reprezentării numerelor se remarcă avantajul reprezentării numerelor cu caracteristică deplasată. La compararea a două numere efectuăm comparaţia celor două pornind de la bitul cel mai semnificativ; prima valoare diferită va decide care din ele este mai mare. În cazul reprezentării în complement faţă de doi compararea ar fi mult mai complicată.
În reprezentarea internă a coprocesorului avem câteva cazuri speciale. Coprocesorul cunoaşte 0-ul negativ şi se poate reprezenta infinitul şi a infinitul cu semn.
Valoarea fizică 0 a caracteristicii este o valoare specială nedefinită.
Erori de operaţie (excepţii)
La efectuarea operaţiilor în virgulă flotantă putem avea numeroase erori începând de la erori logaritmice triviale, până la erorile provenite din limitele reprezentării. Acestea le vom numi excepţii. În continuare vom cunoaşte tipurile acestor erori şi posibilităţile principale de manevrare a lor.
În cazul apariţiei erorilor, coprocesorul poate avea două tipuri de comportare. Anunţă eroarea printr-o întrerupere dacă utilizatorul validează acest lucru. Dacă nu validăm întreruperea, coprocesorul va trata intern eroarea şi în funcţie de erorile apărute va acţiona în modul prezentat în continuare. Proiectanţii coprocesorului au clasificat erorile în următoarele 6 clase:
Invalid operation operaţie invalidă
Aceasta poate fi: depăşire superioară sau inferioară a stivei interioare a coprocesorului. Depăşirea inferioară apare în cazul în care vrem să accesăm un element din stivă care nu există. Acestea sunt de obicei erori (destul de grave) algoritmice; coprocesorul nu afectează operaţia.
Avem rezultat nedefinit în cazul în care încercăm să împărţim 0. 0 cu 0. 0, coprocesorul nu este pregătit pentru aceasta. Cazuri similare apar la scăderea lui infinit din infinit, etc. Aceste erori (deşi se pot evita prin algoritm) nu sunt erori atât de grave ca cele de depăşire inferioară sau superioară a stivei.
Avem tot acest “rezultat” dacă o funcţie de coprocesor este apelată ca parametrii necorespunzători.
În cazul apariţiei rezultatului nedefinit coprocesorul înscrie în caracteristică o valoare rezervată pentru acest caz (biţi de zero).
Overflow depăşire superioară
Rezultatul depăşeşte numărul cel mai mare ce se poate reprezenta. Coprocesorul înscrie infinit în locul rezultatului şi continuă lucrul.
Zero Divizor împărţire cu zero
Împărţitorul împărţirii de efectuat este zero, iar deîmpărţitul nu este zero sau infinit. Coprocesorul înscrie în locul rezultatului infinit şi continuă lucrul.
Underflow depăşire inferioară
Valoarea rezultatului în modul este mai mică decât numărul cel mai mic reprezentabil. Rezultatul va fi zero, coprocesorul continuă lucrul.
Denormalized Operand operand nenormalizat
Această excepţie apare dacă unul din operanzi nu este normalizat sau rezultatul nu se poare reprezenta normalizat (de exemplu este atât de mic încât este imposibilă normalizarea lui). Coprocesorul continuă lucrul (valorile diferite de zero se pierd, vor fi zero).
Inexact result Rezultat inexact
Rezultatul operaţiei este inexact din cauza unor rotunjiri prescrise sau necesare. Putem avea astfel de rezultate după împărţire, dacă împărţim de exemplu 2. 0 cu 3. 0 rezultatul se poate reprezenta doar ca o fracţie infinită. Coprocesorul efectuează rotunjirea şi continuă lucrul.
Cele de mai sus sunt prezentate în funcţie de gravitatea erorii. Dacă apare o depăşire de stivă atunci programul este eronat; nu merită să se continue programul.
În acelaşi timp nu e nevoie să se trateze o de eroare de rotunjire. Nici pe hârtie nu putem manevra uşor fracţii cu repetiţie infinită sau cu numere iraţionale. Din punct de vedere practic este indiferent dacă pierdem a 20-a cifra a fracţiei sau nu, deoarece nu aceasta este elementul care poartă informaţia de bază. Pentru rezolvarea acestei probleme este necesară o analiză adâncă a situaţiilor şi rezultatelor care pot apărea în timpul execuţiei, a preciziei de reprezentare a numerelor, timpul de rulare şi mărimea memoriei. După cum am văzut la reprezentarea numerelor, precizia numerelor reale scurte nu este de ajuns pentru orice aplicaţie practică. Precizia numerelor reale lungi este mai mult ca sigur suficientă, dar necesită un spaţiu dublu de memorie.
Arhitectura internă a coprocesorului
Coprocesorul are două părţi funcţionale distincte:
-
Unitatea de execuţie numerică: execută instrucţiunile aritmetice şi de transfer specifice coprocesorului, are unitatea de execuţie şi blocul registrelor interne;
-
Unitatea de control: extrage instrucţiunile şi operanzii din memorie şi execută instrucţiunile de control, are un bloc logic şi registrele indicatoare şi de control;
Unitatea de execuţie numerică
Din punct de vedere al utilizatorului componenta cea mai importantă este blocul de registre generale, care este organizată sub forma unei stive interne. Toate registrele (elementele stivei) au o lungime de 80 de biţi. Fiecare operaţie adresează elementul din vârful stivei. Din acest motiv elementul stivei se notează cu ST (0), ST (1)... etc, unde ST (0) este capul stivei, ST (1) este elementul următor şi aşa mai departe. Este un inconvenient la programarea în limbaj de asamblare, trebuie să reţinem în fiecare moment, poziţia în stivă a fiecărei valori, iar la introducerea unui nou element pe stivă indicele elementelor introduse anterior se incrementează.
Unitatea de control
Registrul de control (Control Word)
Registrul de control este un registru de 16 biţi. Utilizatorul poate seta conţinutul şi astfel poate controla o serie de mecanisme “fine” ale coprocesorului ca de exemplu metoda utilizată la rotunjire etc.
După cum se poate vedea registrul este împărţit în două, deoarece în timp ce primii 8 biţi (cei mai semnificativi) determină strategia de funcţionare a procesorului, restul de 8 biţi se referă la comanda întreruperilor în cazul erorilor.
15
|
14
|
13
|
12
|
11
|
10
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
x
|
X
|
X
|
ip
|
rc
|
rc
|
pc
|
pc
|
x
|
x
|
pm
|
um
|
om
|
zm
|
dm
|
im
|
Unde biţii cu x sunt nefolosiţi.
Ceilalţi biţi sunt:
IC - Infinit Control-modul de tratare a numerelor infinite.
La împărţirea cu zero coprocesorul scrie în locaţia câtului infinit. În sens matematic avem două tipuri de închidere a axei numerelor: proiectiv şi affin. În linii mari diferenţa este că închiderea affină cunoaşte două tipuri de infinit (pozitiv şi negativ), iar cea proiectivă doar unul singur. Nici una din metode nu este mai “bună”. Semnificaţia bitului:
0-proiectiv
1-affin
RC - Rounding Control-controlul rotunjirii
00-rotunjire la cel mai apropiat element reprezentabil
01-rotunjire în jos
10-rotunjire în sus
11-trunchiere
PC - Precision Control-controlul preciziei de calcul
În unele cazuri nu se doreşte ca să lucrăm cu rezultatul reprezentat cu precizia reprezentării interne deşi el este reprezentat întotdeauna la astfel. Dacă lucrăm cu proceduri scrise anterior care operează cumva cu erorile rotunjite a numerelor reprezentat clasic pe 4 octeţi atunci precizia mare poate cauza dificultăţi.
Valorile perechilor de biţi P. C.
00-24 biţi-real scurt
01-ocupat
10-53 biţi-precizia pt real lung
11-63 biţi-precizia ridicată
M. Mask - validarea sau invalidarea întreruperii coprocesorului. La erorile intervenite în timpul execuţiei operaţiilor în virgulă flotantă, coprocesorul transmite întreruperi procesorului. Întreruperea creată pe IBM-PC este NMI întreruperea nemascabilă a procesorului.
Valorile bitului MASK:
0-validare cerere de întrerupere;
1-invalidare cerere întrerupere;
Cu următorii biţi specificăm care din excepţii (erori) să apeleze întradevăr întreruperea. Acest lucru poate fi util în cazurile când nu ne interesează o anumită excepţie sau dacă vrem să controlăm problema prin citirea stării coprocesorului din program. Următorii biţi validează întreruperea cu 0 şi o invalidează cu 1.
PM Precision Mask -întreruperea pentru semnalarea rotunjirii
UM Underflow Mask - întreruperea pentru semnalarea depăşirii inferioare
OM Overflow Mask - întreruperea pentru semnalarea depăşiriisuperioare
ZM Zero Devide Mask - întreruperea pentru semnalarea împărţirii cu 0
DM Denormalized OM - întreruperea pentru semnalarea operandului
IM Invalid Operation Mask - întreruperea pentru semnalarea operaţiei invalide
Registrul de stare (Status Word)
Este un registru de 16 biţi. Conţinutul se setează conform ultimei operaţii efectuate. Cu ajutorul lui avem informaţii vitale pentru utilizator. Este important că din primii 8 biţi (cel mai semnificativ) doi corespund exact cu biţii de carry zero din registrul de stare a procesorului I 8086. Deoarece cu instrucţiunea SAHF putem încărca orice valoare pe ultimii 8 biţi a lui STATUS, după o operaţie de coprocesor putem citi şi utiliza aceşti biţi cu instrucţiuni simple de predare condiţionată de control.
15
|
14
|
13
|
12
|
11
|
10
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
B
|
C3
|
St
|
St
|
St
|
St
|
C2
|
C1
|
C0
|
Es
|
X
|
Pe
|
Ue
|
Ze
|
De
|
Ie
|
Şi în acest caz avem împărţit registrul de 16 biţi în două părţi. Cei mai semnificativi opt biţi ne arată dacă operaţia efectuată de coprocesor ar efectua întrerupere şi dacă da atunci ne arată de care excepţie e produsă întreruperea. Cei mai semnificativi opt biţi reprezintă starea aritmetică a coprocesorului:
IR Interrupt Request-dacă are valoarea 1 arată că coprocesorul prezintă o cerere de întreruperi. În acest caz unul din următorii şase biţi va fi şi el pe 1, el va arăta clasa în care aparţine eroarea.
IE Invalid Operation Error-operaţie invalidă
DE Denormalized Operand Error - eroarea e cauzată de operand nenormalizat sau rezultat care nu poate fi normalizat
ZE Zero Devide Error - eroare cauzată de împărţirea cu zero
OE Overrflow Error - eroare cauzată de depăşirea superioară
UE Underflow Error - eroare cauzată de depăşirea inferioară
PE Precision Error - eroare de precizie, rezultatul a fost rotunjit
C0 (bitul condiţional 0)
C1 (bitul condiţional 1)
C2 (bitul condiţional 2)
C3 (bitul condiţional 3)
SP - cei trei biţi arată vârful stivei. Valoarea 000 semnalează stiva goală, primul element ce se încarcă va fi în elementul 0 al stivei, iar valoarea 111 semnalează stiva plină.
B Busy - semnalează faptul că coprocesorul lucrează sau nu. Este activ pe 1, deci în acest caz nu avem voie să transmitem altă comandă coprocesorului. Acest bit ne permite o sincronizare software a programului nostru cu coprocesorul.
Semnificaţia biţilor C0, C1, C2, C3 este reprezentată în tabele. După cum se observa definirea acestor biţi nu este simplă. În practică este necesara verificarea doar a unu sau doi biţi, care este relativ simpla dacă ne bazăm pe observaţia făcută la începutul acestui capitol: putem utiliza faptul că pe poziţia flag-urilor STATUS zero şi Carry avem biţi condiţionali cu aceeaşi semnificaţie.
C3
|
C2
|
C1
| C0 |
Semn
|
Semnificaţie
|
0
0
0
0
|
0
0
0
0
|
0
0
1
1
|
0
1
0
1
|
+
+
-
-
|
Nenormalizat
Nu e număr
Nenormalizat
Nu e număr
|
0
0
0
0
|
1
1
1
1
|
0
0
1
1
|
0
1
0
1
|
+
+
-
-
|
Normalizat pozitiv
Pozitiv infinit
Normalizat
Negativ infinit
|
1
1
1
1
|
0
0
0
0
|
0
0
1
1
|
0
1
0
1
|
+
gol
-
gol
|
Zero (pozitiv)
............
zero (negativ)
............
|
1
1
1
1
|
1
1
1
1
|
0
0
1
1
|
0
1
0
1
|
+
gol
-
gol
|
Invalid, nenormalizat
.............
Invalid, nenormalizat
.............
|
Valoarea bitului C3 este 0 dacă rezultatul operaţiei (normalizat sau nenormalizat) este diferit de zero. dacă valoarea bitului e 1 atunci rezultatul este ori zero ori invalid sau elementul respectiv al stivei e gol. Se poate spune că bitul C3 corespunde în linii mari cu bitul STATUS zero. Valoarea bitului C2 depinde de C3. Dacă valoarea bitului C3 este zero bitul C2 indică rezultat normalizat pe 1, iar rezultatul nenormalizat pe 0. dacă valoarea bitului C3 este 1 (deci rezultatul este 0 sau elementul e gol) atunci exact invers, valoarea 1 a lui C2 indică număr invalid, iar valoarea zeri indică zero.
Bitul C1 după cum am văzut din tabel se referă la semnul numărului. Dacă rezultatul e negativ valoarea lui C1 este 1 altfel e 0. Bitul C0 se referă la faptul că rezultatul este valid sau nu. Dacă acest bit este pe zero nu sunt erori grave dar dacă este pe 1 rezultatul este oricum invalid (nu e număr, este infinit sau altă valoare specială).
Dacă însă se efectuează alte operaţii decât cele obişnuite în virgulă flotantă ca de ex. Operaţii de comparare, atunci se schimbă semnificaţia biţilor:
C3
|
C2
|
C1
|
C1
|
Semnificaţia
|
0
0
1
1
|
0
0
0
0
|
X
X
X
X
|
0
1
0
1
|
ST (0) >”op”
ST (0) <”op”
ST (0) =”op”
ST (0) şi “op” nu se pot compara
|
Deci dacă C3 este 0 atunci rezultatul comparaţiei se va citi din bitul C0. Dacă C3 este 1 atunci C2 va indica dacă numerele sunt sau nu egale sau ST (0) nu este comparabil (e gol sau infinit).
După operaţia de creare a restului parţial avem din nou altă semnificaţie a acestor biţi. În acest caz C0, C1 şi C3 (de sus în jos în această ordine) vor conţine cei unu, doi sau trei biţi ai câtului la împărţirea cu rest. Valoarea lui C2 este 0 după crearea unui rest parţial şi este 1 în cazul unei erori. Semnificaţie este (despre crearea de rest parţial vom vorbi la descrierea comenzii) :
Raportul
Împărţitor/de împărţit
|
C3
|
C1
|
C0
|
Împărţitor>de împărţit/2
Împărţitor>de împărţit/4
Împărţitor<=de împărţit/4
|
X
X
Bitul 2
|
X
Bitul 1
Bitul 1
|
Bitul 0
Bitul 0
Bitul 0
|
X semnifică faptul că în cazul respectiv biţii respectivi îşi păstrează valoarea anterioară. De exemplu, dacă împărţitorul e mai mare ca deîmpărţitul atunci restul parţial este identic cu deîmpărţitul iar câtul este zero. În acest caz C3 şi C1 rămân la valoarea anterioară, iar C0 va fi zero semnificând că câtul este zero. Iar dacă împărţitorul este mai mic decât jumătatea deîmpărţitului dar mai mare decât un sfert din deîmpărţit atunci câtul va fi doi sau trei; avem acest număr în C1, C0 iar C3 păstrează valoarea anterioară.
Registrul indicator de deschidere a stivei (Tag Word)
15 14
|
13 12
|
11 10
|
9 8
|
7 6
|
5 4
|
3 2
|
0 1
|
R7
|
R6
|
R5
|
R4
|
R3
|
R2
|
R1
|
R0
|
Perechile de biţi alcătuiesc de jos în sus regiştri de descrierea elementelor 0. 1... etc ale stivei.
O pereche de biţi poate avea următoarele semnificaţii:
Valoarea perechilor |
Semnificaţia de biţi din reg. de descriere a stivei
|
00
|
Elementul corespunzător conţine dată validă
|
01
|
Elementul corespunzător conţine zero
|
10
|
Elementul corespunzător conţine valoare specială
|
11
|
Elementul corespunzător e gol
|
Termenul de “valoare specială” înseamnă că elementul stivei conţine infinit sau dintr-o cauză oarecare conţinutul ca rezultat al unei operaţii este invalid.
Registrul de instrucţiuni (Instruction Pointer)
Registrul de instrucţiuni conţine adresa fizică şi codul operaţiei al ultimei operaţii efectuate de coprocesor.
Acest registru ne ajută în cazurile în care scriem rutine de întreruperi pentru tratarea erorilor ce apar în timpul operaţiilor de coprocesor. În astfel de cazuri este important să cunoaştem codul operaţiei şi adresa fizică (locaţia de memorie internă unde se află). Putem vedea uşor importanţa acestuia gândindu-ne la faptul că programul nu este nevoit să aştepte coprocesorul, în timp ce acesta lucrează procesorul poate efectua alte operaţii. Doar atunci trebuie să luăm în considerare coprocesorul când avem nevoie de rezultat sau vrem să efectuăm o altă operaţie.
În acest moment însă (deoarece programul nostru a trecut de mult de instrucţiunea care a cauzat eroarea) nu putem afla altfel care a fost ultima instrucţiune trimisă coprocesorului. Spaţiul rezervat codului de instrucţiune este mai mare decât mărimea reală a codului deci codul apare aliniat la dreapta.
Registrul de date (Data Pointer)
Registrul de date conţine adresa fizică a datei externe utilizate de ultima instrucţiune în virgulă flotantă.
Asemenea cu cel dinainte acest registru ne foloseşte la scrierea rutinelor de întrerupere pentru tratarea erorilor apărute în timpul executării instrucţiunilor de coprocesor. În acest caz trebuie să cunoaştem adresa fizică a datei (externe pentru coprocesor) utilizată de instrucţiunea care a cauzat eroarea.
Pentru utilizatorul care lucrează în limbaj de asamblare este important să cunoască condiţiile din coprocesor adică mediul coprocesorului care definesc condiţiile de lucru şi stare la un moment dat. Acest mediu se defineşte pe baza elementelor cunoscute.
Mediul coprocesorului (enviroment)
Înseamnă registrele interne la care are acces utilizatorul. Coprocesorul matematic are un set de registre cu lungime totala de 14 octeţi, organizate ca în figură:
REGISTR DE COMANDĂ
|
REGISTRU DE STARE
|
REGISTRU STIVĂ
|
REGISTRU DE INSTRUCŢIUNI (A15-0)
A19-16 | 0 | CODUL OPERAŢIEI (biţii 10-0)
|
REGISTRU DE DATE (A15-0)
A19-16 | 0 . . .. . . . . . . . . . . . .. . . . . .. . . . .. . . . . . .. . . . . . . . .. . . 0
| Setul de instrucţiuni al coprocesorului
Programarea coprocesorului se face în limbajul de asamblare cu ajutorul instrucţiunii ESC. Această instrucţiune trimite pe magistrala de date un cod de operaţie pe 6 biţi şi dacă este necesar trimite pe magistrala de date o adresă de memorie. Coprocesorul sesizează şi “captează” instrucţiunea ce i se adresează şi începe execuţia instrucţiunii. Există două posibilităţi de resincronizare a procesorului cu coprocesorul, ambele la iniţiativa procesorului:
- procesorul testează starea coprocesorului;
- procesorul lansează o instrucţiune WAIT;
Instrucţiuni de transfer de date
Instrucţiunile de transfer de date asigură schimbul de date între memoria calculatorului şi stiva coprocesorului. Ele se pot împărţi în următoarele categorii:
Instrucţiuni de încărcare (LOAD)
FILD adr -Încarcă pe stivă variabila întreagă de la adresa “adr”. Variabila din memorie de tipul definit la declararea lui (DB, DW, DD) se converteşte în formatul intern al coprocesorului în timpul încărcării
FLD adr -Încarcă pe stivă valoarea reală (scurtă sau lungă) de la adresa de memorie “adr”. Variabila din memorie de tipul definit la declararea lui (DD, DQ, DT) se converteşte în formatul intern al coprocesorului în timpul încărcării.
FBLD adr -Încarcă pe stivă variabila din memorie de tipul zecimal împachetat (definit cu DT) de la adresa de memorie “adr”. Are loc convertirea în formatul intern al coprocesorului în timpul încărcării.
Instrucţiuni de memorare (STORE)
FIST adr -memorează la adresa “adr” valoarea de pe stivă (ST (0) ) ca număr. Valoarea memorată poate fi numai întreg pe cuvânt sau întreg scurt, în funcţie de definiţia de la adresa “adr” (DW sau DD). indicatorul de stivă nu se modifică în urma memorării. În timpul memorării are loc convertirea.
FISTP adr -memorează la adresa “adr” valoarea de pe stivă (ST (0) ) ca număr întreg. Valoarea memorată poate fi orice număr întreg (pe cuvânt, scurt sau lung în funcţie de definiţia de la adresa “adr” DW, DD sau DQ). În timpul memorării are loc convertirea necesară. Instrucţiunea afectează stiva: ST (0) este eliminat prin decrementarea indicatorului de stivă.
FST adr -memorează la adresa “adr” valoarea de pe stivă (ST (0) ) ca număr întreg. Valoarea memorată poate fi număr întreg scurt sau dublă precizie în funcţie de definiţia de la adresa “adr” DD sau DQ. În timpul memorării are loc convertirea necesară. Indicatorul de stivă şi conţinutul stivei nu se modifică în urma memorării.
FSTP adr -memorează la adresa “adr” valoarea de pe stivă (ST (0) ) ca număr în reprezentarea în virgulă mobilă. Valoarea memorată poate număr real scurt, cu precizie dublă sau extins, în funcţie de definiţia de la adresa “adr” (DD, DQ sau DT). În timpul memorării are loc convertirea necesară din formatul intern. Instrucţiunea afectează stiva: ST (0) este eliminat prin decrementarea indicatorului de stivă.
FBSTP adr -memorează la adresa “adr” valoarea de pe stivă (ST (0) ) ca număr zecimal împachetat (definit la “adr” de regulă cu DT). Indicatorul de stivă este decrementat. În timpul memorării are loc convertirea necesară din formatul inter.
Observaţie: Este de reţinut faptul că se poate încărca orice tip de date. La memorare sunt
două situaţii: dacă se elimină data de pe stivă se poate lucra cu cele 7 tipuri de date. Dacă
însă se menţine valoarea memorată şi pe stivă sunt permise numai cele 4 tipuri de bază.
Instrucţiuni transfer de date intern
FLD ST (i) Pune pe stivă valoarea de pe ST (i). Deci valoarea din ST (i) se va găsi de două ori: în ST (0) şi ST (i+1).
FST ST (i) Valoarea din ST (0) este copiată în elementul “i” din stivă. Valoarea veche din ST (i) se pierde.
FSTP ST (i) Valoarea ST (0) este copiată în elementul “i” din stivă. Valoarea veche din ST (i) se pierde. ST (0) este eliminat prin decrementarea indicatorului din stivă.
FXCH ST (i) Se schimbă între ele ST (0) şi ST (i).
Instrucţiuni încărcare a constantelor
FLDZ Încarcă zero pe vârful stivei.
FLD1 Încarcă 1. 0 pe vârful stivei.
FLDPI Încarcă “pi” pe vârful stivei
FLDL2T Încarcă pe vârful stivei log (10)
FLDL2E Încarcă pe vârful stivei log (e)
FLDLG2 Încarcă pe vârful stivei log (2)
FLDLN2 Încarcă pe vârful stivei ln (2)
Instrucţiuni aritmetice şi de comparare
Instrucţiunile aritmetice sunt în general cu doi operanzi. Unul din operanzi este totdeauna în vârful stivei şi de regulă tot aici se generează rezultatul. Operaţiile de bază se pot executa fără restricţii cu următoarele variante:
-se scrie numai mnemonica instrucţiunii fără operand. În acest caz operanzii impliciţi sunt ST (0) şi ST (1).
-se scrie mnemonica instrucţiunii şi operandul. Operandul poate fi o locaţie de memorie sau un element de pe stivă (bineînţeles că şi ST (1) se poate dar e inutil).
-se scrie mnemonica instrucţiunii şi doi operanzi: primul un element de pe stivă (nu ST (0), al doilea ST (0). În acest caz rezultatul se va depune în locul primului operand iar ST (0) se şterge de pe stivă. (În mnemonica instrucţiunii apare litera P).
Instrucţiuni aritmetice
FADD ST (0) ST (0) +ST (1)
FADD op ST (0) ST (0) +”op”din memorie sau stivă
Operaţie în virgulă mobilă
FADD op ST (0) ST (0) +”op” din memorie sau stiva
Operaţie cu date întregi
FADD ST (i), ST (0) ST (i) ST (i) +ST (0) ;ST (0) se elimină
FSUB ST (0) ST (0) -ST (1)
FSUB op ST (0) ST (0) -“op” din memorie sau stivă
Operaţie în virgulă mobilă
FISUB op ST (0) ST (0) -“op” din memorie sau stiva
Operaţie cu date întregi
FSUB ST (i), ST (0) ST (i) ST (i) -ST (0) ;ST (0) se elimină
FSUBR ST (i) ST (i) ST (i) -ST (0) ;Este opusul instrucţiunii FSUB ST (i)
FMUL ST (0) ST (0) XST (1)
FMUL op ST (0) ST (0) x”op” din memorie sau stivă.
Operaţie în virgulă mobilă
FIMUL op ST (0) ST (0) x”op” din memorie sau stivă
Operaţie cu date întregi
FMULP ST (i), ST (0) ST (i) ST (i) xST (0) ;ST (0) se elimină
FDIV ST (0) ST (0) : ST (1)
FDIV op ST (0) ST (0) : ”op”din memorie sau stivă
Operaţie în virgulă mobilă
FDIV op ST (0) ST (0) : ”op” din memorie sau stivă
Operaţie cu date întregi
FDIVP ST (i), ST (0) ST (i) ST (i) : ST (0) ;ST (0) se elimină
FDIVR ST (i) ST (i) ST (i) : ST (0) ;Este opusul instrucţiunii FDIV ST (i).
Instrucţiuni pentru compararea valorilor numerice
FCOM Se compară valorile din ST (0) şi ST (1) poziţionând indicatorii C3, C2 şi C0
FCOM op Se compară valorile din ST (0) şi din memorie sau stivă (variabilă în virgulă mobilă) poziţionând indicatorii C3, C2 şi C0.
FICOM op Se compară valorile din ST (0) şi din memorie sau stivă (variabilă întreagă) poziţionând indicatorii C3, C2 şi C0.
FCOMP Se compară valorile din ST (0) si ST (1), poziţionând indicatorii C3, C2 şi C0. Se elimină ST (0) de pe stivă.
FICOMP op Se compară valorile din ST (0) şi din memorie sau stivă (variabilă întreagă) poziţionând indicatorii C3, C2 şi C0. ST (0) se elimină de pe stivă.
FCOMPP Se compară valorile din ST (0) şi ST (1), poziţionând indicatorii C3, C2 şi C0. Se elimină ST (0) şi ST (1) de pe stivă.
FTST Poziţionează indicatorii C3, C2 şi C0 în funcţie de rezultatul comparării valorii din ST (0) cu zero.
FXAM Poziţionează biţii de condiţie în funcţie de valoarea din ST (0). Nu se face comparaţie!
Observaţii:
- FCOMP şi FCOMPP oferă posibilitatea cea mai facilă de a elimina una sau două elemente de pe stivă
-
FXAM se foloseşte pentru analiza condiţiilor mai deosebite de erori de calcul.
Funcţii în virgulă mobilă
FSQRT Radical –rădăcina pătrată a numărului din ST (0) se scrie în ST (0). Numărul trebuie să fie pozitiv, altfel rezultatul nu are sens.
FSCALE Puterea lui 2. Scrie în ST (0) valoarea lui ST (0) înmulţită cu 2 la puterea ST (1), adică:
ST (0) ST (0) *2**ST (1) ST (1) trebuie să fie număr întreg, iar valoarea absolută din ST (0) să fie mai mic de 2**15.
FPREM Calculul restului parţial. ST (0) se împarte cu ST (1) şi pune în ST () ST (0) -ST (1) * (întregul mai mic cel mai apropiat de ST (0) /ST (1) ).
FRMDINT Rotunjire. în locul lui ST (0) se pune ST (0) rotunjit. Strategia de rotunjire se stabileşte în cuvântul de comandă.
FXTRACT Valoarea din ST (0) se desface în caracteristică (în ST (0) ) şi mantisa (în ST (1) ).
FABS În locul lui ST (0) se pune valoarea lui absolută.
FCHS Schimbarea semnului ST (0).
FPTAN Tangenta parţială. Tangenta unghiului din ST (0) este calculată ca o fracţie ST (1) /ST (0). Valoarea iniţială a unghiului din ST (0) trebuie să fie între 0 şi “pi”/4.
FPATAN Arctangentă parţială. În ST (0) se va încărca arctangenta valorii ST (1) /ST (0). Iniţial ST (0) trebuie să fie pozitiv, iar ST (1) mai mare ca ST (0).
F2XM1 Calculul puterii lui 2. În locul lui ST (0) se va scrie 2**ST (0) -1. Iniţial ST (0) trebuie să fie cuprins între 0 şi 0. 5.
FYL2X Logaritmare. ST (0) ST (1) *LOG2 (ST (0) ). ST (0) trebuie să fie pozitiv, iar ST (1) orice număr finit.
FYL2XP1 Logaritmare. ST (0) ST (1) *LOG2 (ST (0) +1). ST (0) trebuie să fie pozitiv mai mic decât 0. 3, iar ST (1) orice număr finit.
Observaţii:
-
Cu ajutorul tangentei se pot calcula sin şi cos
-
Cu F2XM1 so poate calcula orice exponent
-
Pentru calculul de exponent ST (0) la puterea ST (1) se recomandă aplicarea succesiva a funcţiilor FYL2X apoi F2XM1!
Instrucţiuni de comandă
Instrucţiunile de comandă au ca sarcină coordonarea acţiunilor coprocesorului. De obicei nu au o semnificaţie aritmetică, dar există câteva care influenţează serios acţiunile aritmetice ale coprocesorului, deoarece ele salvează sau încarcă starea coprocesorului, adică toate registrele de lucru. În aceste registre este inclusă şi stiva, deci aceste instrucţiuni pot fi privite ca instrucţiuni gigantice de scriere şi salvare.
FINIT Iniţializare-aducerea coprocesorului într-o stare iniţială cunoscută; ”software reset”. După efectuarea instrucţiunii FINIT toate registrele coprocesorului se vor afla în starea iniţială iar stiva va fi goală.
FENI Acceptarea întreruperilor-pentru ca coprocesorul să genereze o întrerupere la apariţia unei erori, pe lângă poziţionarea biţilor corespunzători registrului de comandă este nevoie de acceptarea explicită a întreruperilor.
FDISI Ignorarea întreruperilor-această instrucţiune ignoră întreruperile indiferent de starea biţilor corespunzători ai registrului de comandă; pentru acceptarea unor noi întreruperi trebuie să avem o nouă instrucţiune FENI
FLDCW adr Încărcarea din memorie a registrului de comandă se încarcă în registrul de comandă cuvântul de la adresa “adr” de memorie
FSTCW adr Salvarea registrului de comandă în memorie-salvarea registrului de comandă în variabilă pe un cuvânt aflat în memorie.
FSTSW adr Salvarea registrului de stare-salvarea registrului de stare într-un cuvânt de memorie aflat la adresa “adr” de memorie.
FCLEX Ştergerea biţilor de definire a excepţiilor –instrucţiunea şterge biţii respectivi indiferent de starea biţilor de eroare.
FSTENV adr Salvarea mediului-se salvează registrele interne ale coprocesorului într-o zonă de memorie începând de la adresa “adr” şi având o lungime de 14 octeţi.
FLDENV adr Încărcarea mediului-se încarcă din memorie de la adresa “adr” o zonă de 14 octeţi în registrele interioare ale coprocesorului.
FSAVE adr Salvarea stării-salvarea stării coprocesorului (registrele interioare şi stiva) în zona de memorie care începe la adresa “adr” şi are o lungime de 94 octeţi.
FRSTOR adr Încărcarea stării –încărcarea stării coprocesorului (registrele interioare şi stiva) din zona de memorie care începe la adresa “adr” şi are o lungime de 94 octeţi.
FINCSTP Incrementarea indicatorului de stivă-după acţiunea instrucţiunii se incrementează cu un indicator de stivă; elementul care a devenit astfel ST (0) rămâne neschimbat (fapt semnalat de biţii corespunzători ai registrului de descriere a stivei).
FDECSTP Decrementarea indicatorilor de stivă-după executarea instrucţiunii indicatorul de stivă e decrementat cu unu; elementele stivei rămânând neschimbate (fapt semnalat de biţii corespunzători ai registrului de descriere a stivei).
FFREE ST (i) Ştergerea elementului “i” din stivă; operaţia nu afectează indicatorul de stivă.
FNOP Nici o operaţie.
FWAIT Aşteptare terminare operaţie curentă (analog cu instrucţiunea WAIT pentru 8086).
Exemplu de program simplu cu utilizarea coprocesorului matematic
;program pentru calculul ariei unui cerc de rază R
;şi a volumului unei sfere de rază R
DATE SEGMENT PARA 'DATA' ;DECLARARE SEGMENT DATE
RAZA DQ 8. 567
ARIE DQ ? ;REZERVARE LOC
VOLUM DQ ? ;REZULTATE
PATRU DD 4. 0
TREI DD 3. 0
DATE ENDS
COD SEGMENT PARA 'CODE' ;DECLARARE SEGMENT COD
CALCUL PROC FAR ;DECLARARE PROCEDURA FAR
ASSUME CS: COD, DS: DATE
PUSH AX ;REVENIRE IN DOS
MOV AX, DATE ;INCARCARE DS
MOV DS, AX ;CU SEGMENT DATE
FINIT ;INIŢIALIZARE COPROCESOR
FLD RAZA ;INCARCARE RAZA IN STIVA COPROC
FMUL RAZA ;CALCUL RxR
FLDPI ;INCARCARE PI PE STIVA COPOC
FMUL ;CALCUL RxRxPI
FSTP ARIE ;SALVARE REZULTAT
FWAIT ;SINCRONIZARE
LEA SI, VOLUM ;ADRESA VLUM IN SI
FINIT ;INITIALIZARE COPROCESOR
FLD RAZA ;CALCUL
FMUL RAZA ;RxR
FMUL RAZA ;RxRxR
FLDPI ;ICARCARE PI
FMUL ;INMULŢIRE CU PI
FMUL PATRU ;ÎNMULŢIRE CU PATRU
FDIV TREI ;IMPĂRŢIRE CU TREI
FSTP QWORD PTR[SI] ;SALVARE REZULTAT
FWAIT ;SINCRONIZARE
RET
CALCUL ENDP ;SFÂRŞIT PROCEDURĂ
COD ENDS ;SFÂRŞIT SEGMENT DE COD
END CALCUL ;SFÂRŞIT DE PROGRAM
Mersul lucrării
1. Se va rula exemplul prezentat
2. Se va scrie un program pentru calcularea radicalului de ordin 3 din 2. Indicaţie: se vor folosi instrucţiunile F2XM1 şi FYL2X.
Dostları ilə paylaş: |