Vous êtes sur la page 1sur 60

2016

Ghid Limbaj de asamblare

Asistent univ. drd. RAICU Irina


Academia de Studii Economice din
Bucuresti
Contents
Introducere ...................................................................................................................................... 1
Nivele .......................................................................................................................................... 2
Cum functioneaza limbajul de programare high-level Java? ...................................................... 2
Asamblarea ..................................................................................................................................... 3
Elemente de baza ......................................................................................................................... 3
Tipuri de date in limbaj de asamblare ......................................................................................... 6
Moduri de adresare ...................................................................................................................... 8
Structuri de control .................................................................................................................... 16
Proceduri ................................................................................................................................... 24
Lucru cu fisiere.......................................................................................................................... 42
Lucru in virgula mobila (valori reale) ....................................................................................... 44

Introducere
Fiecare tip de procesor deine propriul su limbaj numit "codul main", care reprezint modul
binar de codificare a instruciunilor i datelor n memorie, n forma direct executabil.
Instruciunile pot fi n general operaii elementare (aritmetice, logice, transfer de date) sau i
operaii de comand i control a procesorului. Codul main este, ca orice cod, format mai ales
din cifre, fiind greu de reinut pentru un programator. De exemplu, un calculator ar putea folosi
pentru instruciunile sale de adunare i scdere codurile main 5B i 5C. ns, n limbajul de
asamblare, aceste dou operaii ar putea fi simbolizate prin ADD i SUB, care sunt mult mai uor
de reinut i folosit.

Pentru a putea fi interpretate de procesor, programul scris de om ("codul surs", scris de exemplu
n limbaj de asamblare) trebuie nti redus prin compilare (sau asamblare sau interpretare) la
"codul obiect" (n cod main), n acest scop fiind folosite "compilatoarele", "asambloarele" sau
"interpretorii".

Programarea n limbaj de asamblare presupune o bun cunoatere a structurii procesorului i a


componentelor sale adiacente. Ea face ca utilizatorul s aib acces la toate facilitile unui
calculator; dar programul rezultat va putea funciona numai pe acest tip de calculator. Dac
programul trebuie portat (transpus) i pe alte tipuri de calculatoare, atunci se prefer limbajele de
programare de nivel mai nalt.
Nivele
Un limbaj de programare se afl la un nivel "nalt" atunci cnd, nainte de a putea fi executat,
trebuie mai nti s treac prin unul sau chiar mai multe filtre de interpretare (compilatoare,
medii de rulare). Nivele:

1. low level: assembler - interacioneaz aproape direct cu procesorul

2. medium level: C++, Pascal - sursele sunt transformate de compilator n cod main

3. high level: Java - pe lng procesul de compilare, necesit JRE (la fel ca Visual C# '08 i
.Net Framework)

Cu ct crete nivelul limbajului, cu att acesta este mai uor de neles de ctre programator, iar
cu ct scade nivelul limbajului, cu att acesta este mai uor de "neles" pentru calculator. Pentru
mrirea eficienei, n codul C++, Visual C++, Basic, Fortran, Pascal sau Delphi pot fi integrate i
poriuni de cod assembler, obinndu-se astfel un cod hibrid.

n funcie de modul de execuie al programelor, limbajele de programare se mpart n dou


categorii :

interpretate: instruciunile sunt citite linie cu linie de un program numit interpretor i


traduse n instruciuni main; avantaj: simplitate; dezavantaj: viteza de execuie
redus;
compilate: codul surs al programelor este transformat de compilator ntr-un cod ce
poate fi executat direct de procesor; avantaj: execuie rapid; dezavantaj: lipsa
portabilitii, codul compilat ntr-un format de nivel sczut nu poate fi rulat dect pe
platforma pe care a fost compilat.

Cum functioneaza limbajul de programare high-level Java?


Programele Java sunt att interpretate ct i compilate

Codul de octei este diferit de codul main. Codul main este reprezentat de o succesiune de 0
i 1; codurile de octei sunt seturi de instruciuni care seamn cu codul scris n limbaj de
asamblare. Codul main este executat direct de ctre procesor i poate fi folosit numai pe
platforma pe care a fost creat; codul de octei este interpretat de mediul Java i de aceea poate fi
rulat pe orice platform care folosete mediul de execuie Java.

Fazele prin care trece un program Java sunt: Cod sursa Java -> (compilare) -> Cod de octeti ->
(interpretare)
Asamblarea
Asamblarea este procesul prin care codul surs, scris n limbaj de asamblare, este transformat n
cod main sau cod obiect. Codul surs poate fi dispus pe mai multe module. Procesul invers se
numete "dezasamblare.
Etapele asamblrii:

1. Mai nti se genereaz o tabel de simboluri, ce conine toate numele simbolice din
programul surs, exceptnd numele simbolice externe (din alte module), instruciuni i
directive de asamblare.
2. Asamblorul contorizeaz instruciunile i datele, asociind numelor simbolice un
"deplasament" fa de nceputul programului, ca i cum programul ar ncepe de la adresa
0. n realitate, programul nu se ncarc n RAM la adresa 0, ci de la o adres furnizat
de sistemul de operare, n spaiul de memorie disponibil; aceast adres chiar poate de
fiecare dat s fie alta. Deci programul furnizat de asamblor trebuie de obicei s fie
"relocabil".
3. Se obine programul obiect, traducnd fiecare instruciune i nlocuind numele simbolice
cu valoarea sau adresa din tabela de simboluri.
4. Programul executabil se obine n urma etapei de editare de legturi (linkage edit), care
permite legarea mai multor module relocabile ntr-un singur fiier executabil,
rezolvndu-se referinele ncruciate dintre ele.

Elemente de baza
Acest tutorial are ca scop descrierea cunostintelor teoretice si practice cu privire la programarea
in limbaj de asamblare pentru procesoarele din familia Intel 8086 pe 16 biti. Folosind aceste
elemente de baza se poate trece cu usurinta la o arhitectura superioara, 32 sau 64 de biti.

Inainte de a realiza o aplicatie in limbaj de asamblare, trebuie intelese o serie de elemente de


baza cu privire la:
Registrele procesorului Intel 8086
Tipurile de date utilizate in limbaj de asamblare
Set registre procesor Intel 8086

Procesorul Intel 8086 are 14 registre pe 16-biti, utilizati n diferite scopuri. Aceste registre pot fi
vazute ca fiind zone de memorie de dimensiune fixa aflate in procesor si care pot fi accesate din
aplicatiile scrise in limbaj de asamblare.

Registrele de baza pot fi accesate si din punctul de vedere a primilor 8 biti, respectiv a ultimilor 8
biti.
De exemplu, daca registrul AX contine valoarea 1234h atunci AH are
valoarea 12h si AL are 34h.
Un registru pe 16 biti numit registru FLAG este utilizat pentru a controla executia instructiunilor.
Flag-urile reprezinta biti ce pot avea valoarea 1 (SET) sau 0 (NOT SET).

Semnificatia indicatorilor de conditie este urmatoarea [6]:

CF (Carry Flag, indicator de transport) semnifica un transport sau un mprumut n, respectiv


din bitul cel mai semnificativ al rezultatului.
PF (Parity Flag, indicator de paritate) este pozitionat dupa cum bitii din cel mai putin
semnificativ octet al rezultatului sunt n numar par (pozitionare pe 1) sau impar (pozitionare
pe 0).
AF (Adjust Flag, indicator de ajustare) este folosit n aritmetica zecimala si semnifica un
transport sau un mprumut n, respectiv din bitul 4 (cel mai semnificativ bit al jumatatii celei
mai putin semnificative) al rezultatului.
ZF (Zero Flag, indicator de zero) indica daca rezultatul unei operatii a fost sau nu zero.
SF (Sign Flag, indicator de semn) are aceeasi valoare ca bitul cel mai semnificativ al
rezultatului (bitul de semn): 0 pozitiv, 1 negativ.
TF (Trap Flag, indicator de urmarire a executiei) este folosit la depanarea programelor prin
executia lor pas cu pas daca este setat, procesorul forteaza automat o exceptie dupa
executia fiecarei instructiuni.
IF (Interrupt Flag, indicator de ntreruperi) precizeaza daca procesorul ia n considerare sau
nu ntreruperile externe.
DF (Direction Flag, indicator de directie) precizeaza sensul (0 crescator sau 1 -
descrescator) n care este modificat contorul de adrese la operatiile cu siruri.
OF (Overflow Flag, indicator de depasire) semnifica depasirea domeniului admisibil la
reprezentarea rezultatului unei operatii aritmetice cu sau fara semn. Practic, este pozitionat
pe 1 daca apare un transport nspre bitul cel mai semnificativ al rezultatului din bitul vecin,
dar nu si din bitul cel mai semnificativ spre CF sau invers, dinspre bitul cel mai semnificativ
spre CF, dar nu si spre bitul cel mai semnificativ din bitul vecin. Similar, la mprumut, este
pozitionat pe 1 daca apare un transport de la bitul cel mai semnificativ la bitul vecin, dar nu
si nspre bitul cel mai semnificativ dinspre CF sau invers, dinspre CF spre b.c.m.s., dar nu si
dinspre bitul cel mai semnificativ spre bitul vecin.

Tipuri de date in limbaj de asamblare

1. Bit
2. Nibble grup de 4 biti; utilizat n codificarea numerelor n format BCD (Binary Coded
Decima)
3. Byte (octet) grup de 8 biti; definire cu db;
4. Word (cuvant) grup de 16 biti sau 2 octeti; definire cu dw;
5. Double (dublu cuvant) grup de 32 biti sau 4 octeti; definire cu dd;
6. Quad grup de 64 biti sau 8 octeti; definire cu dq.
O descriere detaliata a tipurilor de date fundamentale ale limbajului de asamblare:

Tipul de data BYTE

Spatiu ocupat: 1 octet


Definire: a DB 10
Interpretare:
o Intreg pe 8 biti cu sau fara semn
o Caracter ASCII

Tipul de data WORD

Spatiu ocupat: 2 octeti


Definire: a DW 1234h
Interpretare:
o Intreg pe 16 biti cu sau fara semn
o Secventa de 2 caractere ASCII
o Adresa de memorie pe 16 biti

Tipul de data DOUBLE-WORD

Spatiu ocupat: 4 octeti


Definire: a DD 12345678h
Interpretare:
o Intreg pe 32 biti cu sau fara semn
o Numar real simpla precizie
o Adresa de memorie pe 32 biti

Tipul de data QUAD-WORD

Spatiu ocupat: 8 octeti


Definire: a DQ 12345678
Interpretare:
o Intreg pe 64 biti cu sau fara semn
o Numar real dubla precizie
Moduri de adresare
Pentru a intelege modul in care datele si variabilele programului sunt utilizate (citite sau
modificate), in aceasta parte a tutorialului assembler se analizeaza:

Modul de adresare directa in limbaj de asamblare


Modul de adresare indirecta in limbaj de asamblare
o Adresare indexata
o Adresare bazata
o Adresare indexata si bazata
Pentru a intelege mai bine conceptele teoretice descrise, in acest tutorial sunt prezentate si
exemple care pun in practica modurile de adresare pentru:

Citirea unui caracter de la tastatura cu ecou intr-un program scris in limbaj de asamblare
(assembler)
Afisarea unui caracter pe ecran intr-un program scris in limbaj de asamblare (assembler)
Citirea unui sir de la tastatura intr-un program scris in limbaj de asamblare (assembler)
Afisarea unui sir pe ecran intr-un program scris in limbaj de asamblare (assembler)
Adresare directa in limbaj de asamblare
Registrele sunt initializate cu valori constante
Exemplu:

mov AX, 1234h


Numele variabilei este utilizat ca operand in instructiune.
Exemplu:

vector dw 10 dup(5) ; definire vector cu 10 elemente initializate cu valoarea 5

mov AX, vector ;copiaza valoarea primului element de tip cuvant din vector in AX

mov BX, vector[3] ;copiaza valoarea cuvantului care incepe de la offset-ul al treilea

ATENTIE, in exemplul anterior cum elementele vectorului incep de la offset cu valoare


multiplu de 2, rezulta ca in BX se copiaza valoarea 0500h.

Vectorul numit vector se gaseste in segmentul de date memorat astfel:


DS:0000 05 00 05 00 05 00 05 00 05 00
DS:0008 05 00 00 00 00 00 00 00 00 00

iar instructiunea mov BX,vector[3] copiaza in BX 2 octeti (deoarece vector contine elemente de
tip word) insa incepand de la offset-ul 0003 din DS. Deci BX va contine valoarea 0500h.

Valoarea offset-ului este utilizata pentru a citi date direct din segmentul DS.
Exemplu:

vector dw 10 dup(5) ; definire vector cu 10 elemente initializate cu valoarea 5

mov AX, DS:[00h] ;copiaza valoarea primului element de tip cuvant din vector in AX

mov BX,DS:[08h] ;copiaza valoarea cuvantului care incepe de la offset-ul 08h

Cand se specifica offset-ul este absolut necesar sa se utilizeze


expresia DS:[valoare_offset] pentru ca, daca se scrie instructiunea:

mov AX,[08h]

se copiaza in AX doar valoarea 8h (Veti primi si un WARNING [Constant] assumed to mean


immediate constant.)

Adresare indirecta in limbaj de asamblare

Se utilizeaza unul dintre registrele index SI, DI, BP sau registrul de baza BX. Atentie: utilizarea
altor registre va genera eroare: Illegal indexing mode.
Se utilizeaza in general pentru parcurgerea masivelor si pentru a accesa elemente din structuri de
date de tip articol.

Utilizarea registrului index SI sau DI pentru adresare indirecta indexata


registrul SI este utilizat pentru a retine offset-ul elementului pe care dorim sa-l accesam;

vector dw 1234h,1235h,3222h,4343h,5455h

mov SI, offset vector ;incarca in SI offset-ul de inceput al vectorului

mov AX, [SI] ;copiaza in AX valoarea primului element, adica 1234h

mov CX, [SI+2] ;copiaza in CX valoarea elementului al doilea, adica 1235h


mov DX,[SI+3] ;copiaza in DX valoarea 2212h (octetul inferior din 3222h si octetul superior
din 1235h)
acelasi lucru se scrie si:

mov SI, offset vector

mov AX, [SI]

mov CX, [SI][2]


mov DX,[SI][3]
registrul SI sau DI este utilizat asemenea unui indice in parcurgerea masivului;

vector db 1,2,3,4,5,6

XOR SI,SI ; ne asiguram ca SI are valoarea 0

mov AL, vector[SI] ;copiaza in AL valoarea primului element din vector

inc SI

mov AH, vector[SI] ;copiaza in AH valoarea elementului secund din vector

mov CL,vector[SI+1] ;copiaza in CL valoarea celui de al treilea element


mov AL,vector[SI][2] ;copiaza in AL valoarea celui de al patrulea element deoarece SI
contine valoarea 1

in cazul in care vectorul are elemente de tip word parcurgerea acestuia se face marind SI cu
valoarea 2 de fiecare data:

vector dw 1243,2342,3342,44324,53242,63432

XOR SI,SI ; ne asiguram ca SI are valoarea 0

mov AX, vector[SI] ;copiaza in AX valoarea primului element din vector

inc SI

inc SI

mov AX, vector[SI] ;copiaza in AX valoarea elementului secund din vector

mov CX,vector[SI+2] ;copiaza in CX valoarea celui de al treilea element


mov AX,vector[SI][4] ;copiaza in AX valoarea celui de al patrulea element deoarece SI
contine valoarea 2
Utilizarea registrului baza BX pentru adresare indirecta bazata si indexata
registrul BX este utilizat pentru adresare indirecta bazata;
vector db 1,2,3,4,5,6

XOR SI,SI ; ne asiguram ca SI are valoarea 0

mov BX, offset vector ;incarcam in registrul de baza offset-ul de start al vectorului

mov AL, [BX][SI] ;copiaza in AL valoarea primului element din vector

inc SI

add AL, [BX+SI] ;aduna in AL valoarea elementului secund din vector

add AL, [BX+SI+1] ;aduna in AL valoarea celui de al treilea element


add AL,[BX][SI][2] ;aduna in AL valoarea celui de al patrulea element deoarece SI contine
valoarea 1
In exemplele anterioare, SI poate fi inlocuit de DI.

Registrul BX este utilizat si pentru a transmite offset-ul unui articol sau masiv ce reprezinta
parametru de intrare intr-o procedura. Caracterul de generalitate al unei proceduri impune lucrul
in interiorul ei cu offset-ul parametrilor de intrare si nu cu numele lor.

Cand se utilizeaza registrul BX ca registru de baza in adresarile indirecte pentru a memora


offset-ul primului octet al structurii respective, adresa segmentului este data de registrul DS.
Deci, fiecare element identificat prin [BX] se afla memorat la adresa DS:BX (segment:offset).

In cazul in care se utilizeaza registrul BP pentru adresari indirecte, adresa segmentului este data
de registrul SS. Deci BP este utilizat pentru a accesa indirect locatii de memorie din stiva. Din
acest motiv, instructiunea

mov CX,[BP]
copiaza in CX, valoarea din stiva aflata la offset-ul dat de BP, adica SS:BP.

Pentru a forta citirea din segmentul DS la offset-ul dat de BP, instructiunea devine

mov CX,DS:[BP]
Alte instructiuni din limbajul de asamblare pentru Intel 8086:
Instructiunea LOOP
forma analitica a instructiunii este:
LOOP nume_eticheta
decrementeaza registrul CX si sare la eticheta nume_eticheta cu conditia ca valoarea din CX
sa fie mai mare decat zero;
nu afecteaza nici un flag;
instructiunea memoreaza intr-un octet offset-ul etichetei fata de pozitia sa in segmentul de
cod; deci, eticheta trebuie sa se gaseasca la o distanta de maxim128 de octeti in interiorul
segmentului de cod fata de pozitia instructiunii LOOP;
utilizata de obicei pentru a implementa instructiuni de control repetitive;
Exemplu: determinarea sumei elementelor unui vector.

.model small

.286

.stack 100h

.data

vector db 1,2,3,4,5,6,7

n db 7 ;dimensiunea vectorului

suma db 0 ;suma elementelor

.code

mov AX,@data

mov DS,AX

xor SI,SI

xor CX,CX ;ne asiguram ca CX are valoarea 0

mov CL,n ;copiem in CL dimensiunea vectorului

repeat: ;definim eticheta

mov AL,vector[SI]

add suma,AL
inc SI ;marim valoarea din SI cu 1 pentru a trece la
;elementul urmator
loop repeat ;salt la eticheta cat timp CX diferit de 0

mov AX,4c00h
int 21h

end

Instructiunea LEA
forma analitica a instructiunii este:
LEA registru, operand

incarca in registrul specificat offset-ul operandului;


registrul nu poate fi unul dintre registrele de segment;
exemplu:
.data

vb dw 1234h,1235h

.code

mov SI,offset vb ;incarca registrul SI cu valoarea offest-ului variabilei vb

lea DI,vb ;incarca registrul DI cu valoarea offest-ului variabilei vb

Exemple Citirea si afisarea pe ecran


Citirea unui caracter de la tastatura cu ecou intr-un program scris in limbaj de asamblare
(assembler).
se realizeaza utilizand rutina DOS 21h;
registrul AH are valoarea 01h;
codul ASCII al caracterului citit este pus in registrul AL;
transformarea caracterului citit intr-un numar (cu conditia ca acesta sa reprezinte o cifra) cu
valoarea cuprinsa intre 0 si 9 se face scazand din AL valoarea 30h, ce reprezinta codul
ASCII al caracterului 0;
exemplu:

.data

nr db ?

.code

mov ah,01h ;initializare AH cu codul functiei


int 21h ;apel rutina

sub al,30h ;transformare cod ASCII aferent cifrei in valoare intreaga

mov nr,al ;copiere valoare numar

Afisarea unui caracter pe ecran intr-un program scris in limbaj de asamblare (assembler).
se realizeaza utilizand rutina DOS 21h;
registrul AH are valoarea 02h;
codul ASCII al caracterului citit este pus in registrul DL;
afisarea unei valori numerice implica transformarea cifrelor in echivalentul lor ASCII (se
adauga la valoarea cifrei valoarea 30h, ce reprezinta codul ASCII al caracterului 0);
exemplu:

.data

nr db 5

caracter db 'g'

.code

mov DL,caracter

mov ah,02h ;initializare AH cu codul functiei

int 21h ;apel rutina si afisare caracter <em>g</em> pe ecran

mov DL,nr

mov ah,02h

int 21h ;apel rutina si afisare pe ecran caracter cu codul ASCII egal cu 5

mov DL,nr

add, DL,30h ;obtinere cod ASCII al cifrei din DL

mov ah,02h

int 21h ;apel rutina si afisare pe ecran a caracterului <em>5</em>



Afisarea unei valori numerice mai mari decat 9 pe ecran implica prelucrari prin intermediul
carora sa se obtina codul ASCII al tuturor cifrelor din numar.

Afisarea unui sir pe ecran intr-un program scris in limbaj de asamblare (assembler).
se realizeaza utilizand rutina DOS 21h;
registrul AH are valoarea 09h;
adresa de inceput a sirului de caractere trebuie sa se gaseasca in DX; acest lucru se
realizeaza prin intermediul instructiunii LEA sau a instructiunilor LES / LDS (descrise in
Seminar 1)
Important: ultimul caracter din sir trebuie sa fie $ (24h); functia afiseaza sirul pana
intalneste primul caracter $
exemplu:

...

.data

mesaj db "Afisare mesaj !!!","$"

.code

...

mov AH,09

lea DX,mesaj

int 21h

...

Citirea unui sir de la tastatura intr-un program scris in limbaj de asamblare (assembler).
se realizeaza utilizand rutina DOS 21h;
registrul AH are valoarea 0Ah;
adresa din segmentul de date (offset-ul) in care se face memorarea sirului citit trebuie scrisa
in DX; sirul citit de la tastatura se scrie la adresa DS:DX
primul octet de la adresa DS:DX trebuie sa contina numarul maxim n de caractere al sirului
(rutina permite citirea de la tastatura doar a n-1 caractere); neinitializarea primului octet cu
valoarea n poate conduce la situatiile: acesta are valoarea 0 si nu se citesc caractere sau
acesta are o valoarea reziduala mai mare / mica decat lungimea maxima dorita;
introducerea sirului la tastatura se incheie cu Enter (0Dh);
rutina va scrie in al doilea octet de la adresa DS:DX numarul de caractere efectiv citit de la
tastatura;
ultimul octet din sir este codul ASCII al tastei Enter (0Dh)
exemplu:
.data
vb dw 1234h,1234h,1234h
sir db 5 ;valoare necesara pentru a indica numarul maxim de caractere de citit
.code
mov AX,@data
mov DS,AX

mov dx,0006h ;incarc in DX offset-ul la care incepe scrierea sirului de caractere


mov ah,0ah
int 21h

mov AX,4c00h
int 21h
end
Structuri de control
In acest tutorial destinat limbajului de asamblare pentru procesoare din familia Intel 8086 sunt
prezentate structurile de control:

structura alternativa, sau structura IF


structura pre-conditionata, sau WHILE-DO
structura post-conditionata, sau DO-WHILE
structura alternativa multipla, sau CASE
Structura alternativa IF
In limbajele de nivel inalt structura de control alternativa este asociata cu expresia IF-THEN-
ELSE. Implementarea structurii alternative presupune:

evaluarea unei expresii;


compararea a doua valori.
In ambele cazuri sunt initializate flag-urile de conditie, prezentate in partea I a tutorialului.

Daca conditia evaluata este adevarata, atunci se executa secventa de instructiuni de pe


ramura true; altfel expresiile de pe ramura false au prioritate.
In Assembler se utilizeaza pentru a compara doi operanzi instructiunile

CMP
CMPSB
CMPSW.
Tipuri de salturi in limbaj de asamblare
salturi neconditionate: JMP;
salturi conditionate: JA sau JNBE, JAE sau JNB, JB sau JNAE, JBE sau JNA, JC, JCXZ
sau JECXZ, JE sau JZ, JG sau JNLE, JGE sau JNL, JL sau JNGE, JLE sau JNZ, JNC, JNE
sau JNG, JNO, JNP sau JPO, LOOP, LOOPE sau LOOPZ, LOOPNE sau LOOPNZ.
Procesorul 8086 permite mai multe modalitati de a efectua un salt prin intermediul
instructiunii jmp. Destinatia saltului poate fi in acelai segment (intrasegment) sau intr-un
segment diferite (intersegment).

Instructiunea CMP
Flag-urile (descrise in Partea 1 Elemente de baza) modificate de rezultatul instructiunii CMP
sunt:
OF;
SF;
ZF;
AF;
PF;
CF;
Instructiunea CMP compara cei doi operanzi prin intermediul unei scaderi logice. Asta inseamna
ca cei doi operanzi nu sunt modificati, insa bitii de flag sunt setati astfel incat sa indice rezultatul
diferentei.

Exemplu de secventa de cod necesara compararii a doua valori intregi in limbaj de asamblare.
CMP DX, BX;
Cand BX = 0004 i DX = 0008,
DX BX = 0004 (Atentie aceasta scadere nu modifica operanzii)

nu are loc overflow (OF=0)

rezultatul este pozitiv (SF=0)

Cand BX = 000A i DX = 0008,


DX BX = FFFE (- 2)

- nu are loc overflow (OF=0)

negativ (SF=1)

Alte exemple pentru instructiunea assembler CMP


se considera registrele si valorile AX = 10, BX = -12 (decimal)
CMP AX, BX
AX BX = +22

PL (positive, SF=0), CY (carry, CF=1), NV (no

Overflow, OF=0), NZ (not zero, ZF=0)

CMP BX, AX
BX AX = -22

NG (negative, SF=1), NC (no carry, CF=0), NV (no

Overflow, OF=0), NZ (not zero, ZF=0)

CMP AX, AX
AX AX = 0

PL (positive, SF=0), NC (no carry, CF=0;), NV (no

Overflow, OF=0), ZR (zero, ZF=1)

Ce putem compara?
registru cu registru: CMP AX, BX
registru cu memorie (variabile definite): CMP AX, mval
registru cu constante: CMP AX, 42
memorie cu registru: CMP mval, AX
memorie cu constanta (!) CMP mval, 42
Ce nu putem compara?
Nu se poate compara memorie cu memorie!!!
CMP a, b ;instructiune gresita
Una dintre valori trebuie copiata intr-un registru inainte de a realiza comparatia.
Salturi conditionate
Salturile conditionate sunt utilizate pentru a trece la o alta locatie in segmentul de cod in
fucntie de valorile anumitor biti de flag;
Numerele care sunt comparate pot reprezenta atat valori cu semn cat i fara semn. Flag-uri
diferite sunt verificate in functie de interpretarea valorilor.
Cum tie procesorul cum interpreteaza utilizatorul valorile (fie cu semn, fie fara semn)?
Raspuns: in functie de tipul instructiunii de salt.
Salturi fara semn (valorile comparate sunt considerate fara semn) se refera prin cuvintele
cheie above pentru mai mare i below pentru mai mic.
Salturile cu semn se refera prin greater i less.
Exemplu program assembler in care este evidentiata diferenta dintre Valori cu semn vs.
Valori fara semn
.data

total dw 0FFFFh ; sari daca total < 10 (cu semn)


.code

CMP total, 10

JL less10 ;sari daca total &lt; 10

less10:
;FFFFh = -1, codul va sari la less10 pt. ca 1 < 10.
;sari daca total < 10 (fara semn)
CMP total, 10

JB less10 ; sare daca total < 10

less10: ;Acest cod nu va efectua saltul la <strong>less10</strong> pentru ca valoarea


;FFFFh luata fara semn este 65535 &gt; 10.</p>

Intrebare: Cum tie programul daca sa considere FFFFh ca fiind 1 or 65,535?


Raspuns: Utilizatorul ii spune acest lucru prin tipul instructiunii de salt conditionat.
Utilizarea salturilor conditionate
Salturile conditionate sunt utilizate de obicei dupa o instructiune CMP.
Se pot utilizat salturi conditionate i dupa o operatie aritmetica pentru ca i acestea modifica
bitii de flag in functie de rezultat.

Expresia de tip If implementata in limbaj de asamblare

Exemplu aplicatie assembler in care este utilizata structura de control de tip IF


.data

op1 db 10

op2 db 12

op3 db ?

.code

mov al, op1 ;why?

cmp al, op2 ; op1 = op2?

jne eticheta ; daca nu, sari

mov bl, op2 ;expresia 1

mov op3, bl ;expresia 2

eticheta:

add al, op2


Expresia de tip IF-THEN-ELSE implementata in limbaj de asamblare

Exemplu aplicatie assembler in care este utilizata structura de control de tip IF-THEN-ELSE
mov ax, temp

mov bx, max

cmp ax, bx ;compara temp cu max

if: ;"if"

jle els ;sari daca temp &lt;= max

mov max, ax ;temp &gt; max "then"

jmp done ;salt neconditionat

else:

inc bx ; temp &lt;= max "else"

mov max, bx

done:
Expresia de tip DO-WHILE implementata in limbaj de asamblare

Exemplu aplicatie assembler pentru determinarea sumei elementelor unui vector, ce


implementeaza structura de control Do-While prin intermediul instructiunii Loop.
.model small

.286

.stack 100h

.data

vector db 1,2,3,4,5,6,7

n db 7 ;dimensiunea vectorului

suma db 0 ;suma elementelor

.code

mov AX,@data

mov DS,AX

xor SI,SI

xor CX,CX ;ne asiguram ca CX are valoarea 0

mov CL,n ;copiem in CL dimensiunea vectorului

repeat: ;definim eticheta

mov AL,vector[SI]
add suma,AL
inc SI ;marim valoarea din SI cu 1 pentru a trece la elementul urmator
loop repeat ;salt la eticheta cat timp CX diferit de 0

mov AX,4c00h

int 21h

end
Expresia de tip WHILE-DO implementata in limbaj de asamblare

Expresia de tip CASE implementata in limbaj de asamblare


Proceduri
In acest tutorial destinat imbajului de asamblare pentru procesoare din familia Intel 8086 sunt
prezentate procedurile. Acestea permit reutilizarea codului si reducerea dimensiunii acestuia insa
implica un efort suplimentar generat de trimiterea parametrilor si apel.
Atentie: La procesoarele 8086 urmatoarea instructiune de executat este determinata de
continutul registrelor CS:IP (registrul asociat segmentului de cod CS si pointerul la
instructiune IP) ce reprezinta adresa fizica a segmentului de cod si offset-ul in cadrul
acestuia.
Instructiunile de salt neconditionat (Ex. JMP) permit salturi in program insa intoarcere la punctul
de salt este gestionata in intregime de utilizator care trebuie fie sa indice punctul respectiv printr-
o eticheta care ulterior sa fie de o instructiune de salt, fie sa salveze continutul registrului IP.

Apelurile de proceduri, reprezinta salturi la secvente de cod (reutilizabile) declarate de utilizator


in corpul procedurii, care permit reintoarcerea la punctul de start. Acest lucru este posibil prin
implementarea instructiunilor CALL (apel procedura) si RET (iesire din procedura si intoarcere
in programul apelator).

Diferenta dintre CALL si JMP este data de faptul ca prima instructiune salveaza pe stiva inainte
de a face saltul adresa instructiunii urmatoare.

Tipuri de CALL

near; salveaza pe stiva valoarea pe 16 biti din IP si face salt la prima instructiune din corpul
procedurii; are forma interna pe 3 bytes: 1 byte codul operatiei (E8h), 2 bytes reprezentand
distanta ca numar de bytes pana la codul procedurii;
far; salveaza pe stiva valoarea din CS si apoi din IP; are forma interna pe 5 bytes: 1 byte
codul operatiei (9Ah), 2 bytes offset si 2 bytes adresa segemntului.
Sintaxa declararii unei proceduri:

Nume_procedura PROC [FAR | NEAR]


..
[Nume_procedura] ENDP
Structura generala a unei proceduri scrisa in limbaje de asamblare este:
Apelul si iesirea din proceduri
Apelul unei proceduri se face prin instructiunea CALL:

sintaxa: CALL operand


aceasta salveaza pe stiva adresa instructiunii urmatoare (daca saltul este de tip intersegment
far se salveaza inainte si adresa din CS) si executa salt la locatia indicata de operand;
tipul operandului este:

instructiunea CALL se traduce prin secventele de instructiuni:


pentru NEAR
PUSH IP ; salvare adresa instructiunii urmatoare lui CALL

JMP adresa_salt ;adresa_salt reprezinta un offset si este indicata de operand


pentru FAR
PUSH CS ;salvare adresa segment de cod curent

PUSH IP ; salvare adresa instructiunii urmatoare lui CALL

JMP adresa_salt ;adresa_salt reprezinta un sehment+offset si este


indicata de operand

Iesirea din proceduri se realizeaza prin instructiunea RET:

sintaxa: RET [valoare numerica]


aceasta scoate de pe stiva adresa instructiunii urmatoare (daca saltul este de tip intersegment
far se restaureaza dupa IP si CS salvat anterior) si initializeaza registrele care controleaza
executarea instructiunilor, IP si CS (ambele daca procedura a fost de tip FAR);
daca se da si valoarea numerica optionala are loc curatarea stivei prin modificarea pozitiei
curente din stiva (indicata de SP) adunand la SP atatia bytes cati indica valoarea numerica;
instructiunea RET se traduce prin secventele de instructiuni:
pentru NEAR
POP IP ;reinitializeaza registrul IP cu valoarea salvata la intrarea in procedura
;cum acest registru contine offsetul instructiunii de executat, programul se ;reia de la
instructiunea urmatoare saltului

[add SP, valoare_numerica] ;instructiune optionala care se


executa doar daca se da ;instructiunea RET + valoare numerica
pentru FAR
POP IP
POP CS ;reinitializeaza registrul CS cu adresa segmentului de cod
[add SP,valoare_numerica]
instructiunea stie ce iesire sa faca in functie de modul in care a fost declarata procedura sau
mai exact in functie de tipul apelului FAR sau NEAR; la asamblare fiecare instructiune de
tip return este inlocuita cu RETN sau RETF (instructiunile pot fi utilizate a se vedea
exemplul urmator) care reprezinta forma explicita a instructiunii de iesire.

Realizarea unei proceduri fara PROC si ENDP


Exemplul urmator subliniaza modul de interpretare interna a procedurii asemenea unei secvente
de cod la care se realizeaza salturi si de la care programul stie sa se intoarca gestionand adresa
punctului de start.

Procedura realizeaza suma a doua numere de tip word ale caror valori sunt puse pe stiva iar
rezultatul este returnat in registrul CX.

.model small
.286
.stack 100h
.data
a dw 5
b dw 3
s dw ?
.code

mov AX,@data
mov DS,AX

push a ;pun valoarea lui a pe stiva


push b; ;pun valoarea lui b pe stiva

call NEAR PTR start_procedura ;apel explicit de procedura NEAR

mov s, CX ;pun rezultatul in s

mov AX, 4c00h


int 21h

start_procedura: ;eticheta ce indica inceputul procedurii


push BP ;salvez valoarea din BP
mov BP,SP ;initializez BP cu valoarea lui SP pentru a-l utiliza
;ca reper in citirea datelor de pe stiva
push AX ;salvez valoarea lui AX
mov AX,[BP+6] ;copiez in AX valoarea lui a primita pe stiva
;a se vedea figura de mai jos care descrie stiva in acest moment
add AX,[BP+4] ;adun in AX valoarea lui b primita pe stiva
mov CX,AX ;pun rezultatul in CX
pop AX ;restaurez AX
mov SP,BP ;copiez in SP valoarea din BP
;aduc SP la pozitia reperului
pop BP ;restaurez SP
retn ;return de tip NEAR scote doar IP de pe stiva
end
Acelasi program in limbaj de asamblare se scrie utilizand directivele PROC si ENDP:

.model small
.286
.stack 100h
.data
a dw 5
b dw 3
s dw ?
.code
mov AX,@data
mov DS,AX
push a
push b
call suma
mov s, CX
mov AX, 4c00h
int 21h
suma PROC
push BP
mov BP,SP
push AX
mov AX,[BP+6]
add AX,[BP+4]
mov CX,AX
pop AX
mov SP,BP
pop BP
ret
ENDP
end

Proceduri de tip FAR

Procedurile FAR sunt proceduri care se gasesc in alt segment decat cel curent. Pentru a
exemplifica o astfel de situatie se definesc explicit segmentele si se renunta la definirea
simplificata a unui program utilizand directivele .model .code .stack .data. De exemplu, se scrie
programul assembler care aduna doua numere de tip double trimitand parametrii prin referinta pe
stiva.
Variabile SEGMENT ;declar un segment numit Variabile in care declar
;datele
a dd 1234677
b dd 3456123
sum dd ?
Variabile ENDS ;sfarsit segment de date

Stiva SEGMENT ;declar segment numit Stiva in care rezerv 512 octeti
;pentru a-i utiliza pe post de stiva
dw 100h dup(?)
baza label word ;declar o variabila simbolica de tip word pentru a
;lua offset-ul in stiva
Stiva ENDS ;sfarsit segment de stiva

Principal SEGMENT ;declar segment numit Parincipal in care scriu codul


;programului principal
ASSUME CS:Principal,DS:Variabile,SS:Stiva
;se realizeaza asocieri logice intre registrele de
;segment si segmentele utilizate NU inseamna ca
;sunt si initializate registrele
start:
mov AX, Variabile ;initializez DS
mov DS,AX
mov AX,Stiva ;initializez SS
mov SS,AX
mov SP,offset baza ;initializez SP

mov AX,offset a ;pun pe stiva adresa lui a


push AX
mov AX,offset b ;pun pe stiva offset b
push AX
mov AX,offset sum ;pun pe stiva offset sum
push AX
call FAR PTR suma ;apel procedura FAR

mov AX,4c00h
int 21h
Principal ENDS ;sfarsit segment de cod principal

Procedura SEGMENT ;definesc un alt segment de cod in care scriu


;procedura
ASSUME CS:Procedura
;asociere logica
suma PROC FAR ;definesc procedura
push BP ;salvez BP
mov BP,SP ;initializez BP cu valoarea lui SP
push AX ;salvez AX
mov SI,[BP+10] ;copiez in SI offset a
mov DI,[BP+8] ;copiez in DI offset b
mov AX,[SI] ;copiez in AX cuvant inferior din a
add AX,[DI] ;adun la AX cuvant inferior din b
push SI ;salvez continut SI adica affset a
mov SI,[BP+6] ;copiez in SI offset sum
;a se vedea figura urmatoare ce descrie stiva in acest punct
mov [SI],AX ;copiez in sum suma cuvintelor inferioare
pop SI ;restaurez SI adica offset a
mov AX,[Si+2] ;adun cu carry cuvinte superioare din a si b
adc AX,[DI+2]
mov SI,[BP+6]
mov [SI+2],AX ;copiez in partea superioara a sum rezultatul
pop AX ;restaurez AX
mov SP,BP
pop BP
ret 6 ;curat stiva stergand logic cele 3 offset-uri
suma ENDP
Procedura ENDS
end start
Reguli la scriere procedurilor:
secventele de cod ce compun corpul procedurii realizeaza operatii cu caracter general;
utilizarea registrelor in proceduri implica salvarea continutului acestora pe stiva inainte de
efectuarea prelucrarilor si restaurarea lor de pe stiva inainte de a iesi; pentru acest lucru se
utilizeaza instructiunile PUSH (pune pe stiva) si POP (scoate de pe stiva). De exemplu:
ProcTest PROC
push AX
push BX
push CX

Pop CX
Pop BX
Pop AX
ret
ENDP
Atentie: Restaurarea registrelor cu POP se face in ordine inversa salvarii cu PUSH.
citirea datelor de pe stiva se realizeaza numai cu registrul BP
Apeluri indirecte de proceduri
Se realizeaza prin intermediul pointerilor la functii. De exemplu programul in limbaj de
asamblare care aduna doua numere de tip word prin intermediul unei proceduri.

.model small
.286
.stack 100h
.data
pointer_functie dw ? ;pointer la functie de tip NEAR
pointer_functie_far DD ? ;pointer la functie de tip FAR
a dw 5
b dw 3
s dw ?
dif dw ?
.code

mov AX,@data
mov DS,AX

mov AX, offset suma ;incarc in AX offset proecdura


mov pointer_functie,AX ;initializez pointerul la procedura

mov AX,a ;trimit parametrii prin registrii


mov BX,b
call pointer_functie ;apelez procedura NEAR

mov s,CX
; incarc pointerul cu offsetul si adresa segmentului
mov WORD PTR pointer_functie_far,offset diferenta
mov WORD PTR pointer_functie_far+2,seg diferenta
mov AX,a ;trimit parametrii prin registrii

call pointer_functie_far ;apelez procedura FAR


; sau call FAR PTR diferenta ;apel prin nume

mov dif,CX
mov AX, 4c00h
int 21h
suma PROC
add AX,BX
mov CX,AX
ret
ENDP
diferenta PROC FAR ;declar explicit procedura de tip FAR
sub AX,BX
mov CX,AX
ret
ENDP
end
In exemplul anterior procesorul stie ce tip de procedura sa apeleze pentru ca pointerii sunt
declarati ca fiind de tip word, respectiv, double, ceea ce inseamna ca poate sa contina doar
offsetul procedurii apelate (in cazul near) sau adresa completa, segment de cod + offset (pentru
far).
In caz ca exista un vector de variabile de tip pointeri la functii, la apelul procedurii trebuie
indicat explicit tipul acesteia prin WORD PTR (pentru NEAR) sau DWORD PTR (pentru FAR).

Daca in exemplul anterior incarc in SI offsetul de inceput al variabilei pointer_functie (simulez


utilizarea unui vector) si atunci apelurile echivalente sunt:
call WORD PTR [SI] ;apel de tip near pentru suma

call DWORD PTR [SI+2] ;apel de tip far pentru diferenta


Daca se da apelul call [SI] atunci implicit se considera ca apelul este de tip NEAR si se vor citi 2
octeti de la adresa [SI] reprezentand offsetul saltului. De aceea este important (mai ales in cazul
salturilor de tip FAR) sa se indice explicit tipul saltului prin WORD sau DWORD.

Transmiterea parametrilor de intrare in proceduri

Pentru a exemplifica fiecare metoda, se realizeaza un program care verifica daca elementele de
tip student (definit prin nume, varsta si numar matricol) ale unui vector au campul varsta cu
valori cuprinse intr-un interval definit.

Se realizeaza utilizand:

variabile declarate in memorie in segmentul de date; situatia este echivalenta in limbajele


de nivel inalt cu utilizarea variabilelor declarate global in interiorul subprogramelor; prima
varianta a programului implementeaza modelul small de definire a segmentelor si a tipului
de memorie.
.model small
.286
.stack 100h
.data
student struc ;definesc structura de date
nume db 10 dup (?)
varsta db ?
nr_matricol dw ?
ends
dimStudent equ size student ;dimensiune student 13 octeti

s1 student <'Popescu',22,1234>
s2 student <'Ionescu',21,1235>
mes_eroare db 'Depasire limite!','$'
mes_corect db 'Date corecte!','$'

lim_inf db 14
lim_sup db 89
.code
Validare PROC ;procedura valideaza doar varsta studentului s1
push BP
mov BP,SP
push aX

xor AX,AX
mov AL,lim_inf ;copiez in AL valoarea limitei inferioare
mov AH,lim_sup ;copiez in AH valoarea limitei superioare
cmp AL,s1.varsta ;compar varsta cu limita inferioara
ja eroare ;daca varsta e mai mica, afisez mesaj
cmp AH,s1.varsta ;compar varsta cu limita superioara
jb eroare ;daca varsta e mai mare,afisez mesaj

mov AH,09h ;afisez mesaj date corecte


lea DX,mes_corect
int 21h
jmp final

eroare:
mov AH,09h ;afisez mesaj eroare
lea DX,mes_eroare
int 21h
final:
pop AX
mov SP,BP
pop BP
ret ;termin procedura
ENDP

start: ;indic de unde incep instructiunile programului


mov AX,@data
mov DS,AX

call validare

mov AX,4c00h
int 21h

end start ;indic terminarea programului dar si de unde incepe


;executia codului
A doua versiune a programului assembler utilizeaza segmente definite de programator.

Date SEGMENT ;segmentul de date


student struc
nume db 10 dup (?)
varsta db ?
nr_matricol dw ?
ends
dimStudent equ size student
s1 student <'Popescu',22,1234>
s2 student <'Ionescu',21,1235>
mes_eroare db 'Depasire limite!','$'
mes_corect db 'Date corecte!','$'
lim_inf db 14
lim_sup db 89
Date ENDS

Stiva SEGMENT ;segmentul aferent stivei


dw 100 dup (?) ;rezerv 100 de cuvinte pentru stiva
varf label word ;definesc o eticheta pentru a extrage adresa bazei stivei
Stiva ENDS

Main SEGMENT ;segmentul aferent codului


ASSUME CS:Main,DS:Date,SS:Stiva ;fac asocieri logice

Validare PROC ;procedura valideaza doar varsta studentului s1


push BP
mov BP,SP
push aX
xor AX,AX
mov AL,lim_inf ;copiez in AL valoarea limitei inferioare
mov AH,lim_sup ;copiez in AH valoarea limitei superioare
cmp AL,s1.varsta ;compar varsta cu limita inferioara
ja eroare ;daca varsta e mai mica, afisez mesaj
cmp AH,s1.varsta ;compar varsta cu limita superioara
jb eroare ;daca varsta e mai mare,afisez mesaj

mov AH,09h ;afisez mesaj date corecte


lea DX,mes_corect
int 21h
jmp final

eroare:
mov AH,09h ;afisez mesaj eroare
lea DX,mes_eroare
int 21h
final:
pop AX
mov SP,BP
pop BP
ret ;termin procedura
ENDP

start: ;indic de unde incep instructiunile programului


mov AX,Date ;incarc in DS adresa segmentului de date
mov DS,AX
mov AX,Stiva ;incarc in SS adresa segmentului de stiva
mov SS,AX
mov AX,varf ;initializez SP cu offsetul curent in stiva
mov SP,AX

call validare ;apelez procedura

mov AX,4c00h
int 21h
Main ENDS

end start ;indic terminarea programului dar si de unde incepe


;executia codului
Marele dezavantaj al acestei metode de transmitere a parametrilor este diminuarea caracterului
de generalitate pe care procedura trebuie sa-l aiba, deoarece este conditionata de existenta
variabilelor (in cazul anterior lim_inf, lim_sup si s1) definite in segmentul de date.

registrele pentru a transmite parametrii de intrare; consider mesajele de avertizare ca fiind


declarate global si atunci trebuie doar sa trimit in procedura limitele intervalului si valoarea
de verificat; pentru a realiza acest lucru folosesc AX pentru limitele intervalului (lim_inf in
AL si lim_sup in AH) si CL pentru valoarea de verificat; se observa ca din toate datele
studentului intereseaza doar varsta si atunci trimit doar aceasta data.
.model small
.286
.stack 100h
.data
student struc
nume db 10 dup (?)
varsta db ?
nr_matricol dw ?
ends
dimStudent equ size student ;dimensiune student 13 octeti
s1 student <'Popescu',22,1234>
mes_eroare db 'Depasire limite!','$'
mes_corect db 'Date corecte!','$'
lim_inf db 14
lim_sup db 89
.code
Validare PROC ;procedura valideaza varsta oricarui student, aceasta ;fiind trimisa prin CL
push BP
mov BP,SP
push AX ;salvez valoarea din AX, poate mai trebuie
push CX;

cmp AL,CL ;compar varsta cu limita inferioara


ja eroare ;daca varsta e mai mica, afisez mesaj
cmp AH,CL ;compar varsta cu limita superioara
jb eroare ;daca varsta e mai mare,afisez mesaj

mov AH,09h ;afisez mesaj date corecte


lea DX,mes_corect
int 21h
jmp final

eroare:
mov AH,09h ;afisez mesaj eroare
lea DX,mes_eroare
int 21h
final:
pop CX
pop AX
mov SP,BP
pop BP
ret ;termin procedura
ENDP
start: ;indic de unde incep instructiunile programului
mov AX,@data
mov DS,AX

mov AL,lim_inf
mov AH,lim_sup
xor CX,CX
mov CL,s1.varsta

call validare

mov AX,4c00h
int 21h
end start
Dezavantajul metodei deriva din numarul limitat de registre si din faptul ca instructiunile
salvare/restaurare a valorilor registrelor pe/de pe stiva consuma resurse (de exemplu daca
valoarea parametrului de intrare ce a fost trimisa prin intermediul registrului AX este necesara in
procedura dupa efectuarea altor prelucrari trebuie sa ne asiguram ca nu o pierdem salvand-o pe
stiva).

stiva pe post de zona de transfer a datelor catre proceduri; utilizarea stivei in acest sens se
face in doua moduri in functie de semnificatia valorilor de pe stiva: adresa variabilei
(referinta) sau valoarea ei; indiferent de modul ales, secventa se rezuma la a salva valorile
respective pe stiva (prin instructiunea PUSH) inainte de a apela procedura si la a le accesa
in procedura prin intermediul registrului BP; primul program exemplifica transmiterea
parametrilor pe stiva prin valoare, iar al doilea transmite referinta variabilelor de intrare.
.model small
.286
.stack 100h
.data
student struc
nume db 10 dup (?)
varsta db ?
nr_matricol dw ?
ends
dimStudent equ size student ;dimensiune student 13 octeti
s1 student <'Popescu',22,1234>
mes_eroare db 'Depasire limite!','$'
mes_corect db 'Date corecte!','$'

lim_inf db 14
lim_sup db 89
.code
Validare PROC ;procedura valideaza varsta oricarui student, aceasta ;fiind trimisa prin stiva
push BP
mov BP,SP
push AX
push CX
;* a se vedea figura stivei de mai jos

mov AL,[BP+6]
mov AH,[BP+7]
mov CL,[BP+4]
cmp AL,CL ;compar varsta cu limita inferioara
ja eroare ;daca varsta e mai mica, afisez mesaj
cmp AH,CL ;compar varsta cu limita superioara
jb eroare ;daca varsta e mai mare,afisez mesaj

mov AH,09h ;afisez mesaj date corecte


lea DX,mes_corect
int 21h
jmp final
eroare:
mov AH,09h ;afisez mesaj eroare
lea DX,mes_eroare
int 21h
final:
pop CX
pop AX
mov SP,BP
pop BP
ret 4 ;termin procedura si golesc stiva
ENDP
start: ;indic de unde incep instructiunile programului
mov AX,@data
mov DS,AX

mov AL,lim_inf ;salvez pe stiva limitele intervalului


mov AH,lim_sup
push AX
xor CX,CX
mov CL,s1.varsta ;salvez pe stiva varsta studentului
push CX

call validare ;apelez procedura

mov AX,4c00h
int 21h
end start
In cazul acestui program, la momentul * stiva este descrisa de figura urmatoare:

Atentie ! In cazul trimiterii parametrilor de tip sir de caractere este indicat sa se utilizeze metoda
prin referinta deoarece punerea unui sir pe stiva este o operatie ineficienta ce consuma spatiu si
cicluri masina. Din acest motiv, s-a trimis doar valoarea varstei studentului pe stiva si nu intreaga
structura.
Al doilea exemplu de program assembler descrie trimiterea referintelor pe stiva.

.model small
.286
.stack 100h
.data
student struc
nume db 10 dup (?)
varsta db ?
nr_matricol dw ?
ends
dimStudent equ size student ;dimensiune student 13 octeti
s1 student <'Popescu',22,1234>
mes_eroare db 'Depasire limite!','$'
mes_corect db 'Date corecte!','$'
lim_inf db 14
lim_sup db 89
.code
Validare PROC ;procedura valideaza varsta oricarui student, acesta
;este trimis prin stiva utilizand referinta sa
push BP
mov BP,SP
push AX
push CX
push SI
push DI
;* a se vedea figura stivei de mai jos

mov SI,[BP+8]
mov AL,[SI]
mov SI,[BP+6]
mov AH,[SI]
mov SI,[BP+4]
cmp AL,[SI].varsta ;compar varsta cu limita inferioara
ja eroare ;daca varsta e mai mica, afisez mesaj
cmp AH,[SI].varsta ;compar varsta cu limita superioara
jb eroare ;daca varsta e mai mare,afisez mesaj

mov AH,09h ;afisez mesaj date corecte


lea DX,mes_corect
int 21h
jmp final

eroare:
mov AH,09h ;afisez mesaj eroare
lea DX,mes_eroare
int 21h
final:
pop DI
pop SI
pop CX
pop AX
mov SP,BP
pop BP
ret 6 ;termin procedura si golesc stiva
ENDP
start: ;indic de unde incep instructiunile programului
mov AX,@data
mov DS,AX

mov AX,offset lim_inf


push AX
mov AX,offset lim_sup
push AX
mov AX, offset s1
push AX

call validare

mov AX,4c00h
int 21h
end start

Atentie ! In cazul trimiterii parametrilor prin referinta pe stiva orice modificare a valorii lor
utilizand o adresare indirecta (bazata sau indexata) are loc in segmentul de date si valoarea se
pastreaza si dupa iesirea din procedura.
Transmiterea parametrilor de iesire din proceduri
Intoarcerea rezultatelor din proceduri se realizeaza prin intermediul registrelor AX, BX, CX, DX.
De exemplu, programul care aduna doua numere de tip double trimise prin valoare returneaza
suma in registrele CX (cuvantul inferior) si DX (cuvantul superior)

Lucru cu fisiere
In acest tutorial destinat imbajului de asamblare pentru procesoare din familia Intel 8086 sunt
prezentate modalitatile de lucru cu fisiere:
Creare fisier
Inchidere fisier
Deschidere fisier
Scriere in fisier
Citire din fisier
Pozitionare in fisier
Extindere jump-uri de tip short

In programele realizate in limbaj de asamblare fisierul este identificat prin:


nume (sir de caractere), la operatiile de deschidere si creare
handler (valoare pozitiva pe 16 biti ce identifica in mod unic fisierul pe disc sau alte
dispozitive), la operatiile de inchidere, citire, scriere, pozitionare
Exista o serie de handler-e asociate unor dispozitive standard:

Principalele functii DOS pentru lucrul cu fisiere sunt:


Considerand urmatoarele variabile definite in segmentul de date al unui program ce foloseste
fisiere:

handler dw ? ;handler la fisier

atribut dw ? ;atribut creare fisier

tipDeschid dw ? ;modul de deschidere a fisierului

rez db ? ;variabila verificare reusita operatie

numeFis db 'fisier.dat',0 ;nume fisier

NrOctetideScris dw ? ;numarul de octeti de scris in fisier

NrOctetiScrisi dw ? ;numarul de octeti scrisi efectiv in fisier


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:

Atentie ! La declararea variabilelor reale se utilizeaza . si nu ,


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 09 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:

exemplu de numar real in forma binara


forma interna generala a unui numar real in virgula mobila
(-1) *M*2(E-Bias)
S

S Bit de semn; are valoarea 0 pentru pozitiv si 1 pentru negativ;


M Mantisa; este normalizata; are valori cuprinse in intervalul [1.000 , 1.111];
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
semn exponent parte zecimala
pentru long real:
63 62 52 51 32 31 0
semn exponent parte zecimala parte zecimala
pentru real pe 10 octeti:
79 78 64 63 62 32 31 0
semn exponent intreg parte zecimala parte 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:

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:
Registru 79 78 63 62 0

ST(0)

ST(1)

ST(2)

ST(3)

ST(4)

ST(5)

ST(6)

ST(7)

semn exponent parte 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 incep cu F.
*
Format instructiune Sintaxa Operatori impliciti

Classical stack Finstructiune ST,ST(1)

Memory Finstructiune variabila ST

Register Finstructiune ST(nr),ST -


Finstructiune ST,ST(nr)

Register pop FinstructiuneP -


ST(nr),ST
*
- preluate din Micrsoft MASM Programmers 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

ST 3.6 3.14 11.304 1 12.304 1.23 13.534 -

ST(1) - 3.6 - 11.304 - 12.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

ST 1.23 3.6 1.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
#1 #2 #3 #4 #5 #6 #7 #8 #9 #10 #11
2
1.2 1.2 1.512 10.770 10.770 10.770
ST 1.23 3.6 3.6 4.428 5.658 -
3 3 9 9 9 9

ST( 1.2 1.512


- 1.23 1.23 1.23 1.23 1.23 1.23 1.23 - -
1) 3 9

ST( 1.512 5.112 5.112 5.112


- - - - 5.1129 - - -
2) 9 9 9 9

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

ST 1.23 3.6 3.5 7.43 3.5 3.6 15.76 -

ST(1) - 1.23 3.6 3.5 3.6 12.16 - -


ST(2) - - 1.23 3.6 8.66 - - -

ST(3) - - - 1.23 - - - -

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:
aduna doua numere reale
FADD [operanzi]
FADDP op1,op2 aduna cei doi operanzi si descarca stiva
FIADD vb
aduna un intreg de 16/32 de biti la ST

scade numere reale

scade op2 din op1 si se descarca stiva


FSUB [operanzi]
FSUB op1,op2 scade intreg de 16/32 de biti din ST
FSUB vb
FSUBR [operanzi] scade inversa numerele reale
FSUBRPop1,op2
FSUBR vb scade op1 din op2 si se descarca stiva

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

inmultire numere reale


FMUL [operanzi] FMULP
op1,op2 FMUL vb inmultire de numere reale (op1 * op2), cu descarcarea stivei
inmultire ST cu intreg din memorie, de 16/32 de biti
impartire de numere reale (op1/op2)

FDIV [operanzi] impartire op1/op2 si descarcarea stivei


FDIVP op1,op2
FIDIV vb impartirea lui ST la un intreg de 16/32 de biti
FDIVR [operanzi]
FDIVRP opl/op2 impartire inversa de numere reale (op2/op1)

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


stivei
FDIVR vb
impartirea unui intreg de 16/32 de biti la ST

radacina patrata din ST


FSQRT
FSCALE STST*2ST(1), ST(1) interpretat ca intreg impartire modulo:
FPREM ST / ST(1)
FRNDINT
FXTRACT 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|
FABS
FCHS 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; -1ST1


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. registru Registre de control

1 Cuvant de control

2 Cuvant de stare

3 Cuvant Eticheta (Tag)

4
Instruction Pointer
5

6
Operand 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:

15 14 13 12 11 10 9 8
C3 C2 C1 C0

Octetul inferior al registrului de flag-uri al procesorului:

7 6 5 4 3 2 1 0

SF ZF AF PF CF
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 FCOM Dupa FTEST C3 C2 C0

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 instructiuni de comparare a valorilor reale:

FCOM op compara 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