Limbajul Assembler abc-doar


particularitati si exceptii.Implementarea lor pentru algoritmi numerici



Yüklə 1,03 Mb.
səhifə9/10
tarix16.12.2017
ölçüsü1,03 Mb.
#35021
1   2   3   4   5   6   7   8   9   10
particularitati si exceptii.Implementarea lor pentru algoritmi numerici

a ridicat numeroase probleme de ordin tehnic sau conceptual (sunt celebre

dificultatile intampinate de misiunea Apollo 13,calculul orbitelor pla-

netare,calculul numarului PI etc.).Acest manual,nu are decat pretentia

unui abecedar si se va rezuma doar la cateva exemple simpliste,elementare,

care vor ilustra cat mai clar cu putinta modul concret de implementare,

pentru instructiunile 8087,in mediul de programare Borland Pascal 7.0,cu

ajutorul limbajului assembler integrat in program.
Instructiunile 8087 vor fi prezentate succint,in grupuri,ordonate

in functie de principala operatie executata.Pentru transferul numerelor

reale,se pot utiliza urmatoarele instructiuni:

FLD mem -Introduce mem in ST (mem =4,8 sau 10 bytes)

FLD ST(nr) -Introduce o copie a ST(nr) in ST

FST mem -Copiaza ST in mem

FST ST(nr) -Copiaza ST in registrul specificat

FSTP mem -Extrage o copie a lui mem din ST

FSTP ST(nr) -Extrage ST din registrul specificat,care este inlocuit

FXCH [[ST(nr)]] -Schimba ST cu ST(nr)

FXCH -Schimba ST(0) cu ST(1)

Pentru adunare simpla se pot utiliza urmatoarele instructiuni:

FADD -Aduna ST si ST(1).Rezultatul in ST.Distruge operanzii.

FADD ST(nr),ST -Aduna cei doi registri.Inlocuieste ST(nr) cu rezultatul.

FADD ST,ST(nr) -Aduna cei doi registri.Inlocuieste ST cu rezultatul.

FADD mem -Adauga mem la ST.Inlocuieste ST cu rezultatul.

FIADD mem -Adauga un intreg din mem la ST.Rezultatul in ST.

FADDP ST(nr) -Aduna ST+ST(nr).Rezultat in ST(nr).Distruge operamzii.

Cea mai simpla adunare se poate efectua astfel:

EXEMPLU: program assmb84;

{$N+}

uses WinCRT;

var n1,n2,n3:double;

begin

n1:=73.1517;

n2:=11.6539;

asm

FLD n1

FADD n2

FST n3

end;

writeln(n1:2:4,' + ',n2:2:4,' = ',n3:2:4);

end.

Pentru emularea 8087 am utilizat directiva de precompilare $N+,iar pentru

numere am utilizat formatul double (real este pe 6 biti=nereprezentabil).


-77-

Procesorul 8087 accepta urmatoarele tipuri de data:

1 Real (32 de biti = 4 bytes)

2 Long real (64 biti = 8 bytes )

3 Temporary Real (80 biti = 10 bytes)

4 Integer word (16 biti = 2 bytes)

5 Integer (32 biti = 4 bytes)

6 Long integer (64 de biti = 8 bytes)

7 Packed BCD Integer (80 biti -16 digits + sign = 10 bytes)

Pentru mediul de operare Pascal,acestor tipuri de data le corespund:

1 single (7-8 digits 32 biti = 4 bytes)

2 double (15-16 digits 64 biti = 8 bytes)

3 extended (19-20 digits 80 biti = 10 bytes)

4 comp (10-20 digits 64 biti = 8 bytes)

5 integer ( 16 biti = 2 bytes)

6 longint ( 32 biti = 4 bytes)

7 word ( 16 biti = 2 bytes)

Nu toate instructiunile accepta toate tipurile de data.De exemplu,tipul

de data real din Pascal are un format de 6 bytes si nu poate fi incarcat

in ST prin nici una dintre instructiunile de transfer (chiar daca in

registri exista suficient loc pentru acest tip de data.

In exercitiul precedent am transferat in ST prima valoare,la care am

adaugat valoarea din cea de a doua variabila de memorie prin instructiunea

FADD mem.O alta modalitate de a aduna doua numere reale se poate realiza

incarcand cele doua numere in ST si respectiv ST(1) dupa care se va face

adunarea celor doi registri prin instructiunea FADD:

EXEMPLU: program assmb85;

{$N+}

uses WinCRT;

var n1,n2,n3:double;

begin

n1:=123.4567;

n2:=543.8732;

asm

FLD n2

FST ST(1)

FLD n1

FADD

FST n3

end;

writeln(n1:3:4,' + ',n2:3:4,' = ',n3:3:4);

end.

in exemplul de mai sus,am transferat n2 in ST,apoi am copiat registrul ST

in ST(1),dupa care am transferat n1 in ST si am adunat cei doi registri.

Am preluat rezultatul din ST (cei doi operanzi sunt distrusi automat).

Pentru a transfera datele din ST in ST(1),nu este neaparat necesar sa

apelam instructiunea FST ST(nr).Registrii ST actioneaza sub forma de stiva

conform principiului LIFO (LAST IN FIRST OUT).Astfel este suficient sa

transferam o noua valoare in registrul ST,pentru ca valoarea initiala din

registrul ST sa avanseze in registrul ST(1).Daca transferam o noua

valoare in ST,valoarea din ST(1) avanseaza in ST(2),pentru a face loc

celei din ST(0),care avanseaza in ST(1) pentru a face loc noii valori:


-78-

EXEMPLU: program assmb86;

{$N+}

uses WinCRT;

var n1,n2,n3,n4:double;

begin

n1:=1315.1715;

n2:=3375.3792;

n3:=2277.5533;

asm

FLD n1

FLD n2

FLD n3

FXCH ST(2)

FST n4

end;

writeln('ST(0) contine valoarea: ',n4:4:4);

end;

La prima instructiune FLD valoarea n1 este transferata in ST(0).La cea

de a doua instructiune FLD valoarea n1 avanseaza in ST(1) iar la cea de

a treia instructiune FLD,n1 avanseaza in registrul ST(2).Apoi prin in-

structiunea FXCH ST(2) se inlocuieste valoarea din ST(0) cu cea din

registrul ST(2).In final,FST copiaza ST in variabila n4.

Astfel,daca dorim ca variabilele sa fie stocate in ordine crescatoare,

ele trebuiesc transferate in ST in ordine inversa (de la coada la cap).

EXEMPLU: program assmb87;

{$N+}

uses WinCRT;

var n1,n2,n3,n4:double;

begin

n1:=1111.1111;

n2:=2222.2222;

n3:=3333.3333;

asm

FLD n3

FLD n2

FLD n1

FADD ST,ST(2)

FST n4

end;

writeln(n3:4:4,' + ',n1:4:4,' = ',n4:4:4);

end.

In acest mod,variabilele transferate in registri vor fi amplasate in

ordinea crescatoare: n1 in ST,n2 in ST(1) si n3 in ST(2).Acest mod

de incarcare a stivei poate fi util pentru o evidenta mai simpla a

pozitiei fiecarei variabile in stiva.In exemplul de mai sus,se vor

putea efectua facil oricare dintre operatiile n1+n3 sau n1+n2,dar va

fi mai complicat de realizat operatia n2+n3.

Adunarea dintre doua valori se poate face si utilizand numere repre-

zentate in formate diferite,cu conditia sa se apeleze instructiunea co-

respunzatoare.Pentru a aduna un numar intreg la un numar real exista

instructiunea FIADD mem:


-79-

EXEMPLU: program assmb88;

{$N+}

uses WinCRT;

var n1,n3:double;

n2:longint;

begin

n1:=3355.7713;

n2:=123456;

asm

FLD n1

FIADD n2

FST n3

end;

writeln(n1:4:4,' + ',n2,' = ',n3:4:4);

end.

Pentru ca scrierea si/sau citirea unui program sa se desfasoare cat mai

simplu,este bine sa aveti o plansa cu toate instructiunile grupate in

functie de operatia principala.Daca este necesar,adaugati cate un comen-

tariu dupa fiecare operatie efectuata,sau cel putin in punctele in care

intervin modificari greu de observat la prima vedere.

Instructiunile 8087 se pot grupa in patru seturi principale:

1 Setul CORE -contine instructiunile de transfer si cele pentru operatiile

aritmetice simple:adunare,scadere,inmultire,impartire

2 Setul EXTENDED -contine instructiunile de transfer a formatelor speciale

3 Setul SPECIAL FUNCTION-contine instructiunile de extragere a radacinii

patrate si suportul pentru functiile transcedentale

4 Setul ADMINISTRATIVE -contine instructiunile pentru modificarea context-

ului si cele pentru controlul procesorului
Pentru transferul numerelor intregi simple exista urmatoarele instructiuni

FILD mem -Introduce o copie a mem in ST mem = 2,4,8 sau 10 bytes

FIST mem -Copiaza ST in mem mem = 2 sau 4 bytes

FISTP mem -Extrage ST din mem mem = 2,4 sau 8 bytes
Pentru transferul numerelor BCD impachetate se folosesc instructiunile:

FBLD mem -Indroduce o copie a mem in ST (10 bytes)

FBSTP mem -Introduce ST in mem (10 bytes)
Exista si o serie de instructiuni speciale,care transfera in registrul

ST cateva constante utile,cum ar fi zero,unu,PI,log 2e,log 10 2,log e 2:

FLDZ -Introduce 0 in ST

FLD1 -Introduce 1 in ST

FLDPI -Introduce PI in ST

FLDL2E -introduce valoarea lui log2 e in ST

FLDL2T -introduce valoarea lui log2 10 in ST

FLDLG2 -introduce valoarea lui log10 2 in ST

FLDLN2 -introduce valoarea lui loge 2 in ST
Transferul direct al constantelor simplifica operatiile curente prin

eliminarea unor etape intermediare,pentru calculul suprafetelor circulare

si pentru calculul logaritmic.


-80-

EXEMPLU: program assmb89;

{$N+}

uses WinCRT;

var n1:double;

n2:longint;

begin

n2:=12300;

asm

FILD n2

FLDPI

FADD

FST n1

FISTP n2

end;

writeln('12300 + PI = ',n1:4:12);

writeln('Valoarea intreaga este: ',n2);

end.
Pentru scadere simpla se pot utiliza urmatoarele instructiuni:

FSUB -Scade ST din ST(1) si extrage rezultatul in ST

FSUB ST(nr),ST -Scade ST din ST(nr) si inlocuieste ST(nr) cu rezultatul

FSUB ST,ST(nr) -Scade ST(nr) din ST si inlocuieste ST cu rezultatul

FSUB mem -Scade mem din ST si inlocuieste ST cu rezultatul

FISUB mem -Scade numarul intreg mem din ST.Rezultatul in ST.

FSUBP ST(nr),ST -Scade ST din ST(nr).Distruge operanzii.Rezultat in ST(nr)
EXEMPLU: program assmb90;

{$N+}

uses WinCRT;

var n1:double;

begin

n1:=1.3333;

asm

FLDL2T

FSUB n1

FST n1

end;

writeln('Log2 10 - 1.3333 = ',n1:2:8);

end.

In exercitiul de mai sus,am incarcat constanta cu ajutorul instructiunii

FLDL2T,dupa care am scazut din ST valoarea variabilei de memorie.Este

cel mai simplu algoritm pentru o operatie de scadere simpla.Pentru

instructiunile cu doi operanzi,trebuie transferata cate o valoare atat

in ST cat si in ST(1),dupa care se efectueaza operatia de scadere propriu

zisa.Atentie la ordinea in care se efectueaza transferul datelor in stiva

(principiul LIFO).O eroare foarte frecventa apare atunci cand se utili-

zeaza un algoritm cu mai multe operatii succesive.In acest caz,trebuie

tinut cont de faptul ca dupa o operatie de scadere,rezultatul ramane in

ST (sau in ST(1) ) si la un nou transfer de data avanseaza in registrul

urmator.Daca se introduc prea multe date succesiv,se depaseste stiva si

se va returna un mesaj de eroare in executie (run time error).


-81-

Pentru numere intregi se poate utiliza un exercitiu de genul:

EXEMPLU: program assmb91;

{$N+}

var n1,n2,n3:longint;

begin

n1:=55577715;

n2:=33312341;

asm

FILD n2

FILD n1

FSUB ST,ST(1)

FISTP n3

end;

writeln(' 55577715 - 33312341 = ',n3);

end.
Pentru scaderea inversa se pot utiliza urmatoarele operatii:

FSUBR -Scade ST(1) din ST.Distruge operanzii.Rezultat in ST.

FSUBR ST(nr),ST -Scade ST(nr) din ST.Inlocuieste ST(nr) cu rezultatul.

FSUBR ST,ST(nr) -Scade ST din ST(nr).Inlocuieste ST cu rezultatul.

FSUBR mem -Scade ST din mem.Inlocuieste ST cu rezultatul.

FISUBR mem -Scade ST din numarul intreg mem.Rezultatul in ST.

FSUBRP ST(nr),ST-Scade ST(nr) din ST.Rezultat in ST(nr).Distruge operanzii
EXEMPLU: program assmb92;

{$N+}

uses WinCRT;

var n1,n2,n3,n4:double;

begin

n1:=11111.33333;

n2:=777.55555;

asm

FLD n1

FLD n2

FSUB

FST n3

FLDZ

FLDZ

FLD n1

FLD n2

FSUBR

FST n4

end;

writeln('FSUB: ',n1:5:5,' - ',n2:5:5,' = ',n3:5:5);

writeln('FSUBR: ',n2:5:5,' - ',n1:5:5,' = ',n4:5:5);

end.

Se observa usor ca scaderea inversa este identica cu cea simpla,dar se

inverseaza operanzii (descazutul devine scazator iar scazatorul devine

descazut).Pentru a evita coruperea registrilor am transferat de doua ori

valoarea zero,inainte de a reincarca valorile.Acest gen de artificiu nu

se poate repeta prea des,deoarece se supraincarca stiva in mod inutil.


-82-

Pentru inmultirea numerelor reale,se pot utiliza urmatoarele instructiuni:

FMUL -Inmulteste ST cu ST(1).Rezultat in ST.Operanzii distrusi.

FMUL ST(nr),ST -Inmulteste ST(nr) cu ST.Rezultatul in ST(nr).

FMUL ST,ST(nr) -Inmuulteste ST cu ST(nr).Rezultatul in ST.

FMUL mem -Inmulteste ST cu variabila mem.Rezultatul in ST.

FIMUL mem -Inmulteste ST cu numarul intreg mem.Rezultatul in ST.

FIMULP ST(nr),ST -Inmulteste valorile si extrage rezultatul in ST.
EXEMPLU: program assmb93;

{$N+}

uses WinCRT;

var a,b,c:double;

begin

a:=1713.1539;

b:=5.1423;

asm

FLD a

FMUL b

FST c

end;

writeln('1713,1359 x 5,1423 = ',c:5:6);

end.

Sau,pentru a calcula aria unui cerc:

EXEMPLU: program assmb94;

{$N+}

uses WinCRT;

var a,b,c:double;

begin

writeln('Introduceti raza cercului: ');

read(a);

asm

FLD a

FMUL a

FLDPI

FMUL ST,ST(1)

FST c

end;

writeln('Aria cercului este: ',c:8:8);

end.

In mod similar se pot construi diverse functii.Eventual incercati

sa grupati diverse functii programate in assembler,sub forma unei unitati

sau a unei biblioteci DLL.
Pentru impartire,se pot utiliza urmatoarele instructiuni:

FDIV -Imparte ST(1) la ST.Rezultatul in ST.Distrige operanzii.

FDIV ST(nr),ST -Imparte ST(nr) la ST.Rezultatul in ST(nr).

FDIV ST,ST(nr) -Imparte ST la ST(nr).Rezultatul in ST.

FDIV mem -Imparte ST la variabila mem.Rezultatul in ST.

FIDIV mem -Imparte ST la numarul intreg mem.Rezultatul in ST.

FDIVP ST(nr),ST -Imparte ST(nr) la ST.Rezultatul in ST(nr).Ambii operanzi

sunt distrusi.

-83-

EXEMPLU: program assmb95;

{$N+}

uses WinCRT;

var a,b:double;

begin

writeln('Introduceti valoarea dorita: ';

read(a);

asm

FLD a

FLDPI

FDIV ST(1),ST

FXCH

FST b

end;

writeln(a:5:5,' impasrtit la 3.14...=',b:5:5);

end.
Pentru impartire inversa,se pot utiliza urmatoarele instructiuni:

FDIVR -Imparte ST la ST(1).Rezultatul in ST.Operanzii distrusi.

FDIVR ST(nr),ST -Imparte ST la ST(nr).Rezultatul in ST(nr).

FDIVR ST,ST(nr) -Imparte ST(nr) la ST.Rezultatul in ST.

FDIVR mem -Imparte variabila mem la ST.rezultatul in ST.

FIDIVR mem -Imparte numarul intreg mem la ST.Rezultatul in ST.

FIDIVRP ST(nr),ST-Imparte ST la ST(nr).Rezultatul in ST(nr).

EXEMPLU: program assmb96;

{$N+}

uses WinCRT;

var a,b,c,d:double;

begin

writeln('Introduceti primul numar: ');

read(a);

writeln('Introduceti al doilea numar: ');

read(b);

asm

FLD b

FLD a

FDIVR

FST c

FLDZ

FLD a

FLD b

FDIVR

FST d

end;

if c > d then

writeln('primul numar este mai mare !');

if c < d then

writeln('al doilea numar este mai mare !');

if c = d then

writeln('cele doua numere sunt egale !');

end.

-84-

In exercitiul anterior,puteti verifica precizia introducand progresiv

numere care difera prin zecimala a 4-a pana la a 10-a zecimala.

Alte operatii sunt implementate prin instructiunile:

FABS -Semnul valorii din ST devine pozitiv (valoarea absoluta)

FCHS -Inverseaza semnul din ST (+ in - sau - in +)

FRNDINT -Rotunjeste valoarea din ST la un numar intreg

FSQRT -Inlocuieste ST prin radacina sa patrata (radical din valoare)

FSCALE -Factorizeaza puterile lui 2,adaugand valoarea din ST(1) la

exponentul valorii din ST.Astfel multiplica valoarea din

varful stivei cu 2 la puterea ST(1).

FPREM -Calculeaza restul efectuand o impartire modul.Valoarea ST este

impartita cu valoarea din ST(1).Restul inlocuieste ST.Valoarea

din ST(1) ramane neschimbata.

EXEMPLU: program assmb97;

{$N+}

uses WinCRT;

var a,b:double;

begin

a:=33.17;

asm

FLDPI

FLD a

FSQRT

FPREM

FST b

end;

writeln('Restul impartirii SQRT(33.17)/PI este: ',b:6:6);

end;

Sau pentru a extrage valoarea intreaga absoluta:

EXEMPLU: program assmb98;

{$N+}

uses WinCRT;

var a,b:double;

begin

a:=-357.12345;

asm

FLD a

FABS

FRNDINT

FST b

end;

writeln('Valoarea intreaga absoluta este: ',b:6:0);

end.

Incercati sa scrieti exercitiile sub forma de functii,care sa returneze

valoarea absoluta,valoarea intreaga si respectiv radacina patrata din

orice valoare introdusa de la tastatura.Daca aveti deja o biblioteca de

functii proprii,includeti si aceste functii.Da nu,incercati sa scrieti

cateva functii proprii (utile) si apoi incercati sa formati o unitate

sau o biblioteca DLL.Principalul avantaj oferit de invatarea acestui

limbaj il reprezinta tocmai aceasta abilitate de a formula functii si

proceduri noi,diferite de cele din unitatile standard.


-85-

8087 include si urmatoarele instructiuni transcendente:

F2XM1 -Calculeaza 2 la puterea x - 1 unde x este valoarea din varful

stivei ST(0),cuprinsa intre 0 si 0.5 (inclusiv).Rezultat in ST.

FYL2X -Calculeaza de y ori logaritm in baza 2 din x,unde x este in

ST iar y este valoarea din ST(1).Rezultratul in ST.Distruge

operanzii.

FYL2XP1 -Calculeaza de y ori log2 (x+1) unde x este in ST si y in ST(1).

Rezultatul in ST.

FPTAN -Calculeaza tangenta valorii din ST prin raportul y/x,unde y

este valoarea din ST iar x este valoarea din ST(1).Apoi impinge

Yüklə 1,03 Mb.

Dostları ilə paylaş:
1   2   3   4   5   6   7   8   9   10




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©muhaz.org 2024
rəhbərliyinə müraciət

gir | qeydiyyatdan keç
    Ana səhifə


yükləyin