Tutorial Limbaj de Asamblare (Assembler) Intel 8086 – Partea 8 – Lucru in virgula mobila (valori reale)

In acest tutorial destinat imbajului de asamblare pentru procesoare din familia Intel 8086 sunt prezentate modalitatile de lucru cu variabile si constante reale. Acest set de valori, in virgule mobila, necesita o alta abordare decat exemplele cu valori intregi din tutoarialele anterioare deoarece prelucrarile sunt realizate de catre coprocesorul matematic.

Variabile si constante reale

Tipurile de date de tip real sunt:

TipNr. bițiCifre semnificativeInterval de valoriDeclarare
Short real326-71.18 * 10-38 → 3.40 * 1038vb DD 1.2
Long real6415-162.23 * 10-308 → 1.79 * 10308vb DQ 2.3
10-byte real80193.37 * 10-4932 → 1.18 * 104932vb DT 1.8
Tipurile de date de tip real

Atenție ! La declararea variabilelor reale se utilizează . (punct) si nu , (virgula)

Declararea valorilor reale se poate realiza atat in format zecimal cat si hexazecimal. In format zecimal se utilizeaza reprezentarea:

[+ | -] parte intreaga [parte zecimala] [E [+ | -] exponent]

Numerele sunt considerate a fi in baza zece. De exemplu:

a	DD	11.765            ;forma zecimala
b	DD	1.1765E+1	;forma exponentiala zecimala
c	DQ	1176.5E-2	;forma exponentiala zecimala

In format hexazecimal reprezentarea numerelor reale utilizeaza cifrele 0 → 9 si A → F. Numarul trebuie sa inceapa obligatoriu cu una din cifrele 0→9 si sa se termine cu eticheta r ce indica tipul numarului ca fiind real. Numarul de simboluri din reprezentarea hexazecimala este 8 pentru Short real, 16 pentru Long real si 20 pentru 10-Byte real. In caz ca primul simbol din numar este unul din caracterele A → F atunci se mai pune un 0 in fata, iar dimensiunea ca numar de simboluri creste cu unu. De exemplu:

a	DD	3F800000r
b	DQ	3D60000000000000r
c	DT	0A456C000000000000000r

Pentru a usura lucrul cu date de tip real se pot defini propriile tipuri de date:

float 	TYPEDEF	DD
double	TYPEDEF	DQ
long_double	TYPEDEF	DT

Formatul intern al numerelor reale este:

Valoare reala
Formatul real de reprezentare a valorilor reale
  • exemplu de numar real in forma binara
  • forma interna generala a unui numar real in virgula mobila

(-1)S*M*2(E-Bias)

  • S     – Bit de semn; are valoarea 0 pentru pozitiv si 1 pentru negativ;
  • M     – Mantisa; este normalizata; are valori cuprinse in intervalul [1.00…0 , 1.11…1]; primele 2 formate nu mai reprezinta intern primul bit egal cu 1
  • E     – Exponent; reprezinta forma binara a exponentului; utilizat pentru a reface forma zecimala a numarului;
  • Bias     – permite reprezentarea valorilor negative ale exponentului; faciliteaza comparatia intre numere reale.
  • pentru short real (simpla precizie):
31| 30 23 |22 0
semnexponentparte zecimala
short real (simpla precizie)
  • pentru long real:
63 62 < – > 5251 < – > 3231 < – > 0
semnsemnparte zecimalaparte zecimala
Bit range pentru long real
  • pentru real pe 10 octeti:
7978 < – > 646362 <- > 3231 < – > 0
semnexponentîntregparte zecimalaparte zecimala

Formele de reprezentare reprezinta formatul IEEE [http://en.wikipedia.org/wiki/IEEE_754], [http://grouper.ieee.org/groups/754/] .

Dupa cum se observa la numerele reale pe 10 octeti, partea intreaga este reprezentata de bitul 63. Acest bit permite atingerea unei precizii de 19 cifre. Partea intreaga este intotdeauna 1 la numere short real si long real si de aceea nu mai este memorata.

Valoarea exponentiala reprezinta o putere a lui 2n. Pentru a se retine si valori negative de tipul 2-8, valoarea exponentului este ajustata adunand la ea valoarea 127 pentru numere reale simpla precizie (short real), 1023 pentru numere reale dubla precizie (long real) si 16383 pentru precizie extinsa (real pe 10 octeti).

Valoarea de ajustare este scazuta la conversia inversa din format intern (binar) in format extern (zecimal).

Exemplu de transformare a unui numar real din format zecimal in format binar:

Se considera numarul real -134,25. Transformarea acestuia in formatul intern IEEE presupune:

  1. Identificarea semnului numarului; S = 1;
  2. Transformare in format binar: 10000110,01
  3. Normalizare forma binara: 1.000011001 x 27
  4. Transformare exponent prin aplicare deplasare (bias): 7 + 127 = 134
  5. Transformare exponent in format binar: 10000110
  6. Obtinere format intern:

S

EXPONENT

MANTISA

1

1

0

0

0

0

1

1

0

0

0

0

0

1

1

0

0

1

0

0

0

0

0

0

0

0

0

0

0

0

0

0

Transformare valoare reala in format binar
Transformare valoare reala in format binar
Forma binara a unui numar real
Forma binara a unui numar real

Arhitectura coprocesorului matematic

  • are propriile registre de date si de control: 8 registre de date organizate sub forma de stiva si 7 registre de control (asemenea registrelor flag);
  • cele 8 registre de date sunt pe 80 de biti si sunt organizate sub forma de stiva, cu toate ca permit si acces direct; datele sunt incarcate in registrul din varf, ST(0) si coboara catre baza, registrul ST(7);
  • registrul din varful stivei este ST(0) sau ST, urmand apoi ST(1), ST(2), …, ST(7);
  • odata incarcate datele sunt convertite automat la format pe 10 octeti;
  • stiva registrelor coprocesorului este:
Registru7978< – >6362 < – > 0
ST(0)    
ST(1)   
ST(2)   
ST(3)   
ST(4)   
ST(5)   
ST(6)   
ST(7)   
 semn exponentparte zecimala

Tipuri de instructiuni

Cele 8 registre de date pot fi accesate ca elemente ale unei stive sau ca elemente individuale asemenea registrelor procesorului. Toate instructiunile coprocesorului pentru prelucrarea valorilor reale încep cu F.

*Format instructiuneSintaxaOperatori impliciți
Classical stack FinstructiuneST,ST(1)
Memory Finstructiune variabilaST
Register Finstructiune ST(nr),ST
Finstructiune ST,ST(nr)
Register pop FinstructiuneP
ST(nr),ST

*– preluate din Micrsoft MASM Programmer’s Guide

Formatul Classical Stack

  • sinatxa Finstructiune
  • considera registrele coprocesorului ca parti componente ale unei stive; valorile sunt adaugate sau scoase din varful stivei, adica ST sau ST(0);
  • operatorii impliciti sunt ST(0) (sursa) si ST(1) (destinatie);
  • rezultatul instructiunii este pus in registrul destinatie, iar valoarea din sursa (adica ST) este scoasa din stiva;

Atentie ! Nu toate instructiunile de tip Classical Stack utilizeaza cei doi operanzi impliciti, ci doar acele instructiuni care in mod uzual au doi operanzi (de exemplu Fadd); de exemplu instructiuni de acest format sunt:

  • FLD1 – incarca in ST valoarea 1;
  • FLDZ – incarca in ST valoarea 0;
  • FLDPI – incarca in ST valoarea lui pi, 3,14;
  • FLDL2E – incarca in ST log2e;
  • FLDL2T – incarca in ST log210;
  • FLDLG2 – incarca in ST log102;
  • FLDLN2 – incarca in ST loge2.

Atentie ! Pentru a vizualiza registrele coprocesorului in Turbo Debugger se deschide fereastra Numeric Processor din View → Numeric processor.

Atentie ! Instructiunea Fxch interschimba valorile din ST si ST(1) dar fara a scoate valoarea din ST.

Atentie ! Daca se dau mai mult de 8 instructiuni succesive de tip FLD (adica se incarca mai mult de 8 valori in registrele ST, ST(1), …, ST(7) fara a se scoate nici una dintre ele, coprocesorul indica situatia punand in registrul ST(0) valoarea NAN (Not a Number).

Exemplu aplicatie assembler ce prelucreaza valori reale: evaluarea expresiei: e = a + 1 + b * pi

DateIn SEGMENT
	a DD 1.23
	b DD 3.6
DateIn ENDS

DateOut	SEGMENT
	e DD ?
DateOut ENDS

Main SEGMENT
	ASSUME CS:Main, DS:DateIn, ES:DateOut
start:
	mov AX,DateIn
	mov DS,AX
	mov AX,DateOut
	mov ES,AX

	Fld b	;#1
	Fldpi	;#2
	Fmul		;#3
;are operanzi impliciti pe ST(1),ST
	Fld1		;#4
	Fadd		;#5
	Fld a	;#6
	Fadd		;#7
	Fstp es:e	;#8
;pune rezultatul in e si scoate valoarea din ST

	mov AX,4c00h
	int 21h
Main ENDS

end start

Pentru programul anterior stiva registrelor coprocesorului trece prin urmatoarele faze:

#1#2#3#4#5#6#7#8
ST3.63.1411.304112.3041.2313.534
ST(1)3.11.30412.304
ST(2)

Formatul Memory

  • sintaxa Finstructiune variabila
  • instructiuni care realizeaza transfer de valori in si din registrele coprocesorului; considera registrele coprocesorului incluse intr-o stiva;
  • operator implicit registrul ST sau ST(0);
  • pune sau scoate valori din varful stivei; exemple de astfel de instructiuni:

FLD nume_variabila – incarca pe stiva (adica in ST) valoarea variabilei;

FST nume_variabila – copiaza (nu scoate) valoarea din varful stivei in variabila;

Exemplu interschimbarea in limbaj de asamblare a 2 valori reale utilizand coprocesorul matematic

DateIn SEGMENT
	a DD 1.23
	b DD 3.6
DateIn ENDS

Main SEGMENT
	ASSUME CS:Main, DS:DateIn
start:
	mov AX,DateIn
	mov DS,AX

	Fld a	;#1
	Fld b	;#2
	Fstp a	;#3
			;pune valoarea din ST in a si o scoate
	Fstp b	;#4

	mov AX,4c00h
	int 21h
Main ENDS
end start

Pentru programul anterior stiva registrelor coprocesorului trece prin urmatoarele faze:

  #1#2#3#4
ST1.233.61.23
ST(1)1.23
ST(2)

Formatul Register

  • sintaxa FinstructiuneP : ST(nr),ST;
  • instructiuni care trateaza registrele coprocesorului ca registre independente si ca parti ale unei stive;
  • operandul sursa trebuie sa fie ST;
  • primul operand este destinatia, iar cel de-al doilea este sursa;
  • rezultatul instructiunii este pus in destinatie, iar valoarea din sursa (ST – varful stivei) este scoasa din stiva;
  • astfel de instructiuni sunt cele ce implementeaza operatii matematice si care necesita scoaterea valorii sursei din stiva:

Exemplu aplicatie assembler ce prelucreaza valori reale: evaluarea expresiei: e = a + b + a*b + a2

DateIn SEGMENT
	a DD 1.23
	b DD 3.6
DateIn ENDS

DateOut	SEGMENT
	e DD ?
DateOut ENDS

Main SEGMENT
	ASSUME CS:Main, DS:DateIn, ES:DateOut
start:
	mov AX,DateIn
	mov DS,AX
	mov AX,DateOut
	mov ES,AX

	Fld a		;#1
	Fld a		;#2
	Fmul ST,ST	;#3
	Fxch ST(1)	;#4
	Fld b		;#5
	Fadd ST(2),ST	;#6
	Fmul ST,ST(1)	;#7
	Fadd ST,ST(1)	;#8
	Fadd ST,ST(2)	;#9
	Ffree ST(2)	;#10
				;eliberez registrul ST(2)
	Ffree ST(1)	;#11
	Fstp ES:e		;#12

	mov AX,4c00h
	int 21h
Main ENDS
end start

Pentru programul anterior stiva registrelor coprocesorului trece prin urmatoarele faze:

 #1#2 #3#4#5#6#7#8#9#10#11#12
ST1.231.231.51291.233.63.64.4285.65810.770910.770910.7709
ST(1)1.231.231.51291.231.231.231.231.231.23
ST(2)1.51295.11295.11295.11295.1129

Formatul Register

  • sintaxa Finstructiune ST(nr),ST sau Finstructiune ST,ST(nr);
  • instructiuni care trateaza registrele coprocesorului ca registre independente si nu ca parti ale unei stive;
  • indiferent de sintaxa, unul dintre operanzi trebuie sa fie ST;
  • primul operand este destinatia, iar cel de-al doilea este sursa;
  • rezultatul instructiunii este pus in destinatie, sursa ramanand nemodificata;
  • astfel de instructiuni sunt cele ce implementeaza operatii matematice si care necesita scoaterea valorii din varful stivei;

Exemplu aplicatie assembler ce prelucreaza valori reale: evaluarea expresiei: e = a + b + c + d

DateIn SEGMENT
	a DD 1.23
	b DD 3.6
	c DD 3.5
	d DD 7.43
DateIn ENDS

DateOut	SEGMENT
	e DD ?
DateOut ENDS

Main SEGMENT
	ASSUME CS:Main, DS:DateIn, ES:DateOut
start:
	mov AX,DateIn
	mov DS,AX
	mov AX,DateOut
	mov ES,AX

	Fld a		;#1
	Fld b		;#2
	Fld c		;#3
	Fld d		;#4
	Faddp ST(3),ST	;#5
	Faddp ST(2),ST	;#6
	Faddp ST(1),ST	;#7
	Fstp ES:e		;#8

	mov AX,4c00h
	int 21h
Main ENDS
end start

Pentru programul anterior stiva registrelor coprocesorului trece prin urmatoarele faze:

  #1 #2#3 #4 #5 #6 #7 #8 #9 #10 #11 #12

ST 1.23 1.23 1.5129 1.23 3.6 3.6 4.428 5.658 10.7709 10.7709 10.7709
ST(1) 1.23 1.23 1.5129 1.23 1.23 1.23 1.23 1.23 1.23
ST(2) 1.5129 5.1129 5.1129 5.1129 5.1129

Exemplu complet de program in limbaj de asamblare ce rezolva ecuatia de gradul al 2-lea: aX2+bX+c=0 unde a = 3.8, b = 8.2 si c = 1.6.

DateIn SEGMENT
	a DD 3.8
	b DD 8.2
	c DD 1.6
DateIn ENDS

DateOut	SEGMENT
	x1 DD ?
	x2 DD ?
DateOut ENDS

Main SEGMENT
	ASSUME CS:Main, DS:DateIn
start:
	mov AX,DateIn
	mov DS,AX

	Fld1		;incarc valoarea 1 in ST - #1
	Fadd ST,ST	;adun ST cu ST si obtin 2 - #2
	FLD ST	;incarc valoarea din ST - #3
	Fmul a	;obtin 2*a - #4

	Fmul ST(1),ST	;calculez valoarea lui 4*a - #5
	Fxch		;interschimb ST cu ST(1) - #6
	Fmul c	;inmultesc ST cu c si obtin valoarea lui 4*a*c - #7

	Fld b		;incarc valoarea lui b in ST - #8
	Fmul ST,ST	;inmultesc ST cu ST si obtin b*b - #9
	FsubR		;scadere inversa (adica ST(1) = ST-ST(1) si scoate 
;valoarea din ST  - #10
			;doar Fsub ar fi scazut ST(1) = ST(1)-ST
			;am obtinut valoarea lui b*b - 4*a*c

;ATENTIE PROGRAMUL NU VALIDEAZA DACA VALOAREA DIN CARE FACE RADICAL 
;ESTE SAU NU MAI MICA DECAT ZERO (tema !!!)

	Fsqrt		;radical din ST adica din b*b-4*a*c - #11
	Fld b		;incarc valoarea lui b - #12
	Fchs		;schim semnul valorii din ST - #13
	Fxch		;interschimb valorile din ST si ST(1) - #14
	
	Fld ST	;incarc valoarea lui ST (valoarea radicalului) - #15
	Fadd ST,ST(2)	;adun in ST ST+ST(2) si obtin -b + valoare 
;radical - #16
	Fxch			;interschimb valorile din ST si ST(1) - #17
	Fsubp ST(2),ST	;fac ST(2) = ST(2) - ST si apoi scot valoarea 
;lui ST - #18
	
	ASSUME DS:DateOut		;schimb segmentul de date
	mov AX,DateOut		;pentru a scrie valoarea rezultatelor
	mov DS,AX

	Fdiv ST,ST(2)	;fac ST = ST / ST(2) - #19
	Fstp x1		;scot rezultatul in x1 - #20
	FdivR		;impartire inversa adica ST(1) = ST /ST(1)
			;si scot valoarea din ST - #21
			;pe impartire normala Fdiv face ST(1) = ST(1)/ST
	Fstp x2	;scot rezultatul in x2 - #22
	

	mov AX,4c00h
	int 21h
Main ENDS
end start

Pentru programul anterior stiva registrelor coprocesorului trece prin urmatoarele faze:

 

#1

#2

#3

#4

#5

#6

#7

#8

#9

#10

ST

1

2

2

7.6

7.6

15.2

24.32

8.2

67.24

42.92

ST(1)

 

2

2

15.2

7.6

7.6

24.32

24.32

7.6

ST(2)

7.6

7.6

ST(3)

ST(4)

 

#11

#12

#13

#14

#15

#16

#17

#18

#19

#20

#21

ST

6.55

8.2

-8.2

6.55

6.55

-1.64

6.55

-1.64

0.21

-14.75

-1.94

ST(1)

7.6

6.55

6.55

-8.2

6.55

6.55

-1.64

-14.75

-14.75

7.6

ST(2)

7.6

7.6

7.6

-8.2

-8.2

-8.2

7.6

7.6

ST(3)

7.6

7.6

7.6

ST(4)

Alte tipuri de instructiuni

ATENtie ! In cazul instructiunilor cu 2 operanzi , primul este destinatia iar al doilea este sursa. Rezultatul operatiei se pune in destinatie, deci aceste instructiuni sunt echivalente operatiei destinatie = destinatie <operatie> sursa. In cazul instructiunilor care au un R la sfarsit (de ex: FsubR, FdivR) operatia are loc invers, adica: destinatie = sursa <operatie> destinatie.

Instructiunile care au un P la sfarsit scot valoarea din ST.

Operatii aritmetice:

FADD [operanzi]

FADDP op1,op2

FIADD vb

aduna doua numere reale

aduna cei doi operanzi si descarca stiva

aduna un intreg de 16/32 de biti la ST

FSUB [operanzi]

FSUB op1,op2

FSUB vb

FSUBR [operanzi]

FSUBRPop1,op2

FSUBR vb

scade numere reale

scade op2 din op1 si se descarca stiva

scade intreg de 16/32 de biti din ST

scade inversa numerele reale

scade op1 din op2 si se descarca stiva

scade ST dintr-un intreg de 16/32 de biti

FMUL [operanzi] FMULP op1,op2 FMUL vb

inmultire numere reale

inmultire de numere reale (op1 * op2), cu descarcarea stivei inmultire ST cu intreg din memorie, de 16/32 de biti

FDIV [operanzi]

FDIVP op1,op2

FIDIV vb

FDIVR [operanzi]

FDIVRP opl/op2

 

FDIVR vb

impartire de numere reale (op1/op2)

impartire op1/op2 si descarcarea stivei

impartirea lui ST la un intreg de 16/32 de biti

impartire inversa de numere reale (op2/op1)

impartire inversa de numere reale (op2/op1) cu descarcarea stivei

impartirea unui intreg de 16/32 de biti la ST

FSQRT

FSCALE

FPREM

FRNDINT

FXTRACT

 

FABS

FCHS

radacina patrata din ST

ST←ST*2ST(1), ST(1) interpretat ca intreg impartire modulo: ST / ST(1)

rotunjire varf stiva, ST, la intreg ‘

descompune numarul din varful stivei in doua numere: exponent si mantisa; dupa care mantisa este depusa in stiva.

ST = |ST|

ST = -ST

Instructiuni matematice pentru calcule complexe in limbaj

FCOS

cosinusul lui ST

FPATAN

arctangent de ST(1 )/ST si extrage (descarca) ST

FPTAN

tangenta partiala de ST (Y/X – rezultat), Y inlocuieste ST, X este depus in stiva

FSIN

sinusul lui ST

FSINCOS

(temp)← ST, ST = sin (temp) si depune in stiva cos(temp)

F2XM1

2ST-1; -1≤ST≤1

FYL2X

ST(1) = ST(1) * log2(ST(0)) si descarca stiva

FYL2XP1

ST(1) = ST(1) * log2(ST(0)+1) si descarca stiva

Instructiuni de comparare si de control

O parte din flag-urile celor 7 registre (pe 16 biti) de control gestioneaza operatiile coprocesorului si starea curenta a acestuia.

Nr. registruRegistre de control
1Cuvânt de control 
2Cuvânt de stare 
3Cuvânt Eticheta (Tag) 
4Instruction Pointer
5
6Operand pointer
7

Registrul asociat cuvantului de stare este cel mai folosit, restul fiind utilizati de programatorii de sistem.

Modul in care sunt aranjati bitii din octetul superior este identic cu modul de aranjare a flag-urilor din registrul de flag al procesorului. Situatia un este intamplatoare si faciliteaza controlul executiei programului in cazul coprocesorului (acesta nu are instructiuni de salt conditionat si atunci trebuie sa trimita procesorului informatia).

Octetul superior al cuvantului de stare:

15141312111098
C3 C2C1C0
Octetul superior al registrului de flag-uri al procesorului

Octetul inferior al registrului de flag-uri al procesorului:

76543210
SFZF AF PFCF
Octetul inferior al registrului de flag-uri al procesorului

Coprocesorul are instructiuni care seteaza flag-urile din cuvantul de stare (unul dintre registrele de stare). Acest registru este utilizat pentru a controla executia programului si pentru a introduce structuri de control prin intermediul salturilor conditionate. Singura problema este ca, coprocesorul matematic nu are instructiuni de salt, doar procesorul are. Din acest motiv cuvantul de stare trebuie incarcat in memorie in Flag-urile procesorului astfel incat sa se pastreze semnificatia valorilor. Solutia este data de incarcarea octetului superior din cuvantul de stare in octetul inferior din registrul de flag-uri al procesorului prin secventa:

Fstsw 	variabila_de_tip_word	;pun valoarea cuvantului de stare intr-o variabila	
Fwait
mov 	AX, variabila_de_tip_word	;incarc valoarea variabilei in AX
sahf					;incarc valoarea din AH in registrul de Flag al 
;procesorului

Odata incarcata aceasta valoare se pot instructiuni de salt conditionat pe baza valorilor din registrele coprocesorului matematic.

Coprocesorul are o serie de instructiuni care analizeaza valoare din registrul ST in relatie cu valoarea altui operand si raporteaza rezultatul intr-un cod de conditie (dat de bitii C0, C1, C2, C3) ai cuvantului de stare. Operatiile de baza sunt de comparare si de testare(comparare cu zero).

Modul in care sunt afectati bitii C0, C1, C2, C3 este:

Dupa FCOMDupa FTESTC3C2C0
ST > sursa ST > 0 0 0 0
ST < sursa ST < 0 0 0 1
ST = sursa ST = 0 1 0 0
Nu se poate compara Nu se poate testa; ST are valoarea NAN 1 1 1

Alte instrucțiuni de comparare a valorilor reale:

FCOM opcompara ST cu operandul (registru sau rnemorie)
FCOMP op compara ST cu operandul (registru sau memorie) si descarca stiva
FCOMPP compara ST cu ST(1) si extrage ambele valori din stiva
FICOM vb compara ST cu un intreg de 16/32 de biti
FICOMP vb compara ST cu un intreg de 16/32 de biti si extrage ST din stiva
FUCOM op comparare cu NaN (Not a Number)
FUCOMP op comparare cu NaN (Not a Number) si extrage varful stivei
FUCOMPP op compara ST cu ST(1) si extrage arabele valori din stiva
FTST compara SI cu 0.0
FXAM examineaza ST si stabileste codurile de conditie
FINIT reseteaza coprocesorul si cuvintele de stare si control
FFREE [reg] marcheaza registrul indicat ca fiind eliberat