CATEGORII DOCUMENTE |
Procesoare de 32 de biti Coprocesoare matematice
1 Arhitectura procesoarelor de 32 de biti
1.1 Generalitati
Aparitia si dezvoltarea procesoarelor Intel de 32 de biti a constituit o adevarata revolutie in domeniul calculatoarelor personale, atat prin cresterea, performantelor hardware (in special cresterea spatiului de memorie adresabil direct), cat si prin perspectivele deschise sistemelor de programe.
Procesoarele de 32 de biti sunt compatibile ca arhitectura cu cele de 16 biti, prin aceea ca registrele de 16 biti se regasesc ca subregistre ale registrelor de 32 de biti. Aceasta a permis ca setul de instructiuni al procesoarelor de 16 biti sa fie un subset al celui specific procesoarelor de 32 biti, ceea ce face ca orice program dezvoltat pentru procesoarele de 16 biti sa poata fi executat si pe masini de 32 de biti. In plus, toate instructiunile care utilizau operanzi de 16 biti se extind si asupra operanzilor de 32 de biti. Aceasta compatibilitate a setului de instructiuni a fost unul din scopurile declarate ale noii generatii de procesoare, pentru a conserva imensa cantitate de software dezvoltata anterior.
Figura 1 descrie registrele procesoarelor de 32 de biti, din punctul de vedere al programelor de aplicatie.
Exista opt registre generale de 32 de biti, care au numele registrelor generale de 16 biti, cu prefixul E (de la extended). Astfel, registrul EAX se numeste acumulator extins, ESP se numeste stack pointer extins etc. Primii 16 biti mai putin semnificativi ai acestor registre sunt disponibili si ca registre de 16 biti (AX, SP etc.), fiind practic identice cu registrele generale 8086.
Aceeasi abordare se regaseste si in cazul registrelor EIP (contor program extins) si EFLAGS (registru de flaguri extins). Subsetul de bistabili din registrul FLAGS se regaseste in partea low a registrului EFLAGS.
Registrele de segment au fost pastrate de 16 biti, dar s-au adaugat doua noi registre: FS si GS.
Pe langa registrele generale din Figura 1, procesoarele de 32 de biti dispun de registre de control, de gestiune a adresei, de depanare si de test. Acestea difera de la un tip de procesor la altul si sunt folosite in principal de programele de sistem.
Figura 1 Registrele procesoarelor de 32 de biti
Una din modificarile majore ale arhitecturii este semnificatia registrelor de segment, care actioneaza in general ca selectoare de segment. Acestea nu mai indica in mod nemijlocit adresa de baza a segmentului de memorie, ci un descriptor de segment (incarcat intr-un registru special de control) care precizeaza adresa de baza a segmentului, dimensiunea acestuia si drepturile de acces asociate. Abordarea respectiva permite ca adresa de baza si limita segmentului sa poata fi specificate pe 32 de biti, crescand dimensiunea maxima a unui segment pana la 4 GB.
1.2 Moduri de adresare pe 32 de biti
Modurile de adresare (formarea adresei fizice) au fost mult dezvoltate fata de cele pe 16 biti. Se introduc urmatoarele notiuni:
. deplasament - o valoare imediata pe 8 sau 32 de biti, continuta in instructiune;
. registru de baza - orice registru general de 32 de biti (spre deosebire de adresarea pe 16 biti unde ca registre de baza se utilizeaza doar BX si BP);
. registru index - orice registru general de 32 de biti, cu exceptia lui ESP (spre deosebire de adresarea pe 16 biti unde ca registre index se utilizeaza doar SI si DI);
. factor de scala - indexul poate fi inmultit cu un factor de scala de valoare 1, 2, 4 sau 8 (inexistent in adresarea pe 16 biti).
Se obtin astfel 9 moduri posibile de adresare:
. adresare directa - adresa efectiva a operandului face parte din instructiune, putand fi pe 8,16 sau 32 de biti; exemplu:
INC dword ptr [1000H]
. adresare indirecta prin registre - adresa efectiva a operandului este continuta intr-unul din registrele de baza; exemplu:
MOV [EBX] , EAX
. adresare bazata - adresa efectiva a operandului este formata din continutul unui registru de baza la care se poate adauga un deplasament; exemplu:
ADD ECX, [EAX+32]
. adresare indexata - adresa efectiva a operandului este formata din continutul unui registru index la care se poate adauga un deplasament; exemplu:
MUL byte ptr TABLOU [ESI]
. adresare indexata cu factor de scala - adresa efectiva a operandului este formata din continutul unui registru index, inmultit cu un factor de scala, la care se poate adauga un deplasament; exemplu:
MOV EAX, dword ptr TABLOU [EDI*4][100H]
. adresare bazata si indexata - adresa efectiva a operandului este formata din continutul unui registru de baza la care se aduna continutul unui registru index; exemplu:
MOV EAX, [ESI][EBX]
. adresare bazata si indexata cu factor de scala - adresa efectiva a operandului este formata din continutul unui registru de baza la care se adauga continutul unui registru index, inmultit cu un factor de scala; exemplu:
MOV ECX, [EDX*8][EAX]
. adresare bazata si indexata cu deplasament - adresa efectiva 3 operandului este formata din continutul unui registru de baza la care se adauga continutul unui registru index, la care se poate adauga un deplasament; exemplu:
ADD EDX, [ESI] [EBP + 10000H]
. adresare bazata si indexata, cu factor de scala si deplasament - adresa efectiva a operandului este formata din continutul unui registru de baza la care se adauga continutul unui registru index, inmultit cu un factor de scala, la care se poate adauga un deplasament; exemplu:
MOV EAX, TABLOU [EDI*4] [EBP+800H]
Figura 2 ilustreaza modul cel mai general de adresare (bazata si indexata, cu factor de scala si deplasament), in care adresa efectiva AE se calculeaza dupa relatia:
AE = Registru_Baza + Registru_Index * Factor_Scala + Deplasament
Factorul de scala este foarte util la parcurgerea tablourilor de date simple (pe 2, 4 sau 8 octeti), permitand ca indicele logic al tabloului sa coincida cu continutul registrului index. De exemplu, o instructiune C de forma:
long int tablou [1000];
for (i = 0; i < 1000; i++)
tablou[i] += 10;
se implementeaza prin secventa:
MOV CX,
XOR EBX, EBX
bucla:
ADD _TABLOU [EBX*4], 10
INC EBX
LOOP bucla
in care registrul EBX are exact aceeasi semnificatie ca si indicele i din programul C.
1.3 Modurile Real si Protected
Pentru a pastra compatibilitatea cu programele dezvoltate pentru masini de 16 biti, procesoarele de 32 de biti dispun de doua moduri de operare: modul Real Address (pe scurt, modul Real) si modul Protected Virtual Address (pe scurt, modul Protected).
In modul Real, procesorul se comporta ca un procesor de 16 biti foarte rapid, permitand insa accesul la date si adrese de 32 de biti.
Modul Protected ofera mecanisme sofisticate de gestiune a memoriei (paginare, drepturi de acces la segmente etc.). In acest mod de operare, unitatile de program se numesc taskuri. Se poate executa o comutare de task, pentru a intra intr-un regim special de functionare, denumit mod Virtual 8086. Fiecare asemenea task se comporta (din punct de vedere software) ca o masina de tip 8086, permitand programelor de 16 biti (aplicatii sau chiar un intreg sistem de operare) sa poata fi executate ca taskuri.
Atat in modul Real, cat si in modul Protected, procesorul poate executa instructiuni de 16 biti, prin examinarea unui bit din descriptorul de segment asociat registrului CS. Acest bit precizeaza lungimea implicita a operanzilor si a adreselor (16 sau 32 de biti).
In afara dimensiunii implicite, se poate forta o anumita dimensiune prin prefixele numite Operand Size (Dimensiune operand) si Addess Length (Lungime adresa). Aceste prefixe (de valoare 66H si 67H) sunt generate automat de catre macroasambloare. Sa presupunem modul Real si sa (consideram urmatoarea secventa de cod sursa:
. code
MOV AX, word ptr [DI][100H]
MOV EAX, dword ptr [DI][100H]
MOV AX, word ptr [EDI][100H]
MOV EAX, dword ptr [EDI][100H]
Fisierul listing generat va contine urmatoarea descriere:
0000 8B 85 0100 MOV AX, word ptr [DI][100H]
0004 66| 8B 85 0100 MOV EAX, dword ptr [DI][100H]
0009 67| 8B 87 00000100 MOV AX, word ptr [EDI][100H]
0010 66| 67| 8B 87 00000100 MOV EAX, dword ptr [EDI][100H]
Se observa acelasi cod al instructiunii MOV (8BH), acelasi deplasament 100H generat pe 16 sau 32 de biti si prefixele inserate automat. Prima instructiune este cu operand si adresare de 16 biti. A doua instructiune este cu operand pe 32 de biti si adresare pe 16 biti; se observa prefixul 66H si offset-ul 100H generat pe 16 biti. A treia instructiune este cu operand pe 16 biti si adresare pe 32 de biti; se observa prefixul 67H si offset-ul 100H generat pe 32 de biti. In fine, ultima instructiune este cu operand si adresare pe 32 de biti; se observa ambele prefixe si offset-ul 100H generat pe 32 de biti.
In modul de operare Real, formarea adresei fizice este exact ca la procesoarele de 16 biti (vezi Figura 3). Selectorul de segment este unul din cele 4 registre de segment, iar offset-urile sunt pe 16 biti, conducand astfel la o lungime maxima a unui segment de 64KB. Pointerii catre date sau catre instructiuni pot fi memorati pe 4 octeti (doi octeti pentru adresa de segment si doi octeti pentru offset).
Asambloarele dispun de directiva DD (Define DoubleWord), care genereaza pointeri pe 4 octeti, ca in exemplul urmator:
.data
TABLOU DD 256 dup (?)
ADR_16 DD TABLOU
.code
LES BX, ADR_16
MOV EAX, ES:[BX]
Instructiunea LES BX, ADDR_16 incarca perechea de registre (ES:BX) cu un pointer pe 4 octeti.
In modul de operare Protected, registrele selectoare de segment (de 16 biti) sunt incarcate cu adresa unui descriptor de segment, iar offset-urile pot fi de 16 sau 32 de biti (vezi Figura 4), conducand la o lungime maxima a unui segment de 4 GB. Pointerii pot fi pe 4 octeti (doi octeti pentru descriptorul de segment si doi octeti pentru offset) sau pe 6 octeti (patru octeti pentru offset).
Asambloarele dispun de directiva DP (Define Pointer), care genereaza pointeri pe 6 octeti, ca in exemplul urmator:
Figura 3 Adresarea in modul Real
.data
TABLOU DD 256 dup (?)
ADR_32 DP TABLOU
.code
LFS EBX, ADR_32
MOV EAX, FS:[EBX]
Instructiunea LFS EBX, ADDR_32 incarca perechea de registre (FS:EBX) cu un pointer pe 6 octeti.
Sa consideram urmatoarea secventa sursa:
.data
TABLOU DD 256 dup (?)
ADR_16 DD TABLOU
.code
LEA BX, TABLOU ; Acces prin point near
; de 16 biti in
MOV EAX, [BX] ; cadrul segmentului selectat
; prin DS
LEA EBX, TABLOU ; Acces prin point near
; de 32 de biti in
MOV EAX, [EBX] ; cadrul segmentul selectat prin DS
LES AX, ADR_16 ; Acces prin point far
; de 32 de biti in
MOV EAX, ES:[BX] ; cadrul segmentul selectat
; prin ES
LFS EBX, ADR_32 ; Acces prin pointer far
; de 48 de biti in
MOV EAX, FS:[EBX] ; cadrul segmentului selectat
; prin FS
Figura 4 Adresarea in modul Protected
Listingul generat la asamblare pentru secventa de mai sus este:
.data
TABLOU DD 256 dup (?)
0400 00000000sr ADR_16 DD TABLOU
0404 000000000000sr ADR_32 DP TABLOU
040A .code
0000 BB 0000r LEA BX, TABLOU
0003 66| 8B 07 MOV EAX, [BX]
0006 66| 8D 1E 0000r LEA EBX, TABLOU
000B 66| 67| 8B 03 MOV EAX, [EBX]
000F C4 1E 0400r LBS BX, ADR_16
0013 66| 26: 8B 07 MOV EAX, ES:[BX]
0017 66| OF B4 1E 0404r LFS EBX, ADR_32
001D 66| 64: 67| 8B 03 MOV EAX, FS:[EBX]
Se observa prezenta a trei categorii de prefixe. Prefixele de operand pe 32 de biti (marcate cu 66|), cele de adresa pe 32 de biti (marcate cu 67|) si prefixele de segment (marcate cu 26: pentru ES: si cu 64: pentru FS:). Instructiunea LEA (Load Effective Address) permite incarcarea atat offset-urilor de 16 biti, cat si a celor de 32 de biti.
In mod implicit, accesul la date se face prin selectorul DS (la fel ca la 8086), cu exceptia modurilor de adresare care implica registrele EBP si ESP, caz in care selectorul implicit este SS. Se poate folosi orice prefix de segment, cu aceleasi exceptii cunoscute de la 8086:
. instructiunile executate sunt accesate totdeauna prin CS;
. operatiile de salvare si restaurare in stiva implicate in instructiunile CALL, RET, PUSH si POP se executa totdeauna prin selectorul SS;
. destinatia instructiunilor pentru siruri este accesata totdeauna prin selectorul ES.
La punerea sub tensiune, procesorul este in modul Real. Trecerea in modul Protected se face prin pozitionarea unui bit din cuvantul mai putin semnificativ (numit Machine Status Word) al registrului de control CR0.
Asa cum la procesoarele de 16 biti trebuia sa incarcam registrele de segment cu valori cu sens, trecerea in modul Protected presupune definirea corespunzatoare a descriptorilor de segment si incarcarea registrelor selectoare. Aceste operatii nu vor fi descrise, in ideea ca programele de aplicatie dezvoltate in limbaj de asamblare vor opera in general in modul Real.
2 Setul de instructiuni al procesoarelor de 32 de biti
2.1 Extensia instructiunilor de 16 biti
Pentru ca asamblorul sa recunoasca instructiunile specifice, se utilizeaza directivele .286, .386, .486, care precizeaza tipul procesorului.
O serie de restrictii de la setul de baza 8086 sunt eliminate, incepand de la procesorul 80286. De asemenea, se adauga o serie de instructiuni noi.
Incarcarea registrelor de segment se poate face cu valori imediate; exemplu MOV DS, DGROUP.
Instructiunile de deplasare si rotatie se pot executa pe un numar oarecare de biti, specificat in instructiune; de exemplu: SHL AX, 4.
Instructiunea de inmultire cu semn (IMUL) are urmatoarele forme suplimentare:
IMUL reg16, im16
prin care se inmulteste registrul de 16 biti reg16 cu o valoare imediata pe 16 biti im16, iar rezultatul se depune in reg16;
IMULdreg16, sursa16
prin care se inmulteste dreg16 cu sursa16 (registru sau memorie) si rezultatul se depune in dreg16 (numai la 80386 si urmatoarele).
IMULdrea16, sursa16, im16
prin care se inmulteste sursa16 (registru sau memorie) cu valoarea imediata ini16 si rezultatul se depune in registrul dreg16 (destinatie).
Instructiunile de lucru cu stiva se extind cu:
PUSHA (Push AII)
care salveaza in stiva registrele AX, CX, DX, BX, SP, BP, SI, Dl (in aceasta ordine), iar registrul SP este scazut cu 16;
POPA (Pop All)
care reface registrele Dl, SI, BP, SP, BX, DX, CX, AX (salvate cu o instructiune PUSHA anterioara); registrul SP se reface prin adunarea valorii 16, nu prin extragerea efectiva din stiva;
PUSH im16
care pune in stiva o valoare imediata. Instructiunile pentru siruri se extind cu:
INSB, INSW (Input String) cu semnificatia:
(ES:(DI)) <- byte / word citit de la portul specificat de DX;
actualizeaza DI;
OUTSB, OUTSW (Output String)
cu semnificatia:
port specificat prin DX <- (DS:(SI));
actualizeaza SI;
Instructiunile de control se extind cu:
BOUND reg16, lim (Testeaza limite)
in care lim este adresa unei zone de memorie de doi intregi, care precizeaza limita minima si maxima pentru registrul reg16. Daca reg16 < DS:(lim) sau reg16 > DS:(lim+2), atunci se genereaza o intrerupere software pe nivelul 5.
ENTER dim_loc, nivel (Creeaza sablon stiva la intrarea in procedura) in care dim_loc si nivel sunt intregi pe 16 biti fara semn.
Semnificatia este urmatoarea:
PUSH BP
temp <- SP
daca (nivel > 0)
PUSH temp
BP <- temp
SP <- SP - dim_loc
Primul parametru dim_loc este dimensiunea necesara in stiva pentru parametrii locali ai procedurii. Daca nivel este 0, atunci semnifica este echivalenta cu:
PUSH BP
MOV BP, SP
SUB SP, dim_loc
care este secventa standard de intrare intr-o procedura cu parametri locali in stiva (vezi 6.6).
Daca nivel este > 0, se copiaza in stiva continutul zonei de stiva (parametri locali) a procedurii apelante. Daca procedura curenta este apelata dintr-o alta procedura, care are registrul BP pozitionat printr-o instructiune ENTER, atunci sablonul stivei curente va contine primii nivel - 1 parametri locali ai procedurii apelante.
LEAVE (Pregatire pentru iesire din procedura)
Instructiunea LEAVE reface registrele SP si BP, anuland efectul instructiunii LEAVE. Este echivalenta cu secventa:
MOV SP, BP
POP BP
Instructiunea ENTER se scrie ca prima instructiune din procedura, iar LEAVE imediat inainte de RET.
2.2 Instructiuni specifice procesoarelor de 32 de biti
Intregul set de instructiuni de transfer, aritmetice si logice se extinde cu operanzi de tip DoubleWord (registre, memorie sau valori imediate).
Instructiuni specifice de transfer
PUSHAD / POPAD (Push / Pop All Double)
Salveaza / restaureaza registrele EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI in stiva.
PUSHFD / POPFD (Push Flags Double)
Salveaza / restaureaza registrul EFLAGS in stiva.
CMPXCHG reg / mem, reg (Compare and Exchange)
Compara si apoi interschimba cei doi operanzi, pozitionand flagurile aritmetice.
BSWAP reg32 (Byte Swap)
Inverseaza ordinea octetilor intr-un registru de 32 de bti:
XADD reg / mem, reg (Exchange and Add)
Este echivalenta cu secventa:
XCHG reg/mem, reg
ADD reg/mem, reg
Instructiuni specifice de conversie
MOVZX / MOVSX destinatie, sursa (Move with Zero / Sign Extension)
Copiaza operandul sursa (de 8 sau 16 biti) in operandul destinatie (de lungime dubla), completand cu 0 (MOVZX) sau cu bitul de semn al operandului sursa (MOVSX). Destinatia poate fi registru sau memorie de
16 / 32 de biti, iar sursa poate fi registru, memorie sau valoare imediata de 8 / 16 biti.
CWDE (Convert Word to DoubleWord Extended)
Converteste AX la un dublu cuvant in EAX, cu extensie de semn. Este asemanatoare cu CWD (Convert Word to Double), care are ca destinatie perechea (DX:AX).
CDQ (Convert DoubleWord to QuadWord)
Converteste registrul EAX la un cuvant cvadruplu in perechea (EDX:EAX), cu extensie de semn.
Instructiuni specifice adreselor
LFS / LGS / LSS registru, memorie
Incarca o pereche de registre cu un pointer din memorie, pe 4 sau 6 octeti. Registrul specificat poate fi de 16 sau de 32 de biti.
Instructiuni aritmetice
Operatiile de inmultire si de impartire se pot executa pe 32 de biti. Se utilizeaza registrele EAX si EDX, cu semnificatie asemanatoare ca la operatiile de 16 biti. De exemplu, instructiunea:
DIV EBX
imparte (EDX:EAX) la EBX, cu catul in EAX si restul in EDX.
Instructiuni de deplasare
SHLD / SHRD reg / mem, reg, CL / im8 (Shift Left / Right Double)
Se deplaseaza reg / mem la stanga / dreapta cu numarul de biti specificat in CL sau in operandul imediat im8 (pe 8 biti). Al doilea operand este folosit pentru a completa bitii deplasat ai primului operand. Primii doi operanzi trebuie sa fie de aceeasi dimensiune (Word sau DoubleWord).
Instructiuni pentru siruri
Setul de instructiuni pentru siruri se extinde cu operatii specifice sirurilor de intregi pe 4 octeti. Exista astfel instructiunile MOVSD (Move String Double), STOSD (Store String Double), LODSD (Load String Double), SCASD (Scan String Double). Se utilizeaza registrul acumulator extins EAX, iar adresele sursa si destinatie (SI si Dl) sunt incrementate / decrementate cu 4.
BSF / BSR reg, reg / mem (Bit Scan Forward / Reverse)
Instructiunea parcurge operandul sursa reg / mem (16 < 32 de biti), pana la primul bit egal cu 1. BSF parcurge de la dreapta la stanga, iar BSR invers. Indicele bitului 1 identificat este plasat in primul operand registru).
BT reg / mem, im8 / reg (Bit Test)
Plaseaza bitul cu numarul dat de im8 sau de reg al operaului reg / mem in CF.
BTC reg / mem, im8 / reg (Bit Test and Complement)
Plaseaza bitul cu numarul dat de im8 sau de reg al operandului reg / mem in CF, apoi complementeaza bitul respectiv.
BTR reg / mem, im8 / reg (Bit Test and Reset)
Plaseaza bitul cu numarul dat de im8 sau de reg al operandului reg / mem in CF, apoi forteaza bitul respectiv la valoarea 0.
BTS reg / mem, im8 / reg (Bit Test and Set)
Plaseaza bitul cu numarul dat de im8 sau de reg al operandului reg / mem in CF, apoi forteaza bitul respectiv la valoarea 1.
Instructiuni de control
JECXZ eticheta (Jump if ECX is Zero)
Este extensia instructiunii JCXZ pentru registrul ECX.
SETccc reg / mem (Set Bytes Conditiorv)
Seteaza un octet conform unei conditii logice. Octetul poate fi un registru de 8 biti sau o locatie de memorie. Conditiile logice si semnificatiile lor sunt aceleasi ca la instructiunile de salt conditionat. In mnemonicele instructiunilor se substituie ccc cu conditia care este codificata sub forma Jccc la instructiunile de salt conditionat. Exista deci instructiuni SETG, SETGE SETNB, SETPO, SETNLE etc. De exemplu:
SETLE AL
SETNBE byte ptr [SI]
SETNC byte ptr [EBX]
3 Coprocesoare matematice
1 Arhitectura coprocesoarelor matematice
Coprocesoarele matematice sunt circuite integrate dedicate (procesoare specializate), care extind setul de instructiuni al procesoarelor centrale cu instructiuni specifice operatiilor cu numere reale in virgula mobila.
Coprocesoarele sunt fie circuite de sine statatoare (8087, 80287, 80387), fie sunt integrate in procesorul de baza (80486). In cel de-al doilea caz, nu se mai face distinctie intre setul de instructiuni al procesorului de baza si cel specific formatului in virgula mobila.
Tipurile de date recunoscute de coprocesoare sunt:
. numar real in simpla precizie (dword);
. numar real in dubla precizie (qword);
. numar real in precizie extinsa (tbytes);
. intreg pe 2 octeti (word);
. intreg pe 4 octeti (dword);
. intreg pe 8 biti (qword);
. intreg BCD pe 10 cifre (tbytes).
Aceste tipuri de date vor fi notate cu real32, real64, real80, int16, int32 si bcd80. Intregii pe 8 octeti pot fi numai incarcati in coprocesor. Intern, coprocesoarele lucreaza exclusiv cu formatul real in precizie extinsa (10 octeti), descris in Capitolul 1. La incarcarea operanzilor din memorie, toate tipurile de date de mai sus sunt convertite la tipul intern; similar, la depunerea operanzilor in memorie, au loc conversii de la formatul intern la unul din formatele de mai sus.
Arhitectura coprocesoarelor cuprinde 8 registre de cate 80 de biti, numite ST(0), ST(1), , ST(7). Aceste registre sunt organizate ca o stiva, registrul ST(0) (care se mai noteaza simplu cu ST) fiind varful stivei (vezi Figura 5). Coprocesoarele dispun de o serie ce registre suplimentare, dintre care cele mai importante sunt registrul de stare (Status Word) si registrul de control (Control Word). Registrul de stare contine flaguri care se pozitioneaza in urma instructiunilor de comparatie sau in caz de eroare. Registrul de control contine campuri care controleaza modul de executie al anumitor actiuni (de exemplu, cum se face rotunjirea la valori intregi).
Comunicatia dintre procesorul de baza si coprocesor se face exclusiv prin intermediul memoriei. Coprocesorul dispune de instructiuni de transfer intre memorie si cele 8 registre de lucru, precum si pentru cuvintele de control si de stare.
Ne vom referi in continuare la coprocesorul 8087, deoarece setul de instructiuni este practic acelasi la toate coprocesoarele. La procesoarele mai vechi decat 80486, se pune si problema comunicatiei dintre procesorul de baza si coprocesor.
Instructiunile specifice 8087 se scriu in textul sura a fel ca instructiunile procesorului de baza. Asamblorul recunoaste mnemonicele acestor instructiuni si genereaza cod masina corespunzator. Acest cod va fi executat de catre coprocesor, in urma generarii unui semnal de catre procesorul de baza 8086.
Coprocesorul 8087 monitorizeaza permanent fluxul de instructiuni si sesizeaza prezenta unei instructiuni specifice 8087 in memorie. In acest caz, el semnaleaza intentia de a intra in executie prin semnalul electric TEST. Executia incepe numai dupa ce 8086 intra in asteptare, ca urmare a unei instructiuni WAIT. Coprocesorul recunoaste starea de asteptare si incepe executia instructiunii matematice, anuland in acelasi timp cererea efectuata prin semnalul TEST. Ca urmare, 8086 iese din starea de asteptare si isi continua executia. Asambloarele insereaza automat o instructiune WAIT inaintea fiecarei instructiuni 8087, deci nu este necesara codificarea lor explicita.
La coprocesoarele de generatie mai noua (80387), sincronizarea cu procesorul de baza se face prin semnale specializate, ceea ce elimina necesitatea instructiunilor WAIT.
In mod corespunzator, exista instructiunea 8087 FWAIT, destinata sincronizarii reciproce (8087 "asteapta' dupa 8086). Instructiunea FWAIT este necesara numai dupa operatiile de depunere in memorie executate de 8087.
Inaintea inceperii operarii propriu-zise, este necesara o instructiune FINIT, care sterge registrele interne, conditiile de eroare etc.
2 Setul de instructiuni 8087
Mnemonicele instructiunilor 8087 incep toate cu litera F. Majoritatea instructiunilor au ca operanzi varful ST al stivei coprocesorului si un alt registru ST(i) sau un operand in memorie. Cele mai multe instructiuni matematice actualizeaza stiva, prin operatiile descrise mai jos (ST si ST(0) reprezinta acelasi registru):
PUSH_ST:
for (i = 7 downto 1)
ST(i) <- ST(i-l)
POP_ST:
for (i = 1 to 7)
ST(i-l) <- ST(i)
FLD ST(i) (Incarca ST(i) in ST, cu deplasarea stivei)
temp <- ST(i)
PUSH_ST
ST <- temp
FLD mem (real32/64/80) (Incarca numar real din memorie in ST)
PUSH_ST
ST <- mem
FILD mem (int16/32/64) (Incarca numar intreg din memorie in ST)
PUSH_ST
ST <- mem
FBLD mem (bcd80) (Incarca numar BCD din memorie in ST)
PUSH_ST
ST <- mem
FLDZ (Incarca constanta 0.0 in ST)
PUSH_ST
ST <- 0.0
FLD1 (Incarca constanta 1.0 in ST)
PUSH_ST
ST <- 1.0
FLDPI (Incarca constanta p in ST)
PUSH_ST
ST <- p
FLDL2E (Incarca constanta log2 (e) in ST)
PUSH_ST
ST <- Iog2 (e)
FLDL2T (Incarca constanta log2 (10) in ST)
PUSH_ST
ST <- log2 (10)
FLDLG2 (Incarca constanta log10 (2) in ST)
PUSH_ST
ST <- log10 (2)
FST ST(i) (Depune ST in ST(i) fara descarcarea stivei)
ST(i) <- ST
FSTP ST(i) (Depune ST in ST(i) cu descarcarea stivei)
ST(i) <- ST
POP_ST
FST mem (real32/64/80) (Depune ST real in memorie fara descarcare)
mem <- ST
FSTP mem (real32/64/80) (Depune ST real in memorie cu descarcare)
mem <- ST
POP_ST
FIST mem (int16/32) (Depune ST intreg in memorie fara descarcare)
mem <- ST
FISTP mem (int16/32) (Depune ST intreg in memorie cu descarcare)
mem <- ST
POP_ST
FBSTP mem (bcd80) (Depune ST BCD in memorie cu descarcare)
mem <- ST
POP_ST
FXCH (Schimba ST cu ST(1))
FXCH ST(i) (Schimba ST cu ST(i))
FADD (Aduna ST cu ST(1), cu descarcare)
ST(1) <- ST(1) + ST
POP_ST
FADD ST(i), ST (Aduna ST la ST(i))
ST(i) <- ST(i) + ST
FADD ST, ST(i) (Aduna ST(i) la ST)
ST <- ST + ST(i)
FADD mem (real32/64/80) (Aduna real din memorie la ST)
ST <- ST + mem
FIADD mem (int16/32) (Aduna intreg din memorie la ST)
ST <- ST + mem
FADDP ST(i) (Aduna ST la ST(i) cu descarcarea stivei)
ST(i) <- ST(i) + ST
POP_ST
Instructiuni de scadere
FSUB (Calculeaza ST(1) - ST cu descarcare)
ST(1) <- ST(1) - ST
POP_ST
FSUB ST(i), ST (Scade ST din ST(i))
ST(i) <- ST(i) - ST
FSUB ST, ST(i) (Scade ST(i) din ST)
ST <- ST - ST(i)
FSUB mem (real32/64/80) (Scade real in memorie din ST)
ST <- ST - mem
FISUB mem (int16/32) (Scade intreg in memorie din ST)
ST <- ST - mem
FSUBP ST(i) (Scade ST din ST(i) cu descarcare)
ST(i) <- ST(i) - ST
POP_ST
FSUBR (Calculeaza ST - ST(1) cu descarcare)
Temp <- ST - ST(1)
POP_ST
ST <- temp
FSUBR ST(i), ST (Scade ST(i) din ST, rezultat in ST(i))
ST(i) <- ST - ST(i)
FSUBR ST, ST(i) (Scade ST din ST(i), rezultat in ST)
ST <- ST(i) - ST
FSUBR mem (real32/64/80) (Scade ST din real in memorie, rezultat in ST)
ST <- mem - ST
FISUBR mem (int16/32) (Scade ST din intreg in memorie, rezultat in ST)
ST <- mem - ST
FSUBPR ST(i) (Scade ST(i) din ST cu descarcare)
ST(i) <- ST - ST(i)
POP_ST
FMUL (Inmulteste ST cu ST(1), cu descarcare)
ST(1) <- ST(1)*ST
POP_ST
FMUL ST(i), ST (Inmulteste ST cu ST(i), rezultat in ST(i))
ST(i) <- ST(i) * ST
FMUL ST, ST(i) (Inmulteste ST(i) cu ST, rezultat in ST(i))
ST <- ST * ST(i)
FMUL mem (real32/64/80) (Inmulteste real din memorie cu ST)
ST <- ST * mem
FIMUL mem (int16/32) (Inmulteste intreg din memorie cu ST)
ST <- ST * mem
FMULP ST(i) (Inmulteste ST cu ST(i), cu descarcare)
ST(i) <- ST(i) * ST
POP_ST
FDIV (Calculeaza ST(1) / ST cu descarcare)
ST(1) <- ST(1) / ST
POP_ST
FDIV ST(i),ST (Imparte ST(i) la ST, rezultat in ST)
ST(i) <- ST(i) / ST
FDIV ST, ST(i) (Imparte ST la ST(i) rezultat in ST(i))
FDIV mem (real32/64/80) (Imparte ST la real din memorie)
ST <- ST / mem
FIDIV mem (int16/32) (Imparte ST la intreg din memorie)
ST <- ST / mem
FDIVP ST(i) (Imparte ST(i) la ST, cu descarcare)
ST(i) <- ST(i) / ST
POP_ST
FDIVR (Calculeaza ST / ST(1), cu descarcare)
temp <- ST / ST(1)
POP_ST
ST <- temp
FDIVR ST(i), ST (Imparte ST la ST(i), rezultat in ST(i))
ST(i) <- ST / ST(i)
FDIVR ST, ST(i) (Imparte ST(i) la ST, rezultat in ST)
ST <- ST(i) / ST
FDIVR mem (real32/64/80) (Imparte real in memorie la ST, rezultat in ST)
ST <- mem / ST
FIDIVR mem (int16/32) (Imparte intreg in memorie la ST, rezultat in ST)
ST <- mem / ST
FDIVPR ST(i) (Imparte ST la ST(i), cu descarcare)
ST(i) <- ST / ST(i)
POP_ST
Instructiuni de comparatie
Instructiunile de comparatie pozitioneaza indicatorii din cuvantul de stare prin efectuarea unei operatii temporare de scadere intre operanzii care se compara.
FCOM (Compara ST cu ST(1))
FCOM ST(i) (Compara ST cu ST(i))
FCOM mem (real32/64/80) (Compara ST cu real din memorie)
FICOM mem (int16/32) (Compara ST cu intreg din memorie)
FTST (Compara ST cu 0.0)
FCOMP (Compara ST cu ST(1), cu descarcare)
temp <- ST - ST(1)
POP_ST
FCOMP ST(i) (Compara ST cu ST(i), cu descarcare)
FCOMP mem (real32/64/80) (Compara ST cu real, cu descarcare)
FICOMP mem (int16/32) (Compara ST cu intreg, cu descarcare)
FCOMPP (Compara ST cu ST(1), cu descarcare dubla)
temp <- ST - ST(1)
POP_ST
POP_ST
FABS (La valoarea absoluta)
ST <- | ST |
FCHS (Schimba semnul)
ST <- - ST
FSQRT (Radical)
ST <- sqrt (ST)
Instructiuni de control
FINIT (Initializeaza coprocesor)
FWAIT (Sincronizeaza cu procesorul de baza)
FSTSW mem (int16) (Depune cuvant de stare in memorie)
FSTCW mem(int16) (Depune cuvant de control in memorie)
FLDCW mem (int16) (Incarca cuvant de control din memorie)
FNOP (Nici o operatie)
Pe langa instructiunile de mai sus, coprocesoarele dispun de instructiuni transcendente, pentru calculul functiilor trigonometrice directe si inverse, exponentiala, logaritm etc. Aceste instructiuni nu vor fi prezentate, deoarece este putin probabil ca se vor dezvolta programe cu functii transcendente in limbaj de asamblare.
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 2250
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved