Sunteți pe pagina 1din 78

Limbaj de Asamblare (Assembler) Intel 8086 Partea 1 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
Pentru a intelege exemplele si pentru a aprofunda aceste cunostinte, pot fi utilizate resursele:
[1] Microsoft Press Programmers Guide, Microsoft MASM, Assembly-Language Development System,
Version 6.1, For MS-DOS and Windows Operating Systems, Microsoft Press, 1992
[2] Randall Hyde The Art of
Assembly Language Programming, format electronic, 1996
[3] Dan Somnea, Vladut TEODOR Programarea n Assembler, Ed. Tehnica, Bucuresti, 1992.
[4] Gheorghe Musca Programare n limbaj de Asamblare, Ed. Teora, Bucuresti 1997.
[5] Vasile LUNGU Procesoare INTEL Programare n Limbaj de asamblare, Editura TEORA, Bucuresti, 2000.
[6] Ion IVAN, Paul POCATIUL, Doru CAZAN Limbaje de asamblare, Academia de Studii Economice
Bucuresti, Centrul de nvatamant Economic deschis la Distanta, Bucuresti, 2002
[7] Ion IVAN, Paul POCATIUL, Doru CAZAN Practica dezvotarii software in Limbaje de asamblare, Editura
Economica, Bucuresti, 2002
[8] Laur IVAN Programarea n limbaj de asamblare, Culegere de probleme, Editura ASE, Bucuresti, 1997.
Software necesar:
Editor: orice editor ASCII simplu (Microsoft Notepad, Notepad++, editor MS-DOS)
Turbo Assembler 2.5, Turbo Linker 4.0 si Turbo Debugger 2.5 (arhiva utilitare )

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.

Registre de
Segment
CS

Code Segment

Numar pe 16-biti ce reprezinta adresa segmentului de cod activ.

DS

Data Segment

Numar pe 16-biti ce reprezinta adresa segmentului de date activ.

SS

Stack Segment

Numar pe 16-biti ce reprezinta adresa segmentului de stiva activ.

ES

Extra Segment

Numar pe 16-biti ce reprezinta adresa segmentului suplimentar


activ.

IP

Instruction
Pointer

Numar pe 16-biti ce reprezinta offeset-ul instructiunii urmatoare de


executat n cadrul segmentului de cod.

SP

Stack Pointer

Numar pe 16-biti ce reprezinta offeset-ul din cadrul stivei.

BP

Base Pointer

Utilizat pentru a transfera n/din stiva date.

Accumulator
Register

Calcule si operatii de intrare/iesire

Registre index

Registre de
baza
AX

BX

Base Register

Utilizat ca index

CX

Count Register

Utilizat in instructiunile de ciclare

DX

Data Register

Operatii de intrare/iesire, nmultire/mpartire.

SI

Source Index

Utilizat in operatiile cu siruri pentru a parcurge sursa.

DI

Destination Index Utilizat in operatiile cu siruri pentru a parcurge sursa.

Registre index

Registrele de baza pot fi accesate si din punctul de vedere a primilor 8 biti, respectiv a ultimilor 8 biti.

AX
AH AL
BX
BH BL
CX
CH CL
DX
DH DL
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).

Registru de FLAG-uri
Abr.

Nume

Nr. bit

OF

Overflow Flag

11

DF

Direction Flag

10

IF

Interrupt Flag

TF

Trap Flag

SF

Sign Flag

ZF

Zero Flag

AF

Auxiliary Carry

PF

Parity Flag

CF

Carry Flag

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
o

Intreg pe 8 biti cu sau fara semn


Caracter ASCII

Tipul de date Byte - limbaj de asamblare


Tipul de data WORD

Spatiu ocupat: 2 octeti


Definire: a DW 1234h
Interpretare:

o
o
o

Intreg pe 16 biti cu sau fara semn


Secventa de 2 caractere ASCII
Adresa de memorie pe 16 biti

Tipul de date Word - limbaj de asamblare


Tipul de data DOUBLE-WORD

Spatiu ocupat: 4 octeti


Definire: a DD 12345678h
Interpretare:

o
o
o

Intreg pe 32 biti cu sau fara semn


Numar real simpla precizie
Adresa de memorie pe 32 biti

Tipul de date Double - limbaj de asamblare


Tipul de data QUAD-WORD

Spatiu ocupat: 8 octeti


Definire: a DQ 12345678
Interpretare:

o
o

Intreg pe 64 biti cu sau fara semn


Numar real dubla precizie

Tipul de date Quad - limbaj de asamblare

Limbaj de Asamblare (Assembler) Intel 8086 Partea 2 Prima aplicatie


Pentru a intelege intr-un mod practic programarea in limbaj de asamblare, in aceasta parte a tutorialului
assembler se analizeaza 2 exemple simple. Se descriu:

Etapele de realizare a aplicatiei in limbaj de asamblare


Structura unui program assembler
Tipuri de instructiuni assembler
Interfata aplicatiei Turbo Debugger

Etape in realizarea unui program in Limbaj de Asamblare (Assembler)


1. Editare fisier sursa numit fisier.ASM cu un editor de text simplu; NOTEPAD in Windows sau editorul de DOS
apelat din linia de comanda: C:\>edit fisier.asm
2. construirea fisierului obiect si verificarea codului din sursa: C:\> tasm fisier.asm
3. daca nu exista erori de asamblare se construieste fisier.OBJ
4. obtinerea executabilului: C:\> tlink fisier.OBJ

5. rularea executabilului in Debugger: C:\> td fisier


Utilitarele, Turbo Assembler, Turbo Linker si Turbo Debugger, utilizate in acest tutorial sunt disponibile in arhiva
din partea 1 a tutorialului Tutorial Limbaj de Asamblare (Assembler) Intel 8086 Partea 1 Elemente de baza.
Pentru a eficientiza partea de editare si testare a programului assembler se poate construi un fisier batch pentru
a executa automat pasii descrisi.
Fisier batch pentru editare si realizare programe assembler:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

REM Fisier pentru dezvoltarea unui program in limbaj de asamblare


@ECHO off
ECHO Lansare editor pentru fisier sursa
:AAA
EDIT %1.asm
PAUSE
ECHO Lansare asamblor pentru celelalte fisiere: .obj,.lst,.crf
TASM %1
PAUSE
ECHO Daca in urma asamblarii apar erori, se reia editarea
IF errorlevel 1 GOTO AAA
PAUSE
ECHO Obtin executabilele
TLINK %1.obj;
ECHO Lansare in executie a programului prin TD
td %1.exe

Se salveaza fisierul cu numele executa.bat Din linia de comanda se tasteaza executa nume_programsi automat
se urmaresc pasii de realizare a unui program assembler.

Descriere interfata TURBO DEBUGGER

Turbo Debugger Interface


Fereastra A

descrie segmentul de cod al programului;


in partea dreapta adresele CS:0005 indica adresa in segmentul de cod a instructiunii respective;
simbolul (sageata) indica instructiunea curenta;
instructiunile sunt executate pas cu pas utiliznd tasta F8;
valoarea hexa alaturata adresei CS:0005 A00000 este reprezentarea interna a instructiunii mov al, [0000].
Fereastra B
descrie registrele si valorile pe care acestea le au la momentul respectiv;
valorile din registre sunt in hexa.
Fereastra C
descrie registrul FLAG.
Fereastra D
descrie segmentul de date;
imediat dupa incarcarea adresei segmentului de date in DS, pentru a vizualiza aceasta zona din memorie se
utilizeaza secventa de instructiuni Ctrl+G si apoi valoarea DS:0000 in casuta de dialog (atentie fereastra
activa trebuie sa fie D);
utilizata pentru verificarea rezultatelor;
pe coloana din dreapta sunt descrise adresele din segmentul de date (de ex. DS:0008)

Fereastra E

descrie segmentul de stiva;


valorile SS:0100 descriu adresele din segmentul de stiva;
simbolul (sageata) indica locatia curenta in stiva;

Forma Assembler a unui program .EXE (un singur segment de date, unul de cod si stiva)
Programarea in limbaj de asamblare este dificila deoarece sintaxa utilizata si modul in care este vazuta aplicatia
prin prisma codului sunt foarte apropriate de limbajul masina si de modul in care aplicatia va fi executata de
catre procesor. Compilatorul de Assembler, reprezentat in aceste tutoriale de Turbo Assembler si Turbo Linker
realizeaza operatii destul de simple in comparatie cu compilatorul de C (cl.exe in MS Visual Studio). In cazul unor
exemple simple, de genul celor prezentate in acest tutorial, cele 2 instrumente vor face, in principal, o
translatare a codului din limbaj de asamblare in limbaj masina binar. Din acest motiv, se acorda o atentie
deosebita structurii si a modului in care este scris programul.
Structura standard, chiar daca nu este strict obligatorie, a unui program assembler este
.model
.stack
.data

.code

end

Directivele din aceasta structura sunt descrise prin prisma exemplului 1.


Exemplu 1 program in limbaj de asamblare ce calculeaza valoarea expresiei e = a + b in care variabilele au
valori fixe:
; programul determina expresia e=a+b
;---------------------------------------------------------------------.model small
.286
.stack 100h
.data
a db 10
b db 35
e db ?
.code
mov AX,@data
mov DS,AX
mov AL,a
add AL,b
mov e,AL
mov AX,4c00h
int 21h
end

Descriere program:

.model small : Liniile care incep cu .reprezinta instructiuni speciale care indica programului assembler anumite
informatii, descrise de cuvintele cheie ce urmeaza, cu privire la programul de construit. in aceasta
situatie model indica faptul ca urmeaza a se indica modelul de memorie (si cantitatea de memorie) utilizat de
program. Acest program necesita un spatiu redus de memorie, fapt indicat prin small. Un model de memorie
specifica modul in care codul si datele sunt adresate, ori sunt in acelasi segment fizic ori in mai multe segmente.

Cnd toate datele (sau tot codul) se afla in acelasi segment atunci elementele sunt adresate prin adrese near date
de deplasarea lor (offset) fata de adresa de inceput a segmentului. Daca se utilizeaza mai multe segmente atunci
elementele sunt adresate prin adrese far date de adresa segmentului si offset. Tipuri standard de modele sunt:
SMALL, MEDIUM, COMPACT si LARGE.

Model de memorie
Tip adrese

SMALL MEDIUM COMPACT LARGE

Adrese COD

near

near

far

far

Adrese DATE

near

far

near

far

.stack : Alta linie care descrie programul. Instructiunea indica locul in care incepe segmentul de stiva. Acesta este
utilizat ca zona temporara de stocare a rezultatelor intermediare sau pentru a conserva starea sistemului (descrisa
de valorile din registre) inainte de a efectua operatii care sa altereze datele existente. De asemenea stiva este
utilizata si in transferul parametrilor catre si din proceduri. Indiferent daca este utilizata sau nu este obligatorie
definirea segmentului de stiva deoarece un program .EXE trebuie sa aiba o stiva. Optional se poate defini si
dimensiunea stivei ca numar de octeti. Daca nu se specifica dimensiunea se iau implicit 1024 de bytes.

.data : indica faptul ca incepe segmentul de date. Implicit, reprezinta terminarea segmentului de stiva. In
segmentul de date sunt definite variabilele cu care se lucreaza in program.

a db 10: se defineste o variabila de tip byte cu valoarea zecimala 10.


.code : indica inceperea segmentului de cod si implicit, terminarea segmentului de date. Acest segment contine
instructiunile programului.

mov AX, @data : Instructiunea incarca in registrul AX adresa segmentului de date. Alte simboluri predefinite
@code adresa segmentului de cod.

mov DS,AX : Instructiunea incarca in registrul segment DS adresa segmentului de date din registrul AX. Operatia
este necesara deoarece nu este permisa incarcarea registrului DS cu o valoare constanta (adresa).

mov AL,a: se pune in registrul AL valoarea lui a.


add AL,b: se aduna la valoarea din registrul AL, valoarea lui b.
mov e,AL: variabila e este initializata cu valoarea din registrul AL
mov AX, 4c00h : incarca in registrul AX valoarea hexazecimala 4c00h. Acest lucru este necesar apelarii ulterioare
a rutinei 21h.

int 21h : Apelul intreruperii 21h. In registrul AH se gaseste valoarea 4ch deoarece AX are valoarea 4c00h. Pentru
rutina DOS acest lucru semnifica iesire din program. Valoarea din AL, adica 00h, reprezinta codul de iesire din
program ce indica terminare executie fara eroare.

.end : marcheaza sfrsitul fisierului sursa. ATENTIE: Daca se specifica numele unei etichete definita anterior (de
obicei inainte de prima instructiune) atunci aceasta reprezinta adresa din CS la care porneste executia programului.
De exemplu programul
...
.code
mov AX,@data
mov DS,AX
Start:
mov AL,a
add AL,b
mov e,AL
...
end Start

ruleaza incepnd cu instructiunea mov AL,a.


Exemplu 2 afiseaza un mesaj la consola:
; programul afiseaza un mesaj
;---------------------------------------------------------------------.model small
.stack
.data
mesaj
db "Afisare mesaj !!!","$"

.code
main
proc
AX,seg mesaj
mov
DS,AX
mov
mov
lea
int

AH,09
DX,mesaj
21h

AX,4c00h
mov
21h
int
main
endp
end main

Descriere program:

main proc : codul poate fi structurat prin intermediul procedurilor. Pentru a face analogie cu programul C care
trebuie sa contina obligatoriu o procedura numita main, se defineste procedura si in programul assembler.
Instructiunea indica inceputul subprogramului numit main. Sfarsitul subprogramului este indicat de
instructiunea end main.
mesaj db
Afisare mesaj !!! : defineste o variabila sir de caractere numita message ce contine textul Afisare mesaj
!!!.
mov AX, seg mesaj : Instructiunea incarca in registrul AX adresa segmentului de date. Reprezinta o alternativa la
instructiunea mov AX, @data pentru ca instructiunea seg intoarce adresa segmentului in care se afla definita
variabila respectiva. Situatia este posibila pentru ca fiecare variabila este identificata printr-o adresa de
forma segment:offset. Fara a incarca registrul DS cu adresa segmentului activ de date nu se incarca corect
adresa variabilei mesaj.

mov AH, 09 : incarca in registrul AH valoarea constanta 09. Este necesar pentru a afisa un mesaj pe ecran
utiliznd intreruperea DOS 21h.

lea DX, message : Instructiunea LEA (Load Efective Address) incarca in registrul DX offset-ul din cadrul
segmentului de date la care se gaseste variabila mesaj . Acest lucru este necesar pentru a afisa mesajul pe ecran
utiliznd intreruperea 21h.

int 21h : Instructiunea genereaza o intrerupere DOS. Procesorul apeleaza rutina indicata de numarul intreruperii,
in acest caz o rutina DOS. Procedura verifica registrul AH pentru a vedea ce trebuie sa faca. In acest caz, valoarea
09 din AH indica faptul ca trebuie sa scrie pe ecran un sir de biti.

Instructiuni utilizate in cele 2 exemple:


Instructiunea MOV

realizeaza principalele operatii de transfer a valorilor;


este att de utilizata inct este imposibil sa scrii un program assembler fara aceasta instructiune;
forma analitica a instructiunii este:
MOV destinatie, sursa
si realizeaza copierea valorii de la sursa la destinatie fara a modifica sursa.

permite multiple combinatii de tipuri ale sursei si destinatiei (registru, valoare imediata, locatie de memorie)
insa exclude situatiile:

destinatia nu poate fi segmentul CS; cum segmentul CS contine intotdeauna adresa codului de executat
nu este indicat a se modifica aceasta valoarea in timpul prelucrarii.; singurul mod de a modifica CS este
prin intermediul instructiunilor int, jmp sau call;

destinatia si sursa nu pot fi in acelasi timp operanzi din memorie (variabile definite in segmentul de
date); aceasta restrictie se aplica tuturor instructiunilor procesoarelor 8086 care necesita doi operanzi;

.data

exemplu:
vb1 DW 300

vb2 DW ?
.
mov vb2,vb1
;EROARE

pentru a evita situatia se utilizeaza un registru asemenea unei zone temporare; de exemplu:
.data
vb1 DW 300
vb2 DW ?
.
mov AX, vb1
mov vb2,AX

daca sursa este o valoare imediata (constanta valorica), destinatia nu poate fi unul dintre registrele de
segment (CS, DS, ES, SS); pentru a evita situatia se utilizeaza un registru;

destinatia nu poate fi un operand imediat (constanta valorica); exemplu:

cea mai rapida combinatie este MOV registru, registru;

mov 5, AX

;EROARE

Instructiunea XCHG

interschimba valorile din sursa si destinatie;


forma analitica:
XCHG destinatie, sursa

nu afecteaza nici un Flag bit;


Instructiunile LDS si LES
sunt printre putinele instructiuni care prelucreaza un dublu cuvnt (32 de biti); transfera dublu-cuvntul
din memorie catre 2 registre de 16 biti; valoarea din cei doi octeti superiori ai dublu-cuvntului este
copiata intr-unul din registrele de segment (fie DS sau ES in functie de instructiune LDS sau LES); cuvntul
(16 biti) mai putin semnificativ este copiat intr-un registru general indicat ca operand destinatie in
instructiune; de obicei dublu-cuvntul este un pointer ce contine adresa unei variabile data de
segment:offset (adresa segmentului pe 16 biti si offestul in cadrul segmentului tot pe 16 biti);
incarca adresa in segment;
forma analitica:
LDS registru, sursa
LES registru, sursa
unde sursa este reprezentata de o variabila definita pe 32 de biti;

registrul FLAG este neafectat;


restrictie: registru nu poate fi unul din registrele de segment;
exemplu:

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


pointer_mesaj dd mesaj

lds DX,pointer_mesaj
offest-ul

; incarca in DS adresa segmentului in care se afla mesaj si in DX

sau daca DS este deja incarcat cu adresa segmentului atunci


les DX, mesaj

;incarca in ES adresa segmentului si in DX offset-ul

ultima instructiune poate fi inlocuita cu:


mov DX, OFFSET mesaj ;OFFSET returneaza offset-ul variabilei mesaj

Instructiunea ADD

aduna la operandul destinatie valoarea operandului sursa;


adunarea se realizeaza pe 16 biti;
forma analitica:

ADD destinatie, sursa

permite multiple combinatii de tipuri ale sursei si destinatiei (registru, valoare imediata, locatie de
memorie) insa exclude situatiile:

destinatia nu poate fi segmentul CS; cum segmentul CS contine intotdeauna adresa codului de
executat nu este indicat a se modifica aceasta valoarea in timpul prelucrarii.; singurul mod de a
modifica CS este prin intermediul instructiunilor int, jmp sau call;

destinatia si sursa nu pot fi in acelasi timp operanzi din memorie (variabile definite in segmentul de
date); aceasta restrictie se aplica tuturor instructiunilor procesoarelor 8086 care necesita doi
operanzi; exemplu:

.data
vb1 DW 300
vb2 DW ?
.
add vb2,vb1

;EROARE

pentru a evita situatia se utilizeaza un registru asemenea unei zone temporare; de exemplu:
.data
vb1 DW 300
vb2 DW ?
.
mov AX, vb1
add vb2,AX

daca sursa este o valoare imediata (constanta valorica), destinatia nu poate fi unul dintre registrele de
segment (CS, DS, ES, SS); pentru a evita situatia se utilizeaza un registru;

destinatia nu poate fi un operand imediat (constanta valorica); exemplu:

registru FLAG modificat: OF, CF, PF, SF, AF, ZF;

add 5, AX

;EROARE

Instructiunea SUB (SUBstract)

scade din operandul destinatie valoarea operandului sursa;


forma analitica:
SUB destinatie, sursa

restrictii identice ca la instructiunea ADD;


exemple:

.data
vb1 DW 300
vb2 DW 50
.
mov
mov
sub
sub
sub
sub

AX, vb1
CX, vb2
vb1, 50
AX, CX
AX, vb1
AX,10

Instructiunea NEG

utilizat pentru a nega operandul, scaznd-ul din valoarea 0;


forma analitica:

NEG operand
registru FLAG afectat: OF,SF, ZF, AF, PF, CF;
operandul trebuie sa fie registru sau variabila;
cnd operandul contine valoarea minima posibila aceasta nu este afectata;
Instructiunea MUL (MULtiply)
multiplica o valoare unsigned din AL (cnd operandul este de tip byte) sau din AX (cnd operandul este de
tip word) cu valoarea operandului specificat; rezultatul este returnat in AX cnd operandul este de tip byte
si in DX:AX (cei 2 octeti superiori in DX) cnd acesta este de tip word;
forma analitica:
MUL operand

registru FLAG modificat: OF si CF sunt setati daca partea superioara a rezultatului (DX daca operandul este
de tip word, sau AH este de tip byte) este diferita de 0;alte flag-uri SF, ZF, AF, PF;

operandul poate fi alt registru sau o variabila;


daca valoarea inmultita are semn atunci se utilizeaza IMUL;
Instructiunea DIV (DIVide)
imparte o valoare unsigned din AX (cnd operandul este de tip byte; in acest caz DX trebuie sa contina
valoarea 0) sau din DX:AX (cnd operandul este de tip word) cu valoarea operandului specificat; ctul este
returnat in AL iar restul in AH cnd operandul este de tip byte si in DX:AX (DX contine restul si AX ctul)
cnd acesta este de tip word;
forma analitica:
DIV operand
registru FLAG modificat: nedefiniti;
operandul poate fi alt registru sau o variabila;
in cazul operandului de tip word memorarea deimpartitului in DX:AX se face cu instructiunea cwd(convert
word to double) ce extinde valoarea din AX in zona DX:AX; exemplu:

vb1 dw 55
vb2 dw 15
cat dw ?
rest dw ?
...
mov AX,vb1
cwd
div vb2
mov cat,AX
mov rest,DX<span style="text-decoration: underline;"><span style="text-decoration: underline;">
</span></span>

Instructiunea ROR (ROtate Right)

utilizata pentru a roti la dreapta bitii destinatiei de attea ori ct este specificat; cum fiecare bit este rotit la
dreapta, cel mai putin semnificativ bit al destinatiei este copiat in locul celui mai semnificativ bit si in CF
(carry flag);

forma analitica:

destinatia poate fi registru sau variabila; contorul poate fi constanta sau registrul CL; exemple:

registru FLAG: OF este setat doar daca contorul are valoarea 1 si bitul cel mai semnificativ al destinatiei este

ROR destinatie, contor


vb dw 1234h

mov CL, 4
ror AX, CL
ror AX,4
ror vb, CL
ror vb, 4

diferit de bitul vecin; pentru alte valori nu exista regula de modificare a lui OF; se modifica si CF;
Instructiunea ROL (ROtate Left)

utilizata pentru a roti la stnga bitii destinatiei de attea ori ct este specificat; cum fiecare bit este rotit la
stnga, cel mai semnificativ bit al destinatiei este copiat in locul celui mai putin semnificativ bit si in CF
(carry flag);

analogie cu ROR;

Instructiunea SAL sau SHL (Shift Arithmetic Left si SHift Left)

se utilizeaza pentru a muta la stnga bitii din destinatie cu attea pozitii cte sunt specificate in contor; cu
fiecare pozitie se adauga la stnga in bitul cel mai putin semnificativ valoarea 0;

forma analitica:
SAL destinatie, contor

registrul FLAG: SF, ZF si PF; cel mai semnificativ bit al destinatiei este mutat in CF; OF este setat daca
contorul are valoarea 1 iar bitul de semn isi pastreaza valoarea;

utilizat pentru a inmulti destinatia o putere a lui 2;


destinatia poate fi registru sau variabila; contorul poate fi constanta sau registrul CL;
Instructiunea SAR (Shift Arithmetic Right)

se utilizeaza pentru a muta la dreapta bitii din destinatie cu attea pozitii cte sunt specificate in contor; cu
fiecare pozitie se adauga la dreapta in vecinul bitului cel mai semnificativ valoarea 0; bitul cel semnificativ
(bitul de semn) isi pastreaza valoarea;

forma analitica:
SAR destinatie, contor

registrul FLAG: SF, ZF si PF; cel mai putin semnificativ bit al destinatiei este mutat in CF; OF este setat daca

contorul are valoarea 1 iar bitul de semn si vecinul sau sunt diferiti;
utilizat pentru a imparti un numar negativ (destinatia) la o putere a lui 2;
destinatia poate fi registru sau variabila; contorul poate fi constanta sau registrul CL;
Instructiunea SHR (Shift Rigth)
se utilizeaza pentru a muta la dreapta bitii din destinatie cu attea pozitii cte sunt specificate in contor; cu
fiecare pozitie se adauga in vecinul bitului cel mai semnificativ valoarea 0;
forma analitica:
SHR destinatie, contor
registrul FLAG: SF, ZF si PF; cel mai putin semnificativ bit al destinatiei este mutat in CF; OF este setat daca
contorul are valoarea 1 iar bitul de semn si vecinul sau sunt diferiti;
utilizat pentru a imparti un numar pozitiv (destinatia) la o putere a lui 2;
destinatia poate fi registru sau variabila; contorul poate fi constanta sau registrul CL;

Limbaj de Asamblare (Assembler) Intel 8086 Partea 3 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
o
o

Adresare indexata
Adresare bazata
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)

mov AX, vector


mov BX, vector[3]

; definire vector cu 10 elemente initializate cu valoarea 5


;copiaza valoarea primului element de tip cuvant din vector in AX
;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]

mov BX,DS:[08h]

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


;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


mov AX, [SI]
mov CX, [SI+2]
mov DX,[SI+3]
din 1235h)

;incarca in SI offset-ul de inceput al vectorului

;copiaza in AX valoarea primului element, adica 1234h


;copiaza in CX valoarea elementului al doilea, adica 1235h
;copiaza in DX valoarea 2212h (octetul inferior din 3222h si octetul superior

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]
mov AL,vector[SI][2]
valoarea 1

;copiaza in CL valoarea celui de al treilea element


;copiaza in AL valoarea celui de al patrulea element deoarece SI contine

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]
mov AX,vector[SI][4]
valoarea 2

;copiaza in CX valoarea celui de al treilea element


;copiaza in AX valoarea celui de al patrulea element deoarece SI contine

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


mov AL, [BX][SI]

;incarcam in registrul de baza offset-ul de start al vectorului

;copiaza in AL valoarea primului element din vector

inc SI
add AL, [BX+SI]
add AL, [BX+SI+1]
add AL,[BX][SI][2]
valoarea 1

;aduna in AL valoarea elementului secund din vector


;aduna in AL valoarea celui de al treilea element
;aduna in AL valoarea celui de al patrulea element deoarece SI contine

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
suma db 0

;dimensiunea vectorului
;suma elementelor

.code
mov AX,@data
mov DS,AX
xor SI,SI
xor CX,CX
mov CL,n
repeat:

;ne asiguram ca CX are valoarea 0


;copiem in CL dimensiunea vectorului
;definim eticheta

mov AL,vector[SI]
add suma,AL
inc SI
;elementul urmator
loop repeat

;marim valoarea din SI cu 1 pentru a trece la


;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
int 21h
sub al,30h
mov nr,al

;initializare AH cu codul functiei


;apel rutina
;transformare cod ASCII aferent cifrei in valoare intreaga
;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
int 21h

;initializare AH cu codul functiei


;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
mov ah,0ah
int 21h
mov AX,4c00h
int 21h
end

;incarc in DX offset-ul la care incepe scrierea sirului de caractere

Limbaj de Asamblare (Assembler) Intel 8086 Partea 4 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 Tutorial Limbaj de
Asamblare (Assembler) Intel 8086 Partea 1 Elemente de baza.
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

salturi neconditionate: JMP;

CMPSB
CMPSW.

Tipuri de salturi in limbaj de asamblare


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).

Tip jump

Forma interna

Jump intersegment

5 octeti: 1 pentru codul operatiei (EAh), 2 pentru offset i 2 pentru adresa segment.

Jump intrasegment

3 octeti: 1 pentru codul operatiei (E9h), 2 pentru offset.

Jump-uri scurte
(short jumps)

2 octeti: 1 pentru codul operatiei (EBh), 1 pentru a reprezenta o valoare cu semn aferenta
offset-ului. In acest caz, destinatia trebuie sa fie intre +127 i -128 de octeti fata de
instructiunea de salt.

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.

Operatie

Instructiune de salt conditionat daca ambii


operanzi sunt considerati fara semn

Instructiune de salt conditionat daca


unul dintre operanzi este cu semn

<> or !=

JNE sau JNZ

JNE sau JNZ

= or ==

JE sau JZ

JE sau JZ

>=

JNB

JNL

>

JNBE sau JA

JNLE or JG

<=

JNA

JNG

<

JNAE sau JB

JNGE sau JL

Exemplu program assembler in care este evidentiata diferenta dintre Valori cu semn vs. Valori fara semn
.data
total dw 0FFFFh
.code

; sari daca total < 10 (cu semn)

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

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


;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


Limbaj evoluat

In Assembler (tot in pseudo-cod!):

if (op1 = op2) then cmp op1, op2

<expresie1>
<expresie 2>
end if

jne fals
< expresie 1>

< expresie 2>


fals:
<restul programului>
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


Limbaj evoluat

In Assembler (tot in pseudo-cod!):


cmp op1, op2

jle else
<statement1>
if (temp > max) then <statement2>

max = temp
else
max = max + 1
endif

jmp done
else:
<statement3>
<statement4>
done:

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


Limbaj evoluat In Assembler (tot in pseudo-cod!):
mov cx,n
i=n;

do
{
<statement1>
<statement2>
i=i-1;
} while (i>=0)

repeat:
<statement1>
<statement2>
loop repeat

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
suma db 0

;dimensiunea vectorului
;suma elementelor

.code
mov AX,@data
mov DS,AX
xor SI,SI
xor CX,CX
mov CL,n
repeat:

;ne asiguram ca CX are valoarea 0


;copiem in CL dimensiunea vectorului
;definim eticheta

mov AL,vector[SI]
add suma,AL
inc SI
loop repeat

;marim valoarea din SI cu 1 pentru a trece la elementul urmator


;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


Limbaj evoluat In Assembler (tot in pseudo-cod!):
i=n;

while (i>=0) do

mov cx,n

{
<statement1>
<statement2>
i=i-1;
}

repeat:
cmp op1,op2 ;verificare conditie
jle exit ;conditie iesire
<statement1>
<statement2>
loop repeat
exit:

Expresia de tip CASE implementata in limbaj de asamblare


Limbaj evoluat In Assembler (tot in pseudo-cod!):
cmp value,constant1

je case1
cmp value,constant2
je case2

switch (value) {

jmp default

case constant1:
<statement1>
break;
case constant2:
<statement2>
break;

default:
<statements>

case1:
<statement1>
jmp final
case2:
<statement2>
Jmp final

default:
<statements>
final:

Tutorial Limbaj de Asamblare (Assembler) Intel 8086 Partea 5 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:

Nume_procedura PROC [FAR | NEAR]


Salvare registre
Bloc prelucrare date cu referirea parametrilor formalii
Stocare rezultate
Restaurarea registreor
RET [nr_octeti]
[Nume_procedura] ENDP

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:

Tip operand

Descriere

CALL
nume_procedura

Numele procedurii apelate reprezinta in esenta o eticheta.

CALL eticheta

Procesorul presupune in aceasta situati ca eticheta este locala si atunci face un salt de
tip NEAR. Aceasta trebuie sa fie la o distanta cuprinsa in intervalul [-32768,32676] de
bytes. A se vedea exemplul de mai jos.

CALL FAR PTR


eticheta

Eticheta este in alt segment. Inlocuieste CS si IP cu segmentul si offsetul etichetei.

CALL registru sau


variabila

Continutul din registru sau variabila este copiat in IP dupa ce acesta a fost salvat pe
stiva. Deci variabilasau registrul respectiv reprezinta de fapt un pointer near (tine doar
offsetul unei proceduri sau etichete)

CALL WORD PTR


variabila

Continutul variabilei reprezinta un offset si are loc un salt de tip NEAR. De obicei
variabila este reprezentata de o adresare indirecta cu registru index (SI,DI), [SI] sau
registru de baza (BX). [BX] si atunci trebuie specificat cati bytes trebuie cititi (trebuie
indicat procesorului tipul de salt near, se citesc 2 octeti; far se citesc 4 octeti). De
vazut exemplul cu apeluri indirecte de proceduri.

CALL DWORD PTR


adresa

Continutul variabilei reprezinta un segment + offset si are loc un salt de tip FAR. De
obicei variabila este reprezentata de o adresare indirecta cu registru index (SI,DI), [SI]
sau registru de baza (BX). [BX]. De vazut exemplul cu apeluri indirecte de proceduri.

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

Imaginea stivei dupa CALL si la pozitionarea pe prima instructiune din corpul procedurii
SP

adresa( IP ) de intors

Stiva creste pe directia


! Adresele scad

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

Imaginea stivei dupa CALL si la pozitionarea pe prima instructiune din corpul procedurii
SP adresa offset ( IP ) de intors
SP +2 Adresa segment (CS) de intors

Stiva creste pe directia


! Adresele scad

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 returneste 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
mov s, CX

;apel explicit de procedura NEAR

;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

Imaginea stivei la momentul adunarii celor doua valori de pe stiva


Pozitie in stiva relativa fata de
BP
BP-2
BP

SP
SP

valoare din AX

SP + 2

valoare din BP
Stiva creste pe directia

BP+2

SP + 4 adresa offset ( IP ) de intors

BP+4

SP + 6

valoare b

BP+6

SP + 8

valoare a

! Adresele scad

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
1234677
dd
b
3456123
dd
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
100h
dw
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

Imaginea stivei la momentul copierii in sum a rezultatului adunarii cuvintelor inferioare din a si b
Pozitie in stiva relativa fata de
BP

SP

BP-4

SP

valoare din SI

BP-2

SP + 2

valoare din AX

BP

SP + 4

valoare din BP

BP+2

SP + 6

adresa offset ( IP ) de intors


Stiva creste pe directia

BP+4

SP + 8

adresa segment (CS) de intors

BP+6

SP + 10

offset sum

BP+8

SP + 12

offset b

BP+10

SP + 14

offset a

! Adresele scad

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
pointer_functie_far
a dw 5
b dw 3
s dw ?
dif dw ?
.code

dw ?
DD ?

;pointer la functie de tip NEAR


;pointer la functie de tip FAR

mov AX,@data
mov DS,AX
mov AX, offset suma
mov pointer_functie,AX

;incarc in AX offset proecdura


;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
; 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
sub AX,BX
mov CX,AX
ret
ENDP
end

FAR

;declar explicit procedura de tip FAR

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
s2 student
mes_eroare
mes_corect

<'Popescu',22,1234>
<'Ionescu',21,1235>
db 'Depasire limite!','$'
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
mov AH,lim_sup
cmp AL,s1.varsta
ja eroare
cmp AH,s1.varsta
jb eroare
mov
lea
int
jmp

;copiez in AL valoarea limitei inferioare


;copiez in AH valoarea limitei superioare
;compar varsta cu limita inferioara
;daca varsta e mai mica, afisez mesaj
;compar varsta cu limita superioara
;daca varsta e mai mare,afisez mesaj

AH,09h
;afisez mesaj date corecte
DX,mes_corect
21h
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
dw 100 dup (?)
varf label word
Stiva ENDS

;segmentul aferent stivei


;rezerv 100 de cuvinte pentru stiva
;definesc o eticheta pentru a extrage adresa bazei stivei

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
lea
int
jmp

AH,09h
;afisez mesaj date corecte
DX,mes_corect
21h
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:
mov
mov
mov
mov
mov
mov

AX,Date
DS,AX
AX,Stiva
SS,AX
AX,varf
SP,AX

call validare

;indic de unde incep instructiunile programului


;incarc in DS adresa segmentului de date
;incarc in SS adresa segmentului de stiva
;initializez SP cu offsetul curent in stiva
;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
ja eroare
cmp AH,CL
jb eroare
mov
lea
int
jmp

;compar varsta
;daca varsta e
;compar varsta
;daca varsta e

cu limita inferioara
mai mica, afisez mesaj
cu limita superioara
mai mare,afisez mesaj

AH,09h
;afisez mesaj date corecte
DX,mes_corect
21h
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
mov
xor
mov

AL,lim_inf
AH,lim_sup
CX,CX
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
ja eroare
cmp AH,CL
jb eroare
mov
lea
int
jmp

;compar varsta
;daca varsta e
;compar varsta
;daca varsta e

cu limita inferioara
mai mica, afisez mesaj
cu limita superioara
mai mare,afisez mesaj

AH,09h
;afisez mesaj date corecte
DX,mes_corect
21h
final

eroare:
mov AH,09h
;afisez mesaj eroare
lea DX,mes_eroare
int 21h
final:
pop
pop
mov
pop
ret

CX
AX
SP,BP
BP
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:

Imaginea stivei la momentul incarcarii de pe stiva a valorilor parametrilor de intrare


Pozitie in stiva relativa
fata de
BP

SP

BP-4

SP

valoare din CX

BP-2

SP + 2

valoare din AX

BP

SP + 4

valoare din BP

SP + 6

BP+2

adresa offset ( IP ) de intors

Stiva creste
directia

pe

! Adresele scad
BP+4

SP + 8

valoarea varsta student; doar primul octet.

BP+6

SP + 10

limite interval; sunt scrise pe un cuvant in


forma:[[lim_sup][lim_inf]]

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
mov
mov
mov
mov
cmp

SI,[BP+8]
AL,[SI]
SI,[BP+6]
AH,[SI]
SI,[BP+4]
AL,[SI].varsta

;compar varsta cu limita inferioara

ja eroare
cmp AH,[SI].varsta
jb eroare
mov
lea
int
jmp

;daca varsta e mai mica, afisez mesaj


;compar varsta cu limita superioara
;daca varsta e mai mare,afisez mesaj

AH,09h
;afisez mesaj date corecte
DX,mes_corect
21h
final

eroare:
mov AH,09h
;afisez mesaj eroare
lea DX,mes_eroare
int 21h
final:
pop DI
pop SI
pop CX
pop
mov
pop
ret

AX
SP,BP
BP
6

ENDP
start:

;termin procedura si golesc stiva


;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

Imaginea stivei la momentul incarcarii de pe stiva a valorilor parametrilor de intrare


Pozitie in stiva relativa fata de
BP

SP

BP-8

SP

valoarea din DI

BP-6

SP + 2

valoarea din SI

BP-4

SP + 4

valoare din CX

BP-2

SP + 6

valoare din AX

BP

SP + 8

valoare din BP

Stiva creste pe directia


! Adresele scad

BP+2

SP + 10

adresa offset ( IP ) de intors

BP+4

SP + 12

adresa offset student

BP+6

SP + 14

adresa offset a lim_sup

BP+8

SP + 16

Adresa offset a lim_inf

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).

Tutorial Limbaj de Asamblare (Assembler) Intel 8086 Partea 6 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:

Valoare Denumire

Descriere

stdin

Intrare standard

stdout

Iesire standard

stderr

Iesire standard pentru mesaje de eroare

stdaux

Dispozitiv auxiliar

stdprn

Imprimanta standard

Principalele functii DOS pentru lucrul cu fisiere sunt:

Cod functie (se pune in AH)

Operatie

3Ch

Creare fisier

3Dh

Deschidere fisier

3Eh

Inchidere fisier

3Fh

Citire din fisier

40h

Scriere in fisier

41h

Stergere in fisier

42h

Pozitionare in fisier

56h

Redenumire fisier

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

dw

atribut

;handler la fisier
?

dw

tipDeschid

;atribut creare fisier

dw

;modul de deschidere a

rez

db

numeFis

db

'fisier.dat',0

fisierului

;variabila verificare reusita operatie

NrOctetideScris

dw

NrOctetiScrisi

dw

;nume fisier

;numarul de octeti de scris in fisier


?

;numarul de octeti scrisi efectiv in fisier

CREARE FISIER
Parametrii intrare:

Registru corespondent

- cod functie

3Ch AH

- nume fisier

DX

- atribut fisier

CX

Parametrii returnati:
- handler
- rezultat operatie
La momentul crearii, tipul fisierul poate fi:

read-only (1)
hidden (2)
system (4)
normal (0)

Creare MACRO numeFis, atribut, handler, rez


local eroare, final
push AX
push CX
push DX
mov AH,3Ch

;incarc codul functiei

AX
in functie de carry flag

mov CX,atribut

;pun atributul fisierului

lea DX,numeFis

;incarca in DX adresa sirului de caractere asociat numelui

INT 21h

;apelez intreruperea 21h

jc eroare

;daca operatia nu a avut loc cu succes CF este setat

;verific reusita operatiei


mov handler,AX

;daca fisierul a fost creat initializez handler-ul

mov rez,0

;initializez variabila rez cu 0

jmp final

;salt la sfarsit macro

eroare:

;in caz de eroare

mov handler,-1

;initializez handler-ul cu o valoare negativa

mov rez,AX

;retin in rez codul erorii (este diferit de 0)

final:
pop DX
pop CX
pop AX
ENDM

INCHIDERE FISIER
Parametrii intrare: Registru corespondent
- cod functie
- handler

3Eh AH
BX

Parametrii returnati:
- rezultat operatie

in functie de carry flag

Inchidere MACRO handler, rez


local eroare, final
push AX
push BX
mov AH,3Eh

;incarc codul functiei

mov BX,handler

;incarc handler-ul fisierului

INT 21h
jc eroare

;daca operatia nu a avut loc cu succes CF este setat

;verific reusita operatiei


mov rez,0
jmp final
eroare:
mov rez,AX
final:

;retin in rez codul erorii (este diferit de 0)

pop BX
pop AX
ENDM

DECHIDERE FISIER
Parametrii intrare: Registru corespondent
- cod functie

3Dh AH

- nume fisier

DX

- tip acces

AL

Parametrii returnati:
- handler
- rezultat operatie

AX
in functie de carry flag

Fisierul poate deschis pentru:

citire (0)
scriere (1)
citire/scriere (2)

Deschidere MACRO numeFis, tipDeschid, handler, rez


local eroare, final
push AX
push DX
mov AH,3Dh

;incarc codul functiei

mov AL, tipDeschid


lea DX,numeFis
INT 21h
jc eroare

;indic tipul deschiderii fisierului

;incarca in DX adresa sirului de caractere asociat numelui


;apelez intreruperea 21h
;daca operatia nu a avut loc cu succes CF este setat

;verific reusita operatiei


mov handler,AX

;daca fisierul a fost deschis initializez handler-ul

mov rez,0

;initializez variabila rez cu 0

jmp final

;salt la sfarsit macro

eroare:

;in caz de eroare

mov handler,-1

;initializez handler-ul cu o valoare negativa

mov rez,AX

;retin in rez codul erorii (este diferit de 0)

final:
pop DX
pop AX
ENDM

SCRIERE in FISIER
Parametrii intrare:

Registru corespondent

- cod functie

40h AH

- handler fisier

BX

- buffer din care se citesc datele pentru a fi scrise in fisier

DX

- numar octeti de scris in fisier

CX

Parametrii returnati:
- numar octeti scrisi efectiv in fisier
- rezultat operatie

AX
in functie de carry flag

Scrie MACRO handler, buffer, NrOctetideScris, NrOctetiScrisi,rez


local eroare, final
push AX
push BX
push CX
push DX
mov AH,40h

;incarc codul functiei

mov BX,handler

;incarc handler-ul fisierului existent

mov CX, NrOctetideScris


lea DX,buffer
INT 21h
jc eroare

;indic numarul de octeti de scris in fisier

;incarca in DX adresa zonei de unde iau datele de scris


;apelez intreruperea 21h
;daca operatia nu a avut loc cu succes CF este setat

;verific reusita operatiei


mov NrOctetiScrisi,AX

;retin numarul de octeti efectiv scrisi

mov rez,0

;initializez variabila rez cu 0

jmp final

;salt la sfarsit macro

eroare:
mov rez,AX

;in caz de eroare


;retin in rez codul erorii (este diferit de 0)

final:
pop DX
pop CX
pop BX
pop AX
ENDM

Atentie Buffer-ul poate fi un element de tip articol, masiv sau variabila. De exemplu, pentru a scrie intr-un fisier
primele 3 elemente ale unui vector vector db 1,2,3,4,5b se scrie instructiunea:
Scrie handler,vector,3,NrOctetiScrisi,rez

CITIRE din FISIER


Parametrii intrare:
- cod functie

Registru corespondent
3Fh AH

- handler fisier

BX

- buffer in care se scriu datele citite din fisier

DX

- numar octeti de citit din fisier

CX

Parametrii returnati:
- numar octeti cititi efectiv din fisier
- rezultat operatie

AX
in functie de carry flag

Citeste MACRO handler, buffer, NrOctetideCitit, NrOctetiCititi,rez


local eroare, final
push AX
push BX
push CX
push DX
mov AH,3Fh

<strong>;incarc codul functiei</strong>

mov BX,handler

<strong>;incarc handler-ul fisierului existent</strong>

mov CX, NrOctetideScris


</strong>
lea DX,buffer
INT 21h
jc eroare

<strong>;indic numarul de octeti de citit din fisier

<strong>;incarca in DX adresa zonei unde pun datele citite</strong>


<strong>;apelez intreruperea 21h</strong>
<strong>;daca operatia nu a avut loc cu succes CF este setat</strong>

<strong>;verific reusita operatiei


</strong>
mov NrOctetiCititi,AX

<strong>;retin numarul de octeti efectiv cititi</strong>

mov rez,0

<strong>;initializez variabila rez cu 0</strong>

jmp final

<strong>;salt la sfarsit macro</strong>

eroare:
mov rez,AX
final:
pop DX
pop CX
pop BX
pop AX
ENDM

<strong>;in caz de eroare</strong>


<strong>;retin in rez codul erorii (este diferit de 0)</strong>

Pozitionare in fisier
Parametrii intrare:

Registru corespondent

- cod functie

42h AH

- handler fisier

BX

- punct de referinta

AL

- numar octeti fata de punctul de referinta ai saltului (e un double)

cuv. inferior DX
cuv. superior CX

Parametrii returnati:
- noua pozitie in fisier (un double)
- rezultat operatie

cuv. inferior AX
cuv. superior DX
in functie de carry flag

Punctul de referinta poate fi:

0, inceputul fisierului;
1, pozitia curenta in fisier;
2, sfarsitul fisierului.

Pozitionare MACRO handler, pozitie, referinta, pozitieNoua, rez


local eroare, final
push AX
push BX
push CX
push DX
mov AH,42h
mov AL,referinta
mov BX,handler

;incarc codul functiei


;indic referinta fata de care fac saltul
;incarc handler-ul fisierului existent

mov DX,word ptr pozitie[0]

;numar octeti salt

mov CX,word ptr pozitie[2]


<p style="margin-left: 108pt;">; expresie similara este si</p>
<p style="margin-left: 108pt;">; mov DX,WORD PTR pozitie</p>
<p style="margin-left: 108pt;">; mov CX,WORD PTR pozitie +2</p>
INT 21h
jc eroare

;daca operatia nu a avut loc cu succes CF este setat

;verific reusita operatiei


mov word ptr pozitieNoua[0],AX

;noua pozitie

mov word ptr pozitieNoua[2],DX


mov rez,0
jmp final
eroare:
mov rez,AX
final:

;salt la sfarsit macro


;in caz de eroare
;retin in rez codul erorii (este diferit de 0)

pop DX
pop CX
pop BX
pop AX
ENDM

Presupunand ca toate aceste macrodefinitii sunt definite in fisierul MacroFis.inc se scrie programul care
construieste un fisier si il foloseste pentru a memora elementele unui vector de elemente si de structuri. Ulterior,
se construiesc alti doi vectori in care se pun elementele aflate in fisier.
Atentie Fisierul MacroFis.inc contine doar codul fiecarei macrodefinitii in parte fara nici o alta declaratie in plus.
Acest

fisier

nu

necesita

asamblare

sau

link-editare.

Instructiunea include

MacroFis.inc din programul principal (dat mai jos) copiaza codul din fisierul indicat si il insereaza pe pozitia
instructiunii.
Atentie Pentru a determina dimensiunea unui vector se va utiliza simbolul $ asociat offset-ului curent in
segmentul de date.
Pentru un masiv de tip tip_vect (orice tip de baza sau structura) pentru lungime ca numar de elemente se
utilizeaza expresia:
vector tip_vector elem1, elem2, elem3, .., elemn
tip equ TYPE vector
nrElem equ ($ vector)/tip
In cazul masivelor definite cu dup se poate utiliza LENGTH pentru a obtine numarul de elemente.
.model small
.286
.stack 100h
.data

student STRUC
;articol de tip student
nume db 15 dup (?)
varsta db ?
nrMatricol dw ?
ENDS
dimStudent equ SIZE student
;articol de tip student

;dimensiune in octeti a unui

vector db 1,2,3,4,5
;vector de elemente
lvector equ $-vector
;lungime vector ca numar de octeti
;cum elementele vectorului sunt de tip octet atunci lvector
;da si numarul de elemente
vector2 db 5 dup(?)
;al doilea vactor
vectorStudenti

student <'Popescu',23,1234>,<'Ionescu',22,1235>,<'Gheorghe',22,1236>
;vector de articole
dimVectStud equ $-vectorStudenti ;dimensiune in octeti
nrStudenti equ dimVectStud/dimStudent
;numar elemente
vectorStudenti2 student nrStudenti dup(?) ;al doilea vector
handler
atribut
tipDeschid
rez
NrOctetideScris
NrOctetiScrisi
NrOctetiCititi

dw
dw
dw
dw
dw
dw
dw

?
?
?
?
?
?
?

;handler la fisier
;atribut creare fisier
;modul de deschidere a fisierului
;variabila verificare reusita operatie
;numar de octeti de scris in fisier
;numar de octeti scrisi in fisier
;numar de octeti de cititi din

dd

;dimensiunea saltului la

dd

;fisier
Pozitie
;pozitionare
PozitieNoua
numeFis db
mesajEroare db

;noua pozitie in fisier

'fisier.dat',0
;nume fisier
'Eroare executie functie!','$';mesaj eroare

.code
include MacroF.inc ;includ fisierul ce contine macrodefinitiile
start:
mov AX,@data
mov DS,AX
Creare numeFis,0,handler,rez
;creez fisierul
cmp rez,0
;verific executia operatiei
je continuare1
AfiseazaMesaj mesajEroare ;afisez mesaj eroare
continuare1:
Inchidere handler,rez
;inchid fisierul
cmp rez,0
;verific executia operatiei
je continuare2
AfiseazaMesaj mesajEroare ;afisez mesaj eroare
continuare2:
Deschidere numeFis,2,handler,rez ;deschid fisierul
cmp rez,0
;verific executia operatiei
je continuare3
AfiseazaMesaj mesajEroare ;afisez mesaj eroare
continuare3:
Scrie handler,vector,lvector,NrOctetiScrisi,rez
;scriu in fisier primul vector
Scrie handler,vectorStudenti,dimvectstud,NrOctetiScrisi,rez
;scriu in fisier primul vector de articole
mov word ptr pozitie,0
;indic pozitia saltului
mov word ptr pozitie[2],0 ;pun zero pt. a ma pozitiona la 0
;octeti fata de inceputul fisierului
POzitionare handler,pozitie,0,PozitieNoua,rez
;ma pozitionez pe inceputul fisierului
Citeste handler,vector2,lvector,NrOctetiCititi,rez
;citesc in al doilea vector elementele din
;fisier: 1,2,3,4,5
Citeste handler,vectorStudenti2,dimVectStud,NrOctetiCititi,rez
;citesc in al doilea vector de articole
;elementele din fisier
Inchidere handler,rez
;inchid fisierul
mov AX,4c00h
int 21h
end start
Codul macrodefinitiei AfiseazaMesaj este (este inclus tot in MacroF.inc) :
AfiseazaMesaj MACRO mesaj
push AX
push DX
mov Ah,09h
lea DX,mesaj
int 21h
pop DX
pop AX
ENDM

Atentie Salturile conditionate nu pot referi etichete aflate la mai mult de 128 octeti. Solutia consta in evitarea
acestor situatii prin rescrierea codului si a conditiei de verificat astfel incat sa avem salturi mai mici. In exemplul
anterior, verificarea realizarii corecte a unei macrodefinitii se realiza prin:
apel de macrodefinitie
cmp rez,0
jne afiseaza_eroare
apel macrodefinitie urmatoare

jmp exit
afiseaza_eroare:
AfiseazaMesaj mesajEroare
exit:
mov AX,4c00h
int 21h

insa eticheta afiseaza_eroare se afla la o distanta mai mare de 128 de octeti. Din acest motiv s-au folosit
etichetele continuarei cu i = 1,2.. iar verificarea a devenit:
apel de macrodefinitie
cmp rez,0
je continuarei
AfiseazaMesaj mesajEroare
continuarei
apel macrodefinitie urmatoare

Extindere jump-uri de tip short


Se presupune secventa de cod
efectuare comparatie
je salt
...
salt:

care este corecta in cazul in care eticheta salt se gaseste la mai putin de 128 de octeti. In caz contrar saltul,
extinderea salturilor conditionate se realizeaza prin abordarea secventei de cod astfel:

utilizarea unui salt neconditionat (acesta poate face salturi mai mari de 128 de octeti):
efectuare comparatie
jne continuare
jmp salt

continuare:
...
salt:

salt:

repetarea codului de la instructiunea salt pentru fiecare comparatie:


efectuare comparatie
jne continuare

salt:
...
continuare:
...

utilizarea unui salt neconditionat fara a utiliza etichete suplimentare


efectuare comparatie
jne $+2+ dimensiune in octeti a instructiunii urmatoare
jmp salt
...

salt:

Instructiunea jne $+2+ dimensiune in octeti a instructiunii urmatoare adauga la offset-ul curent din segmentul
de cod (retinut in IP si indicat cu $) 2 octeti reprezentand dimensiunea acestei instructiunii si dimensiunea in octeti
a instructiunii urmatoare. Cum in aceasta abordare instructiunea urmatoare este jmp salt trebuie indicata
dimensiunea ei (vezi documentatie Structuri de control 3 octeti pentru jump near si 5 octeti pentru jump far).
Deci, in acest caz instructiunea se mai poate scrie jne $ + 5. Pentru a afla dimensiunea altor instructiuni se
utilizeaza TurboDebugger-ul si se fac diferente de offset-uri ale instructiunilor respective. Pentru a fi sigur de
tipul jump-ului se indica tipul acestuia explicit cu jmp NEAR PTR salt aceasta instructiune avand 3 octeti.

Tutorial Limbaj de Asamblare (Assembler) Intel 8086 Partea 7 Lucru cu


segmente
In acest tutorial destinat imbajului de asamblare pentru procesoare din familia Intel 8086 sunt prezentate
modalitatile de lucru cu segmente. Aceasta abordare permite realizarea de aplicatii compexe in care datele si
codul nu sunt limitate doar la un singur segment.

Arhitectura de segmente
Familia de procesoare 8086 implementeaza o arhitectura de segmente prin faptul ca fiecare adresa fizica este
reprezentata prin perechea adresa segment:offset.

Generatia de procesoare 8086/286 pe 16 biti permit lucru cu segmente mai mici de 64K (cea mai mare adresa
posibila din cadrul unui segment offset este 216).
Procesoarele 90386/486 utilizeaza arhitectura pe 16 biti (segmente de maxim 64K) cand prelucreaza date in
mod real, insa in mod protejat utilizeaza registre pe 32 de biti ce pot retine adrese de pana la 4 Gbytes.
Un segment fizic poate incepe numai de la o adresa divizibila cu 16, aceste locatii fiind numite (Intel) paragrafe.
Modul in care sunt definite datele si codul nu are importanta la programele mici pentru ca acestea ocupa mai putin
de 64Kbytes fiind grupate in segmente individuale si sunt accesate prin intermediul offset-ului relativ la adresa
de inceput a segmentului respectiv. Problema se complica in cazul programelor mari in care codul sau datele ocupa
mai mult de 64K si atunci sunt segmentate. In aceasta situatie, programatorul trebuie sa se asigure ca fiecare data
sau secventa de cod referita poate fi accesata prin segment:adresa.
Problema segmentarii datelor sau codului este mai putin acuta in cazul procesoarelor pe 32 de biti pentru ca
segmentele sunt destul de mari (4 Gbytes) astfel incat si cele mai complexe aplicatii sa se comporte asemenea
programelor mici, compacte.

Segmentele logice
Segmentele reprezinta seturi de date sau instructiuni ce sunt disponibile prin intermediul offset-ului relativ de
adresa de inceput a segmentului.
Adresele fizice ale segmentelor sunt cunoscute prin intermediul registrelor de segment:

Registru

Descriere

DS

- segmentul de date

CS

- segmentul de cod

SS

- segmentul de stiva

ES

- segmentul extins

, insa trebuie avut in vedere faptul ca, in cazul in care exista mai multe segmente definite de programator, numai
unul dintre ele, la un moment dat, poate fi asociat cu segmentele logice de date, de cod, de stiva sau extins.
La incarcarea in memorie a programului, sistemul initializeaza registrul de segment CS cu prima adresa se segment
disponibila instructiune, iar registrul IP cu adresa relativa din cadrul segmentului, a primei instructiuni ce trebuie
executata. Segmentele logice se incarca in memorie in ordinea cod, date, stiva.

Definirea segmentelor
Segmentele logice contin cele tei componente ale unui program: cod, date si stiva. Modul in care pot fi
specificate segmentele sunt:

definire simplificata;
definire completa a segmentelor.
Definirea simplificata ascunde multe detalii ale definirii segmentelor si utilizeaza aceleasi conventii implementate
de Microsoft in limbajele de nivel inalt.

Structura unui program ale carui segmente sunt descrise utilizand definirea simplificata este: (descrisa si in prima
parte a tutorialului)

.MODEL [tip_model] [conventia_de_limbaj] \ ;declaratie obligatorie inainte de a


[tip_stiva]
;utiliza directivele simplificate de
;definire a unui segment
[.tip_procesor]
;definire tip procesor, implicit 8086
.STACK [expresie]
;definire segment de stiva, implicit 1KB (1024
;de octeti)
.DATA
;definire segment de date
.CODE
start:

;definire segment de cod


;eticheta ce indica adresa de start a codului

END start

;indica sfarsit program - obligatoriu

in care:

Optiune

Descriere

Valori posibile

defineste modelul de memorie; determina TINY, SMALL,


dimensiunea codului si datelor (segmentelor) COMPACT, MEDIUM,
precum si a adreselor;
LARGE, HUGE, FLAT

tip_model

faciliteaza compatibilitatea cu limbajele de nivel C, BASIC,FORTRAN,


conventia_de_limbaj inalt prin determinarea codarii interne a numelor PASCAL, SYSCALL,
simbolurilor externe si publice;
STDCALL

tip_stiva

modul in care este definita stiva ca distanta fata de


segmentul de date; NEARSTACK plaseaza stiva NEARSTACK (implicit),
in acelasi segment fizic cu cel al datelor; pentru FARSTACK
FARSTACK stiva are propriul ei segment fizic;

tip_procesor

odata selectat tipul procesorului se utilizeaza doar


.186, .286, .386, .486
setul de instructiuni asociat;

expresie

dimensiunea in octeti a stivei

Pot fi utilizate o serie de simboluri predefinite pentru a descrie segmentele:

Simbol

Descriere

@Model

- intoarce modelul de memorie ca valoare intreaga cuprinsa intre 1 si 7;

@Data

- segmentul de date

@DataSize

- dimensiunea modelului de memorie

@CurSeg

- segmentul curent

@CodeSize - tipul pointerilor: far sau near

Definirea completa a segmentelor utilizeaza sintaxa:


nume_segment SEGMENT [tip_aliniere] [READONLY] [tip_combinare] [tip_adresare] [clasa_segmente]

nume_segment ENDS in care:

Element

Descriere

nume_segment

- defineste numele segmentului; in cadrul unui modul toate segmentele definite cu


acelasi nume sunt considerate ca reprezentand acelasi segment; de asemenea sunt
combinate si segmentele cu acelasi nume, dar care se gasesc in module diferite.

tip_aliniere

- descrie adresa la care incepe un segment nou

READONLY

- indica programului ca segmentul este de tip read-only si se genereaza eroare la


incercarile de modifica valori; element optional;

tip_combinare

- indica modul in care sunt combinate segmentele cu acelasi nume dar din module
separate la crearea executabilului;

tip_adresare

- descrie modul de lucru al procesoarelor (de la 386 in sus), fie pe 16 biti, fie pe 32
de biti;

clasa_segmente

- nume dat intre ce indica o clasa de segmente; segmentele din aceeasi clasa sunt
aranjate secvential; utilizat pentru a indica ordinea de aranjare a segmentelor.

Atentie ! Nu se poate specifica mai mult de o valoarea pentru fiecare element.


Un segment se poate inchide cu ENDS si apoi redeschide ulterior doar cu directiva nume_segment SEGMENT, fara
a modifica optiunile din prima definire.

[tip_aliniere]
element optional;
defineste multimea din care sa fie selectata adresa de la care este alocat segmentul;
descrie faptul ca adresa fizica de inceput a segmentului este divizibila cu 1,2,4,16 sau 265;
link-erul utilizeaza aceasta informatie pentru a determina adresa relativa de start a fiecarui segment; sistemul
determina adresa de start actuala cand programul este incarcat;

valorile pe care le poate lua:

Tip aliniere

Adresa de start

BYTE

- urmatoarea adresa de tip byte disponibila;

WORD

- urmatoarea adresa de tip word disponibila;

DWORD

- urmatoarea adresa de tip double disponibila;

PARA

- urmatoarea adresa de tip paragraf (16 octeti) disponibila; valoare default

PAGE

- urmatoarea adresa de tip pagina (256 octeti) disponibila;

[tip_combinare]
element optional;
indica modul in care sunt combinate segmente cu acelasi nume, dar care apar in module diferite; informatie
utilizata de link-er, nu de asamblor, pentru ca este necesara la crearea executabilului si nu la asamblarea
fiecarui modul in parte;

valorile pe care le poate lua:

Tip
combinare

Descriere

PRIVATE

- nu combina segmentul respectiv cu alte segmente (din alte module) ce au acelasi


nume; optiune default;

PUBLIC

- combina segmentele cu acelasi nume din module separate intr-o zona de memorie
continua;

COMMON

- combina segmentele cu acelasi nume din module separate suprapunandu-le pe aceeasi


zona de memorie de marime egala cu dimensiunea celui mai mare segment;

- segmentul este plasat la adresa indicata de expresie; nu se permite declararea de cod


sau initializare de date; reprezinta o masca care se poate suprapune datelor si codului
AT expresie
existent in memorie; asamblorul nu genereaza date sau cod pentru acest segment, insa
permite adresarea in cadrul sau;
MEMORY

- segmentul curent este asezat in memorie in spatiul ramas disponibil dupa alocarea
celorlalte segmente (catre sfarsitul memoriei); utilizat si ca sinonim pentru PUBLIC;

STACK

- concateneaza toate segmentele cu acelasi nume si pune in SS adresa de inceput a


segmentului rezultat, iar SP pe sfarsitul sau; segmentul rezultat este asociat stivei;

[tip_adresare]
element optional;
reprezinta atributul modului de utilizare pentru procesoare, incepand de la .386;
valorile pe care le poate lua:

Tip
adresare

Descriere

USE16

- indica faptul ca elementele din segment sunt adresate utilizand un offset pe 16 de biti;
daca se specifica .386 sau .486 dupa de directiva .MODEL atunci default este modul
USE16;

USE32

- indica faptul ca elementele din segment sunt adresate utilizand un offset pe 32 de biti;
daca se specifica .386 sau .486 inainte de directiva .MODEL atunci default este modul
USE32;

[clasa_segmente]
element optional;
indica modul de aranjare in memorie a segmentelor din aceeasi clasa;
doua segmente cu acelasi nume, dar cu clase diferite nu sunt combinate;
segmentele din aceeasi clasa sunt aranjate secvential in memorie in ordinea in care sunt intalnite.
In mod normal, asamblorul aranjeaza segmentele in fisierul .obj in ordinea in care apar in codul sursa. In schimb,
link-editorul proceseaza fisierele .obj in ordinea din linia de comanda. In cadrul fiecarui modul, acesta aloca
memorie pentru segmente in ordinea aparitiei, apartenentei la un grup, clasa si cerinte date de modul de aranjare
.DOSSEG (conventia de ordonare a segmentelor MS-DOS).
Modul de aranjare a segmentelor este important atunci cand e doreste ca anumite segmente sa apara la inceputul
sau sfarsitul unui program sau cand se fac presupuneri in legatura cu ce segmente se gasesc langa altele.
Pentru a controla ordinea in care segmentele apar in memorie se utilizeaza directivele:

.SEQ

- in ordinea in care sunt declarate; modalitate implicita

.ALPHA

- ordonare alfabetica a segmentelor dintr-un modul;

- aranjeaza segmentele in ordinea standard a limbajelor Microsoft; nu se utilizeaza


.DOSSEG directiva in module apelate in cadrul altor module; ordinea segmentelor este cod, date,
stiva.

Initializarea segmentelor de registru


In cadrul programelor cu structura simplificata (.model) initializarea registrelor de segment (DS, SS, ES, CS) si
asocierea lor cu segmentele de date, cod si stiva era realizata de asamblor si lnk-editor. In cadrul programelor a
caror structura este definita de programator, initializarea acestora se face de catre acesta. Pasii ce trebuie urmati
sunt:

Atentie

Asocierea logica dintre registrul de segment si segmentul declarat se face prin intermediul directivei ASSUME.
Aceasta informatie este necesara asamblorului si link-editorului la transformarea programului in cod masina.
Multe dintre instructiunile assembler presupun existenta unui segment implicit. Accesul la o zona de memorie din
segmentul de date fie prin nume variabila, [registru index] sau [registru de baza][registru index] (toate reprezinta
adrese offset) se realizeaza fata de adresa fizica continuta de registrul DS. Fiecare instructiune de citire/scriere cu
stiva (POP/PUSH) se realizeaza implicit fata de SS. Instructiunile de salt conditionat/neconditionat reprezinta salturi
la adrese offset in cadrul segmentului de cod, a carui adresa se gaseste in CS.
De aceea in cazul programelor cu mai multe segmente este necesar sa se indice asocierea logica dintre segment
si registru de segment pentru ca programul (mai precis asamblorul si link-editorul care transforma codul in cod
masina) sa stie unde (in ce segmente) se gasesc adresele respective (date sau instructiuni).
Asocierea se realizeaza cu instructiunea
ASSUME registru_segment:nume_segment[,registru_segment:nume_segment]
ASSUME [registru_segment:] NOTHING [,registru_segment:NOTHING]

Un registru_segment reprezinta unul dintre registrele de segment: CS, DS, ES sau SS; nume_segmentreprezinta
numele unui segment sau grup de segmente.
Atentie

Odata ce s-a modificat unul dintre registrele DS, ES sau SS trebuie precizat acest lucru procesorului prin incarcarea
registrului de segment utilizat implicit cu adresa noului segment.Daca segmentul utilizat reprezinta o zona de
date initializarea registrului DS se face prin secventa:
mov AX, nume_segment
mov DS, AX

Daca segmentul reprezinta o zona de stiva initializarea registrului SS se realizeaza prin:


mov AX, nume_segment
mov SS, AX
mov SP, offset baza_stiva ;pentru ca adresele in stiva scad trebuie ca SP sa fie ;initializat cu
offset-ul ultimei zone de memorie din stiva

Modul simplificat de definire a unui segment ce va fi utilizat pe post de stiva este:


Stiva SEGMENT
dw 50 dup (?)
;rezerv o zona de 50 * 2 octeti
baza_stiva label word
Stiva ENDS

Daca segmentul utilizat reprezinta o zona de date extinsa initializarea registrului ES se face prin secventa:
mov AX, nume_segment
mov ES, AX

Se observa ca registrul CS nu trebuie incarcat. Acest lucru este realizat implicit (daca nu s-ar fi realizat acest lucru
nu se putea executa nici o instructiune din program ,iar initializarile reprezinta de fapt secvente de instructiuni)
prin indicarea punctului de start al programului (NU UITA de eticheta start: si de instructiunea de final end start)
si prin asocierea logica ASSUME CS:nume_segment.
Instructiunea ASSUME registru_segment:NOTHING sterge asocierea logica anterioara. Instructiunea ASSUME
NOTHING sterge asocierile logice pentru toate registrele de segment.

Definirea grupurilor de segmente


Un grup reprezinta o colectie de segmente ce nu trebuie sa depaseasca (cumulat !!!) mai mult de 64 KBytes pe
arhitectura de 16 biti si nu mai mult de 4GBytes pe 32 de biti. Un grup permite asocierea dintre mai multe segmente
definite logic si elimina repetarea instructiunilor de incarcare a registrelor de segment la schimbarea registrelor

utilizate. De exemplu programul contine mai multe segmente de date iar accesul la ele implica schimbarea adresei
din registrul DS. Gruparea acestor segmente intr-un grup implica realizarea unui singur segment obtinut prin
concatenarea segmentelor din grup si incarcarea o singura data a registrului DS cu adresa grupului. Toate
datele/codul este astfel accesibil relativ la adresa de inceput a grupului. Sintaxa de definire a grupului este:
nume_grup GROUP nume_segment [, nume_segment]

Atentie ! Se are in vedere:

un segment nu poate fi definite in mai multe grupuri


dimensiunea grupului nu trebuie sa depaseasca 65 KBytes pe 16 biti si 4 GBytes pe 32 de biti;
nu indica modul de incarcare in memorie a segmentelor din grup si de aceea trebuie acordata atentie la
modul de definire a segmentelor astfel incat segmente ce nu apartin grupului sa nu fie alocate intre
segmentele din grup, iar in final acesta sa depaseasca dimensiunea maxima admisa.

De exemplu secventa de program:


Date1 SEGMENT
a dw 1234h
b dw 5678h
Date1 ENDS
Date2 SEGMENT
vector dw 5 dup (9)
Date2 ENDS
Temporare SEGMENT
temp dw 5 dup (3)
Temporare ENDS
Date3 SEGMENT
c dw 1111h
d dw 2222h
Date3 ENDS
Stiva SEGMENT
dw 100 dup(?)
varf label word
Stiva ENDS
Date GROUP Date1, Date2, Date3
Principal SEGMENT
ASSUME CS:Principal,SS:Stiva,DS:Date
start:
mov AX,Date
;incarc in DS adresa grupului de segmente
mov DS,AX
mov
mov
mov
mov

AX,Stiva
;incarc in SS adresa segmentului de stiva
SS,AX
AX, offset varf
;incarc SP
SP,AX

mov
mov
mov
mov

AX,
AX,
AX,
AX,

b
vector
c
d

;pun in AX valoarea din b


;pun in AX valoarea din vector[0]
;pun in AX valoarea din c
;pun in AX valoarea din d

;se observa ca datele sunt accesibile fara a incarca de fiecare data DS cu adresa
;segmentului parinte
mov AX,4c00h
int 21h
Principal ENDS
end start

genereaza dispunerea in memorie a datelor astfel:

1
2
3
4
5
6
7

DS:0000
DS:0008
DS:0010
DS:0018
DS:0020
DS:0028
DS:0030

34
00
09
09
03
03
11

12
00
00
00
00
00
11

78
00
09
00
03
00
22

56
00
00
00
00
00
22

00
00
09
00
03
00
00

00
00
00
00
00
00
00

00
00
09
00
03
00
00

00
00
00
00
00
00
00

;date
;zona
;date
;date
;date
;date
;date

segment
de date
segment
segment
segment
segment
segment

Date1
Date2
Date2
Temporare
Temporare
Date3

Atentie !De ce fiecare segment pare ca ocupa 16 octeti (fiecare segment ocupa atata spatiu cate date sunt definite
in el, iar restul de octeti sunt nerezervati) ? Pentru ca implicit la definire tipul alinierii este PARA segmentele sunt
alocate in memorie numai de la adrese divizibile cu 16. Restul de octeti (pana la al 16-lea) sunt nerezervati, dar
pot fi accesati relativ fata de adresa de inceput a segmentului.
Atentie ! In exemplul anterior instructiunea mov AX,offset d va pune in AX valoarea 0002h si nu 0030h deoarece
intoarce offset-ul fata de adresa segmentului parinte si nu fata de adresa de start a grupului.
In Debugger (la dezasamblarea instructiunilor) se observa ca variabilele b, vector, c si d sunt referite prin offseturi relative fata de adresa de inceput a grupului: 0002h, 0010h, 0030h, 0032h evidentiindu-se faptul ca intre
segmentele grupului s-a intercalat segmentul Temporare (ordinea de alocare in memorie este implicit .SEQ). Pentru
a evita situatia:

se declara segmentul Temporare dupa declararea celor 3 segmente Date1, Date2 si Date3;
se utilizeaza o clasa de segmente clasa_seg in care sunt puse segmentele Date1, Date2 si Date3.

De exemplu:
Date1 SEGMENT 'clasa_date'
a dw 1234h
b dw 5678h
Date1 ENDS
Date2 SEGMENT 'clasa_date'
vector dw 5 dup (9)
Date2 ENDS
Temporare SEGMENT BYTE
;alocare la o adresa divizibila cu 1
temp dw 5 dup (3)
Temporare ENDS
Date3 SEGMENT 'clasa_date'
c dw 1111h
d dw 2222h
Date3 ENDS
Stiva SEGMENT
dw 100 dup(?)
varf label word
Stiva ENDS
Date GROUP Date1, Date2, Date3
.................

In aceasta situatie segmentele sunt aranjate in memorie astfel:


1
2
3
4
5
6

DS:0000
DS:0008
DS:0010
DS:0018
DS:0020
DS:0028

34
00
09
09
11
03

12
00
00
00
11
00

78
00
09
00
22
03

56
00
00
00
22
00

00
00
09
00
03
03

00
00
00
00
00
00

00
00
09
00
03
00

00
00
00
00
00
00

;date
;zona
;date
;date
;date
;date

segment
de date
segment
segment
segment
segment

Date1
Date2
Date2
Date3 si Temporare
Temporare

Se observa ca indicand ca segmentul Temporare sa fie alocat la o adresa de tip BYTE el urmeaza dupa segmentul
Date3 eliminandu-se octetii nefolositi.

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:

Tip

Nr. biti Cifre semnificative

Interval de valori

Declarare

Short real

32

6-7

1.18 * 10-38 3.40 * 1038

vb DD 1.2

Long real

64

15-16

2.23 * 10-308 1.79 * 10308

vb DQ 2.3

10-byte real

80

19

3.37 * 10-4932 1.18 * 104932 vb DT 1.8

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
b
c

DD
DD
DQ

11.765
1.1765E+1
1176.5E-2

;forma zecimala
;forma exponentiala zecimala
;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
b
c

DD
DQ
DT

3F800000r
3D60000000000000r
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

exemplu de numar real in forma binara


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

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

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:

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

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:

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
ST

#2

#3

#4

#5

3.6 3.14 11.304 1

#6

12.304 1.23

#7

#8

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
Fld b
Fstp a

;#1
;#2
;#3

Fstp b

;#4

;pune valoarea din ST in a si o scoate


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

Pentru programul anterior stiva registrelor coprocesorului trece prin urmatoarele faze:

#1
ST

#2

1.23 3.6

#3

#4

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
Fld a
Fmul ST,ST
Fxch ST(1)
Fld b
Fadd ST(2),ST
Fmul ST,ST(1)
Fadd ST,ST(1)
Fadd ST,ST(2)
Ffree ST(2)

;#1
;#2
;#3
;#4
;#5
;#6
;#7
;#8
;#9
;#10

Ffree ST(1)
Fstp ES:e

;#11

;eliberez registrul ST(2)


;#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

#1
2

1.2
3

1.2
3

1.512
9

1.23

3.6

3.6

4.428

5.658

10.770
9

10.770
9

10.770
9

ST(1
)

1.2
3

1.23

1.512
9

1.23

1.23

1.23

1.23

1.23

1.23

ST(2
)

1.512
9

5.112
9

5.112
9

5.112
9

5.1129

ST

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
Fld b
Fld c
Fld d
Faddp ST(3),ST
Faddp ST(2),ST
Faddp ST(1),ST
Fstp ES:e

;#1
;#2
;#3
;#4
;#5
;#6
;#7
;#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

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

ST

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
Fmul ST,ST
FsubR
;valoarea din ST - #10

;incarc valoarea lui b in ST - #8


;inmultesc ST cu ST si obtin b*b - #9
;scadere inversa (adica ST(1) = ST-ST(1) si scoate
;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
Fld b
Fchs
Fxch

;radical din ST adica din b*b-4*a*c - #11


;incarc valoarea lui b - #12
;schim semnul valorii din ST - #13
;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
mov AX,DateOut
mov DS,AX

;schimb segmentul de date


;pentru a scrie valoarea rezultatelor

Fdiv ST,ST(2)
Fstp x1
FdivR

;fac ST = ST / ST(2) - #19


;scot rezultatul in x1 - #20
;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

ST

7.6

7.6

15.2 24.32

ST(1)

15.2

7.6

ST(2)

ST(3)

ST(4)

#11

#12

#13

#6

#7

#8

#9

#10

8.2

67.24

42.92

7.6

24.32

24.32

7.6

7.6

7.6

#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

ST(1)

7.6

6.55

6.55

-8.2 6.55

6.55

-1.64 -14.75 -14.75

ST(2)

7.6

7.6

7.6

-8.2

-8.2

-8.2

7.6

ST(3)

7.6

7.6

7.6

ST(4)

-14.75 -1.94
7.6

7.6

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
FIADD vb

aduna cei doi operanzi si descarca stiva


aduna un intreg de 16/32 de biti la ST
scade numere reale

FSUB [operanzi]
FSUB op1,op2
FSUB vb
FSUBR [operanzi]
FSUBRPop1,op2
FSUBR vb

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
inmultire numere reale

FMUL [operanzi] FMULP


op1,op2 FMUL vb

FDIV [operanzi]
FDIVP op1,op2
FIDIV vb
FDIVR [operanzi]
FDIVRP opl/op2

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)
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

FDIVR vb

impartirea unui intreg de 16/32 de biti la ST

radacina patrata din ST

FSQRT
FSCALE
FPREM
FRNDINT
FXTRACT

STST*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|

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

Cuvant de control

Cuvant de stare

Cuvant Eticheta (Tag)

3
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
C3

C2 C1 C0

Octetul inferior al registrului de flag-uri al procesorului:

SF ZF

4
AF

2
PF

0
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:
variabila_de_tip_word
Fstsw
;pun valoarea cuvantului de stare intr-o variabila
Fwait
AX, variabila_de_tip_word ;incarc valoarea variabilei in AX
mov
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

ST > sursa

ST > 0

ST < sursa

ST < 0

ST = sursa

ST = 0

C3 C2 C0

Nu se poate compara Nu se poate testa; ST are valoarea NAN

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

Coduri si Simboluri ASCII + Coduri si Caractere Speciale HTML


Tabelul urmator descrie setul de caractere si simboluri ASCII, coduri si caractere speciale HTML, simboluri ISO
10646, ISO 8879, HTML 4.01 si Latin extins A si B

Valoare
zecimala

Valoare HEX
hexazecimala

Simbol

Cod numeric
HTML

Cod
HTML

NUL

null

SOH

start heading

STX

start text

ETX

sfarsit text

EOT

sfarsit transmisie

ENQ

enquiry

ACK

acknowledge (confirmare)

BEL

bell

BS

backspace

TAB

tabulation

10

LF

line feed

11

VT

vertical tabulation

12

FF

form feed

13

CR

carriage return

14

SO

shift out

15

SI

shift in

16

10

DLE

data link escape

17

11

DC1

device control 1

Descriere

18

12

DC2

device control 2

19

13

DC3

device control 3

20

14

DC4

device control 4

21

15

NAK

negative acknowledge

22

16

SYN

synchronous idle

23

17

ETB

end of transmission block

24

18

CAN

cancel

25

19

EM

end of medium

26

1A

SUB

substitute

27

1B

ESC

escape

28

1C

FS

file separator

29

1D

GS

group separator

30

1E

RS

record separator

31

1F

US

unit separator

32

20

33

21

&#33;

34

22

&#34;

35

23

&#35;

diez

36

24

&#36;

dolar

37

25

&#37;

procent

38

26

&

&#38;

(space) &#32;

space (spatiu)
semn de exclamatie
&quot;

&amp;

ghilimele

ampersand (si logic)

39

27

&#39;

apostrof

40

28

&#40;

paranteza deschisa

41

29

&#41;

paranteza inchisa

42

2A

&#42;

asterix

43

2B

&#43;

plus sign

44

2C

&#44;

virgula

45

2D

&#45;

minus

46

2E

&#46;

punct

47

2F

&#47;

slash

48

30

&#48;

49

31

&#49;

50

32

&#50;

51

33

&#51;

52

34

&#52;

53

35

&#53;

54

36

&#54;

55

37

&#55;

56

38

&#56;

57

39

&#57;

58

3A

&#58;

doua puncte

59

3B

&#59;

punct si virgula

60

3C

<

&#60;

&lt;

mai mic

61

3D

&#61;

62

3E

>

&#62;

63

3F

&#63;

semnul intrebarii

64

40

&#64;

at (a rond sau coada de


maimuta)

65

41

&#65;

66

42

&#66;

67

43

&#67;

68

44

&#68;

69

45

&#69;

70

46

&#70;

71

47

&#71;

72

48

&#72;

73

49

&#73;

74

4A

&#74;

75

4B

&#75;

76

4C

&#76;

77

4D

&#77;

78

4E

&#78;

79

4F

&#79;

80

50

&#80;

egal
&gt;

mai mare

81

51

&#81;

82

52

&#82;

83

53

&#83;

84

54

&#84;

85

55

&#85;

86

56

&#86;

87

57

&#87;

88

58

&#88;

89

59

&#89;

90

5A

&#90;

91

5B

&#91;

92

5C

&#92;

93

5D

&#93;

94

5E

&#94;

95

5F

&#95;

96

60

&#96;

97

61

&#97;

98

62

&#98;

99

63

&#99;

100

64

&#100;

101

65

&#101;

paranteza patrata
deschisa

paranteza patrata inchisa

102

66

&#102;

103

67

&#103;

104

68

&#104;

105

69

&#105;

106

6A

&#106;

107

6B

&#107;

108

6C

&#108;

109

6D

&#109;

110

6E

&#110;

111

6F

&#111;

112

70

&#112;

113

71

&#113;

114

72

&#114;

115

73

&#115;

116

74

&#116;

117

75

&#117;

118

76

&#118;

119

77

&#119;

120

78

&#120;

121

79

&#121;

122

7A

&#122;

123

7B

&#123;

124

7C

&#124;

125

7D

&#125;

126

7E

&#126;

127

7F

160

A0

161

A1

162

tilda

&#160;

&nbsp;

spatiu

&#161;

&iexcl;

inverted exclamation
mark

A2

&#162;

&cent;

cent

163

A3

&#163;

&pound;

pound

164

A4

&#164;

&curren;

currency

165

A5

&#165;

&yen;

yen

166

A6

&#166;

&brvbar;

broken vertical bar

167

A7

&#167;

&sect;

section sign

168

A8

&#168;

&uml;

spacing diaeresis umlaut

169

A9

&#169;

&copy;

copyright

170

AA

&#170;

&ordf;

feminine ordinal indicator

171

AB

&#171;

&laquo;

left double angle quotes

172

AC

&#172;

&not;

not sign

173

AD

&#173;

&shy;

soft hyphen

174

AE

&#174;

&reg;

registered trade mark

175

AF

&#175;

&macr;

spacing macron overline

176

B0

&#176;

&deg;

degree sign

177

B1

&#177;

&plusmn;

plus-or-minus sign

178

B2

&#178;

&sup2;

superscript two squared

179

B3

&#179;

&sup3;

superscript three cubed

180

B4

&#180;

&acute;

acute accent spacing


acute

181

B5

&#181;

&micro;

micro sign

182

B6

&#182;

&para;

pilcrow sign paragraph


sign

183

B7

&#183;

&middot;

middle dot Georgian


comma

184

B8

&#184;

&cedil;

spacing cedilla

185

B9

&#185;

&sup1;

superscript one

186

BA

&#186;

&ordm;

masculine ordinal
indicator

187

BB

&#187;

&raquo;

right double angle quotes

188

BC

&#188;

&frac14;

fractie sfert

189

BD

&#189;

&frac12;

fractie jumatate

190

BE

&#190;

&frac34;

fractie 3 sferturi

191

BF

&#191;

&iquest;

192

C0

&#192;

&Agrave;

latin capital letter A with


grave

193

C1

&#193;

&Aacute;

latin capital letter A with


acute

194

C2

&#194;

&Acirc;

latin capital letter A with


circumflex

195

C3

&#195;

&Atilde;

latin capital letter A with


tilde

196

C4

&#196;

&Auml;

latin capital letter A with


diaeresis

197

C5

&#197;

&Aring;

latin capital letter A with


ring above

198

C6

&#198;

&AElig;

latin capital letter AE

199

C7

&#199;

&Ccedil;

latin capital letter C with


cedilla

200

C8

&#200;

&Egrave;

latin capital letter E with


grave

201

C9

&#201;

&Eacute;

latin capital letter E with


acute

202

CA

&#202;

&Ecirc;

latin capital letter E with


circumflex

203

CB

&#203;

&Euml;

latin capital letter E with


diaeresis

204

CC

&#204;

&Igrave;

latin capital letter I with


grave

205

CD

&#205;

&Iacute;

latin capital letter I with


acute

206

CE

&#206;

&Icirc;

latin capital letter I with


circumflex

207

CF

&#207;

&Iuml;

latin capital letter I with


diaeresis

208

D0

&#208;

&ETH;

latin capital letter ETH

209

D1

&#209;

&Ntilde;

latin capital letter N with


tilde

210

D2

&#210;

&Ograve;

latin capital letter O with


grave

211

D3

&#211;

&Oacute;

latin capital letter O with


acute

212

D4

&#212;

&Ocirc;

latin capital letter O with


circumflex

213

D5

&#213;

&Otilde;

latin capital letter O with


tilde

214

D6

&#214;

&Ouml;

latin capital letter O with


diaeresis

215

D7

&#215;

&times;

multiplication sign

216

D8

&#216;

&Oslash;

latin capital letter O with


slash

217

D9

&#217;

&Ugrave;

latin capital letter U with


grave

218

DA

&#218;

&Uacute;

latin capital letter U with


acute

219

DB

&#219;

&Ucirc;

latin capital letter U with


circumflex

220

DC

&#220;

&Uuml;

latin capital letter U with


diaeresis

221

DD

&#221;

&Yacute;

latin capital letter Y with


acute

222

DE

&#222;

&THORN;

latin capital letter THORN

223

DF

&#223;

&szlig;

latin small letter sharp s


ess-zed

224

E0

&#224;

&agrave;

latin small letter a with


grave

225

E1

&#225;

&aacute;

latin small letter a with


acute

226

E2

&#226;

&acirc;

latin small letter a with


circumflex

227

E3

&#227;

&atilde;

latin small letter a with


tilde

228

E4

&#228;

&auml;

latin small letter a with


diaeresis

229

E5

&#229;

&aring;

latin small letter a with


ring above

230

E6

&#230;

&aelig;

latin small letter ae

231

E7

&#231;

&ccedil;

latin small letter c with


cedilla

232

E8

&#232;

&egrave;

latin small letter e with


grave

233

E9

&#233;

&eacute;

latin small letter e with


acute

234

EA

&#234;

&ecirc;

latin small letter e with


circumflex

235

EB

&#235;

&euml;

latin small letter e with


diaeresis

236

EC

&#236;

&igrave;

latin small letter i with


grave

237

ED

&#237;

&iacute;

latin small letter i with


acute

238

EE

&#238;

&icirc;

latin small letter i with


circumflex

239

EF

&#239;

&iuml;

latin small letter i with


diaeresis

240

F0

&#240;

&eth;

latin small letter eth

241

F1

&#241;

&ntilde;

latin small letter n with


tilde

242

F2

&#242;

&ograve;

latin small letter o with


grave

243

F3

&#243;

&oacute;

latin small letter o with


acute

244

F4

&#244;

&ocirc;

latin small letter o with


circumflex

245

F5

&#245;

&otilde;

latin small letter o with


tilde

246

F6

&#246;

&ouml;

latin small letter o with


diaeresis

247

F7

&#247;

&divide;

division sign

248

F8

&#248;

&oslash;

latin small letter o with


slash

249

F9

&#249;

&ugrave;

latin small letter u with


grave

250

FA

&#250;

&uacute;

latin small letter u with


acute

251

FB

&#251;

&ucirc;

latin small letter u with


circumflex

252

FC

&#252;

&uuml;

latin small letter u with


diaeresis

253

FD

&#253;

&yacute;

latin small letter y with


acute

254

FE

&#254;

&thorn;

latin small letter thorn

255

FF

&#255;

&yuml;

latin small letter y with


diaeresis

338

152

&#338;

latin capital letter OE

339

153

&#339;

latin small letter oe

352

160

&#352;

latin capital letter S with


caron

353

161

&#353;

latin small letter s with


caron

376

178

&#376;

latin capital letter Y with


diaeresis

402

192

&#402;

latin small f with hook


function

8211

2013

&#8211;

en dash

8212

2014

&#8212;

em dash

8216

2018

&#8216;

left single quotation mark

8217

2019

&#8217;

right single quotation


mark

8218

201A

&#8218;

single low-9 quotation


mark

8220

201C

&#8220;

left double quotation


mark

8221

201D

&#8221;

right double quotation


mark

8222

201E

&#8222;

double low-9 quotation


mark

8224

2020

&#8224;

dagger

8225

2021

&#8225;

double dagger

8226

2022

&#8226;

bullet

8230

2026

&#8230;

horizontal ellipsis

8240

2030

&#8240;

per thousand sign

8364

20AC

&#8364;

8482

2122

&#8482;

&euro;

euro
trade mark

S-ar putea să vă placă și