You are on page 1of 109

1.

MICROPROCESORUL Intel 8x86


1.1. Structura microprocesorului I8x86

Registre generale (8,16,32biti)


31 15 8 0
EAX ……. AX AH AL Acumulator
EBX ……. BX BH BL Baze reg.
ECX ……. CX CH CL Counter reg.
EDX ……. DX DH DL Data reg.

Registre pointer si index( 16,32biti)


31 15 0
ESP ……. SP Stack pointer
EBP ……. BP Baze pointer
ESI ……. SI Source index
EDI ……. DI Destination index

Registre de baza pentru segmente


31 15 0
ECS ……. CS Code segment
EDS ……. DS Data segment
ESS ……. SS Stack segment
EES ……. ES Extra segment
(la Pentium exista si reg.segment FS, GS)
Registre de stare
31 15 0
IP ……. Adresa instructiune curenta Instruction pointer
FLAG …….NT O D I T S Z A P C Flag register

Bitii din registrul Flag sunt indicatori de stare care se pozitioneaza functie de rezultatul ultimei
operatii aritmetice sau logice si se testeaza de instructiunile de salt.
Instructiunile de transfer a datelor si salt nu pozitioneaza indicatorii.

O – Overflow flag depasire capacitate registru la operatii aritmetice


D – Direction flag directia deplasarii la instr. pe siruri de caractere( d=0 spre dreapta)
I – Interupt enableflag intreruperi admise
T – Trap flag
S – Sign flag indica semnul rezultatului (S=0 pozitiv, S=1 negativ)
Z – Zero flag indica rezultat zero (Z=1)
A – Auxiliar carry Transport intermediar din rangul 4 ( A=1)
P - Parity flag Numar de biti par in rezultat (P=1)
C – Carry flag Transport din rangul cel mai semnificativ (C=1)
NT – Nested task Pentru control task-uri

1.2. Segmentarea programelor

1
Programele trebuie sa fie modulare si relocatabile - sa poata fi incarcate oriunde in memorie si sa poata rula
din acea zona.
Modulele vor cuprinde informatii de acelasi tip rezultate din compilarea programelor.
Un segment poate cuprinde mai multe module asamblate de Link-Editor.
Un program poate cuprinde mai multe segmente. Exista 4 tipuri de segmente :
 segment de cod ce contine numai instructiuni de program cu adrese relative la inceputul
segmentului, bazat cu registrul de segment CS;
 segment de date ce contine numai date din program, bazat cu registrul DS ;
 segment de date comune pentru mai multe segmente, bazat cu registrul ES ; 
 segment de stiva ce contine datele gestionate ca stive, bazat cu registrul SS ;
Implicit adresele datelor din program se bazeaza cu reg.DS, adresele de salt cu reg.CS si adresele de stiva
indicate de SP (Stack Pointer) cu reg.SS.

Structura unui program relocatabil format din segmente

Segment de cod
CS=1000 000 -salt la adresa 250 din seg.
… JMP CS :250 de cod plasat la adresa
1000 indicata de CS
(adresa absoluta 1250)
250
MOV AX,DS :[150] -incarca z din seg. de date
bazat cu DS de la adr. 150
-incarca x de la adr.40 din
MOV BX,ES :[40] seg.Extern bazat cu ES
Segment date locale
DS=2000 000

- adresa absoluta
150 2000+150=2150
Z=350

Segment date extern (comune)


ES=5000 000
- adresa absoluta
40 X=333 5000+40=5040

Segment de stiva
SS=7500 ….. Contine toate stivele
…. folosite in program

2
Calculul adresei fizice

15 0
Cod Offset Adresa Adresa relativa in
instr. (Deplasament) segment
0
15 +
CS Adresa inceput segment 0000
0
19 =
Adresa de memorie fizica

1.3. Moduri de adresare

La microprocesorul Ix86 poate exista o singura adresa de memorie in instructiune.


Un operand este in registru iar celalalt in memorie sau alt registru.

Adresarea registru registru


ADD AX,DX se aduna continutul lui DX la AX pe 16 biti
ADD BH,CL se aduna continutul lui CL la BH pe 8 biti

COD instr Reg.sursa, Reg.destinatie - codul poate fi pe 1 sau 2 octeti

Adresarea imediata - un operand este in instructiune


ADD AX,5000 se aduna 5000 la AX
ADD SI,25 se aduna 25 la registrul SI

COD instr 5000 (valoare) - valoarea operand poate fi pe 1, 2 sau 4 octeti

Adresarea directa - un operand este in memorie


ADD AX,alfa continutul lui alfa se aduna la AX (bazat cu DS)
ADD AX,[500] continutul adresei 500 se aduna la AX

COD instr Adresa relativa in segment - adresa poate fi pe 1, 2 sau 4 octeti


- codul poate fi pe 1 sau 2 octeti
Adresarea indirecta
ADD AX,[BX] continutul adresei indicate de BX se aduna la AX (bazat cu DS)

BX RAM
COD instr. Adresa relativa operand Operand2

Adresarea indexata
ADD AX,X[SI] din tabloul X se ia elementul indicat de SI (adr.in tablou)

3
Tablou X +SI
COD instr. Adresa relativa tablou X X1 X2 X3 Xi

Adresarea cu baza
ADD AX,[BX+5] BX indica o zona de date, iar 5 este adr.relativa in zona

BX Zona de date +5
COD instr. Adresa relativa zona Oper2

Adresarea cu baza si index


ADD AX,[BX+SI+5] BX indica o zona, iar 5 este adr.rel.a unui tablou si SI
pozitia elementului in tablou(nu indice)
BX +5 Tablou X SI
COD instr. Adresa relativa zona X1 X2 Xi

1.4. Formatul instructiunilor


Informatiile din memoria RAM pot fi:
- date in binar, in virgule flotanta, in zecimal si pe diferite lungimi
- instructiuni de diferite lungimi

Instructiunile care se folosesc determina cum se interpreteaza acele informatii.


In limbaj de asamblare nu exista tipuri de date declarate si se poate da doar lungimea.
Daca o variabile in VF se adreseaza cu o instructiune binara valoarea este imprevizibila.
Daca registrul IP (Instruction Pointer) se incarca cu o adresa de date, datele se interpreteaza ca intructiune si
se pot face distrugeri in program. La incarcarea unui program se sterge toata memoria pentru a nu ramane
reziduri din vechile programme.

Datele pot fi : locale in segment specificate prin adresa relative la care se adauga [DS]
comune mai multor segmente (ext) spec.prin adr.rel. si se adauga [ES]
temporare care se pastreaza in stive in segmentul de stiva adr. [SP]+ [SS]

Setul de instructiuni al calculatorului cuprinde:


 instructiuni de transfer, aritmetice si logice realizate in dispozitivul aritmetic;
 instructiuni pentru prelucrare siruri de caractere (texte);
 instructiuni de control a programului (salturi conditionate);
 instructiuni de calcul in Virgula Flotanta (VF) realizate in coprocessor;
 instructiuni de calcul in zecimal realizate in coprocessor

Pentium si I486 cuprind procesor si coprocesor care lucreaza in paralel. Coprocesorul nu are mecanism
de calcul al adresei si salt, care se realizeaza de processor.

Structura instructiunilor I8x86

COD - instructiune pe un octet MOV AL,BL

4
COD adr.rel -instr. pe 3 octeti, adresare directa ADD BX,alfa

COD operand2 - instr. pe 2 sau 3 octeti – instr. imediata MOV SI,55

COD adr.rel operand2 - instr.pe 4 sau 5 oct MOV X,5200

COD Mod r/m deplasament operand2 - instr 6 octeti MOV X[SI],5230

In toate cazurile de mai sus implicit la adresa relativa se aduna continutul reg. DS.
Daca se doreste sa se specifice al registru segment decat cel implicit DS sau SS pentru stiva, se adauga in
fata un octet suplimentar care specifica reg.segment explicit.

MOV AX,ES : [BX+5000] operandul se ia din segmentul indicat de ES

Codul instructiei este pe 1 octet si are structura de baza :

i Cod instr d w i=1 – instructiune imediata


d=1 – rezultatul in registru d=0 –rezultatul in memorie
w=1 - operand pe 16biti w=0 - operand pe 8 biti

Instructiunile care fac referire la memorie contin o extensie de cod notata Mod r/m care specifica modul de
adresare folosit (reg-reg, bazata, indirecta,indexata) si are structura:

MOD r/m Mod - 2cb – modul de adresare folosit


00 – deplasament 0 MOV AX,[BX]
01 – deplasament pe 8cb MOV DX,[BX+25]
10 – deplasament pe 16cb MOV DX,[BX+2500]
11 – adresare reg- reg si r/m pe 3cb specifica reg destinatie
reg - 3cb codul registrului sursa utilizat
r/m - 3cb indica modul de adresare
000 adresarea este data de [BX+SI+depl]
001 adresarea este data de [BX+DI+depl]
010 adresarea este data de [BP+SI+depl]
011 adresarea este data de [BP+DI+depl]
100 adresarea este data de [SI+depl]
101 adresarea este data de [DI+depl]
110 adresarea este data de [BP+depl]
111 adresarea este data de [BP+DI+depl]

Combinatia Mod=00 si r/m=110 indica o adresare directa.

6cb 2cb 3cb 3cb 8-16cb 8-16cb


COD d w Mod reg r/m Depl/data data

Codificarea registrelor in zona reg si r/m este :

reg si r/m w=1 w=0 Registre


reg. pe 16cb reg. pe 8cb reg pe 32cb segment
000 AX AL EAX ES

5
001 CX CL ECX CS
010 DX BL EDX SS
011 BX DL EBX DS
100 SP AH ESP FS
101 BP CH EBP GS
110 SI DH ESI
111 DI BH EDI
PUSHA salveaza toare registrele in ordinea data de codul registrului.

Pentru utilizarea registrelor pe 32 biti se introduce un octet extensie de cod si inca unul pentru utilizarea
adreselor pe 32 biti.

Pentru exercitii se va folosi programul de depanare AFD si se vor studia structurile instructiunilor utilizate.
Adresele din memorie au octetii inversati.
Specificarea lungimii operandului cand nu rezulta din reistrul folosit se specifica prin :
/B pentru un octet si /W pentru 2 octeti (word).

ADD W/[BX],50 operandul se consider ape 2 octeti

Pentru exercitii se pot folosi instructiunile de mutare, aritmetice si logice pe 1 sau 2octeti.
MOV reg_dest,reg_sursa transfer intre registre
MOV reg,[adresa] transfer din memorie in registru (citire din memorie)
MOV [adresa],reg transfer din registru in memorie (memorare registru)
MOV reg,valoare incarcare imediata in registru
MOV adresa,valoare memorare imediata in memorie
Cand se specifica adresa, ea poate fi directa, indirecta,sau/si indexata.
PUSHA memorare toate registrele in stiva
POPA incarcare toate registrele din stiva
ADD dest,sursa se aduna sursa la destinatie cu un singur operand in memorie
SUB dest,sursa se scade din destinatie sursa
AND dest,sursa operatia logica SI intre sursa si destinatie
OR dest,sursa operatia logica SAU intre sursa si destinatie
XOR dest,sursa operatia logica SAU EXCLUSIV intre sursa si destinatie

6
1.5. Utilizare AFD (Advanced Full screen Debuger)

Exista mai multe ferestre deplasarea cu tastele F4 sus, F8 jos,F9 stinga, F10 dreapta
In fiecare fereastra se poate modifica direct pe ecran continutul registrelor, adreselor de memorie, a
continutului celulelor de memoriei.
Schimband adresa sau reg.segment se schimba zona de memorie afisata.
Valorile din register si memorie sunt reprezentate in hexazecimal.
Fereastra din dreapta jos da continutul ASCII al locatiilor de memoriei din fereastra 2.
F4 afiseaza Help-ul programului
F1 Step executa o instructiune de program( pas de program).
F1 StepProg executa un program terminat cu INT 3 (termina un task si revine in AFD).
Fereastra CMD de comanda permite introducerea de comenzi :
D adresa -afiseaza in hexa si in limbaj de asamblare o zona de program.
R reg=val initializeaza registre
M n adresa afiseaza zona de memorie in fereastra 1 sau 2 (n=1,2)
A adresa asambleaza un program de la adresa (>100), reg seg. CS (Exit-Ctr/Home)
G adresa lansare un program de la adresa bazata cu CS (oprire cuCtr/Esc)
L prog incarca un program .exe in memorie la adresa
W fis,adr,lung scrie intr-un fisier o zona de memorie de lungime specificata
QUIT terminare AFD si iesire in DOS sau Windows

7
2. INSTRUCŢIUNI ARITMETICE SI LOGICE
2.1. Instrucţiuni de mutare
Instrucţiunile de mutare realizează transferul datelor intre registre, intre registre şi memorie, intre
registre şi stiva. Transferurile se pot executa intre registre de aceeaşi lungime, iar la transferul intre
registre şi memorie lungimea este dată de registrul folosit.
Instrucţiunile de mutare nu modifică indicatorii de condiţie.
Toate mutările se pot face pe 1,2,4 sau 8 octeţi. Mutările sunt de forma:

MOV destinaţie, sursă - unde ca argumente putem avea combinaţiile:

reg,reg - transfer intre registre pe 1, 2, 4 octeţi


reg,const - încărcare imediata constanta intr-un registru
mem, const - încărcare imediata constanta intr-o adresa de memorie
reg,mem - încărcare conţinut adresă de memorie într-un registru
mem,reg - memorare conţinut registru într-o locaţie de memorie
mem,mem - !! este o combinaţie interzisă fiindcă nu pot fi doua adrese în instrucţiune

Prin mem vom înţelege o locaţie de memorie specificată prin orice mod de adresare (directă,
indirectă, indexată). La indexare se pot folosi numai registrele SI si DI, iar la adresarea cu bază se pot folosi
numai BX şi BP. La toate adresările se foloseşte un registru de segment implicit sau explicit. Registrele
segment implicite sunt:
CS - pentru instrucţiunile de salt în program
DS - pentru toate datele utilizate
SS - pentru adresarea stivei prin SP (Stack Pointer) sau când baza este BP.

Exemple:
MOV CL,DH - reg-reg pe 1 octet unde orice combinaţie este posibilă
MOV SI,DX - reg-reg pe 2 octeti aproape orice combinaţie este posibilă
MOV EDX,EBX - reg-reg pe 4 octeti
MOV BP,3420 - încărcare imediata constanta intr-un registru pe 2 octeţi
MOV ECX,3420 - încărcare imediata constanta intr-un registru pe 4 octeţi
MOV b/[4200],54 - încărcare imediata const. intr-o adresa de mem. pe 1 octet
MOV w/[4200],54 - încărcare imediata const. intr-o adresa de mem. pe 2 octeţi
In memorie constanta 0054 se va memora pe cei 2 octeţi inversaţi 5400.
Inversarea se produce la orice memorare de registru si la orice citire din memorie.
MOV BX,[3450] - încărcare conţinut adresă de memorie intr-un reg. pe 2 oct.
MOV EBX[3450] - încărcare conţinut adresă de memorie intr-un reg pe 4 oct.
MOV [2400],DS - memorare conţinut registru într-o locaţie de memorie
MOV X,DX - memorare conţinut reg. într-o locaţie de memorie in ASM
MOV [BX],DX - memorare conţinut reg. într-o locaţie de memorie indirect
MOV DX,X[SI] - încărcare reg. din memorie cu adresă indexata din tabel X
MOV CX,[BX+SI+5]- încărcare reg. din memorie cu adresa indirecta si indexata

Când nu se poate da implicit prin registru lungimea în AFD se precizează explicit prin:
b/ - byte (1 octet) şi w/ - word(2octeţi).
În limbajul de asamblare (ASM sauTASM) lungimea explicită a operanzilor se dă prin:
MOV byte ptr[BP+5],25 - încărcare imediata in memorie pe 1 octet
MOV word ptr[BP+5],25 - încărcare imediata in memorie pe 2 octeţi (word)

8
MOV dword ptr[BP+5],25 - încărcare imediata in memorie pe 4 octet (double word)
MOV qword ptr[BP+5],25 - încărcare imediata in memorie pe 8 octet (quadword)
MOV tbyte ptr[BP+5],25 - încărcare imediata in memorie 10 octeţi(ten byte la VF)

XCHG operand1,operand2 (XChange)


- Instrucţiune de interschimbare operand1 cu operand2
Pentru operand1 si operand 2 se păstrează toate posibilităţile de la instrucţiunea MOV.
Ex: MOV AX,DX - se schimba conţinutul registrelor AX cu DX
MOV BX,X - se schimba conţinutul registrelor AX cu variabila X
Instrucţiunea NOP este echivalentă cu XCHG AX,AX

Adresarea stivei (PUSH şi POP)


Stiva este o zonă de memorie adresată prin registrul SP care indică elementul din vârful stivei (top).
In stivă se ia din vârful stivei si apoi se incrementează SP.
Când se pune în stivă întâi se decrementează SP şi după aceea se memorează valoarea.
PUSH reg16 - pune în stivă un registru pe 16 biţi (PUSH BX)
POP reg16 - încarcă din stivă un registru pe 16 biţi (POP BX)
PUSH reg32 - pune în stivă un registru pe 32 biţi (PUSH EBX)
POP reg32 - încarcă din stivă un registru pe 32 biţi (POP EBX)
PUSH mem - pune în stivă conţinutul unei locaţii de memorie pe 16 biţi
Este foarte utilă la transmiterea parametrilor spre subprograme (PUSH X).
PUSH constanta - pune în stivă o constantă pe 16 biţi
PUSHA - pune în stivă toate registrele pe 16 biţi (AX;BX;CX,...)
POPA - încarcă toate registrele pe 16 biţi din stivă (starea programului)
PUSHAD - pune în stivă toate registrele pe 32 biţi (EAX;EBX;ECX,...)
POPAD - încarcă toate registrele pe 32 biţi din stivă
PUSHF - pune în stiva registrul FLAGS (indicatorii de condiţie)
POPF - încarcă di stivă registrul FLAGS
PUSHFD - pune în stiva registrul EFLAGS
POPFD - încarcă di stivă registrul FLAGS

STIVA 0
PUSH BX SP=SP-2 si BX [SP]
POP BX [SP] BX si SP=SP+2
SP BX Top vârful stivei
Alpha
N Y

LEA reg,adresa - (Load Effectiv Adress)


- Instrucţiunea calculează adresa relativa si o memorează in registru utilizat.

Ex: LEA AX,[BX+SI+15] - adresa operandului este memorata in AX

Este echivalenta cu: MOV AX,offset adresa offset = adresa relativa calculata
La coprocesor nu exista dispozitiv de calcul al adresei si se poate folosi LEA

9
LDS reg16,dwpointer - reg16=offset adresa DS= adresa segment
LES reg16,dwpointer

Încarcă registrul segment DS sau ES si registrul general de la o adresa de 4 octeţi unde se găseşte
adresa relativa a operandului si adresa segmentului din care face parte. Se foloseşte la comunicarea intre
segmente pentru pregătirea registrelor de segment.

dwpointer ofsset Adresa Adresa segment LDS SI,dwpointer

SI DS sauES

2.2. Instrucţiuni aritmetice şi logice


Instrucţiunile aritmetice şi logice pot fi executate pe 1,2 sau 4 octeţi şi sunt de forma:

Adunare ADD
Adunare cu carry ADC reg,reg
Scădere SUB reg,mem
Scădere cu SBB dest,sursa mem,reg Lungime
împrumut (borow) reg,const 1, 2 sau 4
SI logic pe bit AND mem,const octeţi
SAU OR
SAU Exclusiv XOR
Comparaţie (scadere) CMP
Comparaţie cu SI TEST

Toate instrucţiunile aritmetice şi logice poziţionează indicatorii de condiţie funcţie de valoarea


rezultatului. Rezultatul poate fi si in memorie
Z=1 rez=0 sau operanzii sunt egali la comparaţie
S=1 rez<0
S=0 si Z=0 rez>0 - NU zero si NU negativ
C=1 transport din rangul cel mai semnificativ. La instrucţiunile logice C=0
O=1 rezultatul depăşeşte capacitatea
P=1 numărul biţilor de 1 din rezultat este par

Instrucţiunile logice se fac bit cu bit iar indicatorii se poziţionează funcţie de întregul rezultat. Pentru a
selecta un bit sau un grup de biţi din rezultat se foloseşte o mască.
C=1 nu înseamnă depăşire.
Depăşirea poate apărea la adunarea numerelor de acelaşi semn şi S diferă de acest semn.
La adunarea numerelor negative apare obligatoriu C=1 fără a fi depăşire.

1001 AND + 35 42 + 75 4E 1101+ -3


1100 - E1 24 + 77 14 1111 -1
1000 Rez1 1 16 66 Rez>0 - EC 62 Rez<0 11100 -4
1000 Masca C=1 S=1 C=1
1000 Rez # 0 nu Depasire si nu

10
depasire transfer spre S depas.

Comparaţia CMP dest,sursa face scădere dest-sursa fără a modifica dest, dar cu poziţionarea indicatorilor
funcţie de rezultatul scăderii.
S=0 dest > sursa S=1 dest < sursa Z=1 dest=sursa

Comparaţia TEST dest,sursa face un SI logic intre biţii din dest şi sursă fără a modifica dest, dar cu
poziţionarea indicatorilor funcţie de rezultat.
Z=1 toţi bitii din rezultat sunt 0, Z=0 cel puţin un bit din rezultat este 1 (S nu are sens)
Indicatorii de condiţie se pot modifica prin program:

Instrucţiune Operaţie Observaţii


CLC C=0 Pune Carry pe 0 (Clear Carry)
STC C=1 Pune Carry pe 1 (Set Carry)
CMC C= ~C Complementează carry
CLD D=0 Pune D pe 0 (Clear Direction)
STD D=1 Pune D pe 1 (Set Direction)
CLI I=0 Pune I pe 0 (Clear Interupt) dezautorizează întreruperile
STI I=1 Pune I pe 1 (Set Interupt) autorizează întreruperile
LAHF AH=Flag Încarcă Flags în AH (Load Flags from AH)
SAHF Flag=AH Pune AH in Flags (Store AH in Flags)

Instrucţiunile LAHF şi SAHF sunt folosite pentru a prelua indicatorii de condiţie din coprocesor şi ai testa
in procesor folosind instrucţiunile de salt condiţionat JZ. Reamintim că nu exista instrucţiuni de salt la
coprocesor.

Instrucţiuni cu un operand sunt de tip logic sau aritmetic:

NOT - complementare operand faţă de 1


NEG Reg - complement operand faţă de 2 (negativ) Operand pe
DEC Mem - decrementare operand 1, 2, 4 sau 8biţi
INC - incrementare operand

2.3. Operaţii în zecimal codificat binar (BCD) sau ASCII

Calculele zecimale se fac în binar pe un octet, utilizând obligatoriu registrul AL şi sunt urmate de o
corecţie zecimală. Corecţiile zecimale nu au argumente şi folosesc informaţii din indicatorii de condiţie C
şi AC (auxiliar carry).

AAA Ajustare pentru Adunare ASCII


DAA Ajustare pentru Adunare BCD (Binary Coded Decimal)
AAS Ajustare pentru scădere ASCII
DAS Ajustare pentru scădere BCD
AAM Ajustare pentru înmulţire ASCII
AAD Ajustare pentru împărţire ASCII (divide)

11
Corecţia constă în a aduna 6 la cifrele hexa ale rezultatului care depăşesc 10.
Vom exemplifica pentru DAA si AAA

DAA AAA
operanzi BCD 54 + operanzi 34+
78 ASCII 38
Rezultat binar CC + 6C
Corecţie +auxcarry 66 corecţie 6
Rezultat zecimal 32 Forţează 0 si C=1 02 +
30
Rezultat ASCII afişabil 32

Program 1 de adunare pe 16 biţi a elementelor a două tablouri X şi Y şi memorarea rezultatului în Z. Vom


considera 8 elemente într-un tablou şi tablourile plasate la adresele hexa X la DS:0, Y la DS:10 şi Z la
DS:20.
Z(I)=X(I)+Y(I)

DS:0 X DS:10 Y DS:20 Z


0 X(1) 0 Y(1) 0 Z(1)
2 X(2) 2 Y(2) 2 Z(2)
SI 4 X(3) SI 4 Y(3) SI 4 Z(3)
6 6 6
.. .. ..

0C X(7) 0C Y(7) 0C Z(7)


0E X(8) 0E Y(8) 0E Z(8)

Folosind AFD putem scrie programul de la adresa 100 şi îl terminăm cu INT 3.


Selectând zona de memorie DS:0, DS:10 şi DS:20 vom introduce manual valorile pentru elementele
tabelelor X şi Y. Vom lansa în execuţie programul de la adresa 100 şi vom verifica valorile obţinute în
tabloul Z de la adresa DS:20.

Adresa
100 MOV SI,0 ; index I=1 –registrul de segment implicit este DS
103 MOV CX,8 ; contor pentru cicluri (număr de elemente tablou)
106 MOV AX,[SI+0] ;AX=X(I)
109 ADD AX,[SI+10] ;AX=X(I)+Y(I)
10C MOV [SI+20],AX ; memorare rezultat la Z(I)
10F ADD SI,2 ; incrementare index pentru rândul următor(I=I+1)
112 LOOP 106 ; salt pentru CX # 0 şi face CX=CX-1
114 INT 3 ; terminare program si revenire in AFD

Pogram 2 de adunare a doua numere zecimale BCD sau ASCII de lungime 8 octeţi.
Adunarea se va face din dreapta spre stânga octet cu octet. Se memorează in Carry transportul dintre ranguri
si aduna la fiecare rang si carry cu ADC (iniţial C=0). Programul permite operaţii pe orice lungime,
modificând numărul de octeţi (CX)

DS:0 X SI

12
.. 31 35
DS:10 Y +
.. 33 39
DS:20 Z =
.. 35 34

100 CLC ; C=0 - primul rang nu exista transport


101 MOV SI,7 ; SI poziţionat pe ultimul octet
104 MOV CX,8 ; număr de cicluri (număr octeţi)
107 MOV AL,[SI+0] ; X(i)
10A ADC AL,[SI+10] ; AX=X(i)+Y(i)
10D AAA ; sau DAA corecţie zecimala
10E ; OR AL,30 ; corecţie ASCII modifica carry
110 MOV [SI+20],AL ; memorează cifra rezultat in Z(i)
113 DEC SI ; cifra următoare
114 LOOP 107 ;
116 MOV SI,0 ; corecţie ASCII pentru afişare
119 MOV CX,8 ; număr de cicluri (octeţi)
C2: ADD b/[SI+20],30 ; corecţie ASCII cifra Z(i)
INC SI
LOOP C2
INT 3 ; terminare program

2.4. Instrucţiuni de înmulţire si împărţire

Operaţiile aritmetice sunt definite în dispozitivul aritmetic pentru numere subunitare, dar pentru
adunare şi scădere sunt valabile şi pentru numerele binare întregi. Considerăm 2 numere întregi A şi B
pentru care facem o adunare pe 16 biţi. Din punct de vedere al dispozitivului aritmetic adunarea se face ca
pentru numere subunitare cu virgula după bitul de semn şi avem:

A*(2**-15)+ Operand1 subunitar


B*(2**-15) Operand2 subunitar
(A+B)*(2**-15) Rezultat subunitar

Ca sa obţinem rezultatul corect in întreg (A+B) trebuie ca rezultatul sa-l înmulţim cu 2**15 adică sa
deplasam virgule cu 15 cifre binare spre dreapta.

(A+B)=(A+B)*(2**-15)*2**15

15 ……2 1 0
S
Virgula zecimala pt nr. întreg
Virgula zecimala pentru nr. subunitar

Operaţiile de înmulţire şi împărţire se pot face cu operanzi pe 1,2 sau 4 octeţi.

13
Sunt instrucţii cu un singur operand, deînmulţitul/deîmpărţitul este implicit în registrul acumulator (Al, AX,
EAX), iar celălalt operand poate fi într-un registru sau în memorie.

MUL Operand AX=AL * operand - înmulţire fără semn


IMUL pe 1,2,4 oct. DX:AX=AX*operand - înmulţire de întregi cu semn
EDX:EAX=EAX*operand

Rezultatul înmulţirii este de lungime dublă faţă de operanzi şi se obţine pentru operanzi pe 16biţi în DX şi
AX în prelungire.
La înmulţire numerele se consideră subunitare şi niciodată nu poate apare depăşire.
La IMUL (înmulţire de întregi cu semn) se face o corecţie de deplasare spre dreapta a rezultatului cu o
poziţie binară. Numerele sunt văzute ca subunitare şi avem:

(X*(2**-15) * (Y*(2**-15)= (X*Y)*2**-30

Pentru ca rezultatul sa fie corect în întreg virgula trebuie deplasată cu 30 poziţii spre dreapta, deci în faţa
ultimei cifre binare. Rezultatul obţinut trebuie împărţit la 2, care echivalează cu o deplasare dreapta cu un
bit.

IMUL
15 0
AX S X X - număr întreg în AX (X*(2**-15)
*
Op16 S Y Y – număr întreg pe 16biţ (Y*(2**-15)
31 = 0
Rez 32cb S X* Y 0 Rezultat X*Y pe 32 biţi în DX şi AX
DX AX (X*Y)*2**-30 necesare 30 depl.dreapta
Virgula ca nr.zecimal - virgula ca număr întreg

Impărtirea presupune ca deîmpărţitul este în registrul acumulator (AX, DX:AX sau EDX:EAX)
împărţitorul este într-un registru sau memorie.

DIV operand AX / operand8 - înpărţire fără semn


AL –cât, AH -rest
IDIV pe 1,2,4 oct. DX:AX / operand16 - înpărţire de întregi cu semn
(împărţitor) AX-cât, DX -rest
EDX:EAX / operand32

La împărţire trebuie să avem deîmpărţitul < împărţitorul văzute ca numere subunitare fiindcă rezultatul
trebuie să fie subunitar. În caz contrar avem depăşire.
In figură văzut ca subunitar 4250 < 35 şi nu apare depăşire .
Restul are semnul deîmpărţitului.

IDIV 1 0
5
DX:AX S X 4250 X - număr întreg în AX (X*(2**-30)

14
/
Op16 S Y 35 Y – număr întreg pe 16biţ (Y*(2**-15)
3 = 0
1
Rez 16biţi S Rest Cât Rezultat X/Y pe 16 biţi
DX AX în DX -rest şi AX – cât
Virgula ca nr.zecimal - virgula ca număr întreg

La împărţire numărul din AX trebuie extins spre stânga în DX, prin copierea bitului de semn. Operaţia se
face prin intrucţiunile:
CBW - Convert Byte to Word - extindere AL pe AX
CWD - Convert Word to Double word - extindere AX pe DX:AX
CDQ - Convert Double word to Quad word - extindere EAX peEDX:EAX
Există şi instrucţiuni de extindere cu Zero MOVZX sau cu Semn MOVSX prin mutare:
MOVSX CX,BL
MOVZX EAX,CX
MOV AX,4520
CWD - extindere pe DX:AX
IDIV CX - Cât în AX şi Rest în DX

Exemplu de calcul expresie: E=(A*B+C)/(A+B) unde A,B,C sunt numere întregi 16 biţi

MOV AX,A

IMUL word ptr B ; rezultatul A*B în DX:AX


ADD AX,C ; se aduna C la AX ştiind ca rezultatele nu depăşesc 2 octeţi(16biti)
MOV BX,A
ADD BX,B ; BX=A+B
CWD ; extensie AX pe DX pentru împărţire
IDIV BX cat in AX=AX/BX restul in DX
MOV CAT,AX ; memorare cat
MOV REST,DX ; memorare rest

2.5. Instrucţiuni de deplasare


Instrucţiunile de deplasare se fac numai în registre pe 1,2 sau 4 octeţi.
Deplasările pot fi: - spre stânga sau spre dreapta
- logice sau aritmetice
- deschise sau circulare (Rotate)
Deplasarea se face cu un număr de biţi (1-32) dat în registrul CL sau în instrucţiune.

SAL Shift Aritmetic Left - deplasare deschisă


SHL Shift (logic) Left
SAR Reg,1 Shift Aritmetic Right
SHR Reg,n Shift (logic) Right
ROL Reg,CL Rotate (logic)Left - deplasare circulară
ROR Rotate (logic) Right
RCL Rotate (logic)Left whith Carry
RCR Rotate (logic) Right whith Carry

15
Deplasările aritmetice - spre stânga se consideră înmulţiri cu 2**N ţi pot da depăşire
- spre dreapta se consideră împărţiri cu 2**N

La toate deplasările biţi care ies din registru trec prin Carry.
Prezentăm în figurile de mai jos modul de efectuare a operaţiilor de deplasare:

SAL Shift Aritmetic Left


C 0 SHL Shift Left

C ROL Rotate Left

C RCL Rotate Left whith Carry

S
0 C SHR Shift logicRight

S C SAR Shift Aritmetic Right


Se recopiază semnul

S
C ROR Rotate Right

S
C ROR Rotate Right whith carry

Testarea unui bit dintr-un registru se face prin deplasarea lui în Carry sau în Semn.
Testarea mai multor biţi dacă sunt pe 1 se poate face prin secvenţa:

MOV AX,X
AND AX,0C0H - masca ce indică primi 2 biţi
CMP AX,0C0H - verifica dacă rezultatul este egal cu masca
JZ OK - cei 2 biţi sunt pe 1

Dacă trebuie verificaţi biţii care sunt pe 0 se face înainte complementarea lui X (NOT).

Testarea unui bit se face şi prin instrucţiunea TEST care face AND între cei 2 operanzi, poziţionează
indicatorii de condiţie, fără a modifica operandul destinaţie. Se poate folosi instrucţiunea imediată cu masca
bitului testat:

16
TEST AX,02H
JNZ bit2 ; bitul 2 din dreapta este 1

TEST X,4000H ; verifică bitul 2 din stânga lui X


JNZ etX2 ; bitul este 1

Testarea unui bit se poate face la procesoarele pe 32 de biţi cu instrucţiuni speciale:


BT - testează bitul indicat şi îl memorează în C (carry)
BTC - testează bitul indicat şi îl complementează (Bit Complement)
BTR - testează bitul indicat şi îl pune pe zero (Bit Reset)
BTS - testează bitul indicat şi îl pune pe 1 (Bit Set)

BT AX,4 ; verifica bitul 4 din AX şi il trece în C (carry)


JC bit4 ; salt pentru bit4=1

3. LIMBAJUL DE ASAMBLARE

Limbajele de asamblare permit scrierea programelor folosind:


 mnemonici pentru instrucţiunile procesorului şi coprocesorului,
 directive pentru descrierea datelor
 directive pentru controlul programului (segmentare, module, proceduri)
 funcţii DOS apelate prin întreruperi
 macroinstrucţiuni definite de utilizator

Pentru procesoarele Intel se folosesc curent asambloarele:


MASM (MacroAssembler) de la Microsoft împreună cu editorul de legături LINK
TASM (TurboAssembler) de la Borland

3.1. Asamblarea programelor

Programul sursă scris în limbaj de asamblare va avea extensia .ASM şi trebuie să treacă prin mai
multe faze pentru a fi transformat în program executabil direct (Prog.EXE).

Include Mod.obj Date

Prog.asm ASAMBLOR Prog.obj LINK Prog.exe Rezultate


sursă obiect EDITOR executabil

Prog.lst Bibl.lib Prog.map EX2BIN Prog.com


Fisier listing

Asamblorul prelucrează un fişier text sursă (Prog.asm), scris cu un editor de texte şi generează un
modul obiect (Prog.obj) care conţine instrucţiuni şi date ce sunt plasate de la adresa 000. Se mai generează
şi un fişier listing al programului compilat (Prog.lst). Programul sursă poate face referire prin directiva
INCLUDE şi la alte fişiere sursă (subprograme), care vor fi înglobate prin copiere în programul sursă.
Modulele obiect nu sunt executabile, dar pot fi depuse in biblioteci (Bibl.lib).
LINK EDITORUL prelucrează modulele obiect obţinute prin compilare (asamblare) şi alte module
obiect din biblioteci. Din asamblarea lor rezultă un program executabil (Prog.exe), în care adresele

17
modulelor şi adresele relative din instrucţiuni sunt recalculate şi se face legătura între modulele care fac apel
la alt modul (subprograme). Adresele din instrucţiuni se recalculează relativ la începutul segmentului ţinând
cont de adresa modulului în segment. Un program poate conţine mai multe segmente. Adresele simbolice
definite în alt modul trebuie date ca EXTRN, iar cele care sun referite din exterior declarate cu PUBLIC.
Asamblorul va genera câte un tabel cu etichetele referite în exterior (EXTRN) şi unul cu etichetele
care pot fi referite din exterior (PUBLIC), în care se specifică adresa lor din modul. Tabelele de definiţii
externe şi referinţe externe se păstrează în modulele obiect şi vor fi folosite de linkeditor pentru rezolvarea
referinţelor externe prin completarea adreselelor care fac referire la etichete din alte module. În fişierul
Prog.map se găsesc noile adrese ale modulelor şi ale etichetelor definite ca externe.
Programul executabil (Prog.exe) poate fi lansat ca o comandă DOS, care prelucrează datele şi se
obţin rezultatele. Prin programul EX2BIN se poate obţine o variantă Prog.com a programului.

Module .obj Referinţe ExternePr1


0 0 Pr1.obj 0 Pr1.exe Simbol Adr.unde Adresa reală
e utilizat
32 jmp c1 c1 32,67,89 20+n1
k 170,230
n1 alfa 60,540
0 Pr2.obj n1

20 c1 mov ax,bx
n2 Definiţii externe Pr2
0 Pr3.obj n1+n2 Simbol Adr.unde
e definit
c1 20

n n3 n

3.2. Scrierea programelor sursă


Linia de program sursă în limbaj de asamblare are structura:

Eticheta: cod_instr arg1,arg2 ; comentariu


directiva arg1,arg2,arg3,.... ; comentariu
Exemplu:
C1: MOV AX,[BX+SI+20] ; - încarcă reg.AX cu un element X(I)
......
X DW 3490,43,780,4000,500 ; iniţializare elemente tablou X

Tipuri de constante
B binare 0111011B
H hexazecimale 0BA56H ; MOV CX,0FFH
O octale 6573Q ; MOV SI,342Q
D zecimal 4586D sau 7500 ; implicit numerele se consideră zecimale

Directive pentru definire date:

DB Define Byte ; definire pe un octet


DW Define Word ; definire pe 2octeţi

18
DD Define Double word ; definire pe 4 octeţi
DQ Define Quadword ; definire pe 8 octeţi
DT Define Ten Byte ; definire pe 4 octeţi
EQU constanta ; da etichetei valoarea constantei
ORG adresa ; forţează contorul de amplasare la adresa specificată
ALIGN n ; unde n=1,2,4,8,16 aliniere contor amplasare la multiplu
INCLUDE fisier.asm ; copiază în acel loc o secvenţă de program (subprogram)

Exemple:
A1 DB 12,0,0ACH,345Q,041H,’TREN rapid’
A2 DW 9542,0DE89H,20,0,’TR’
A21 DW A1,A2 ; se generează adresele relative a lui A1 şi A2
A4 DD 54,89589BAH
A41 DD A1,A2 ; adresele relative a lui A1 şi A2 cu adresa segmentului
A7 DW 20 DUP(20h)
P1 EQU 16 ; eticheta P1 echivalată cu 16 (adresă port)
MOV DX,P1 ; DX=16
CR EQU 0DH ; Cod ASCII CR

Directive de control program


NAME nume_modul ; dă numele modulului compilat
Un modul poate fi o procedură care e cuprinsă între:
nume_proc PROC near sau far ; inceput de procedură
..........
RET [n] ; ieşire din procedură cu eliberare stivă
nume_proc ENDP ; sfârşit de procedură

END start ; directiva de sfârşi de asamblare care dă adresa de lansare program


Atenţie END se pune după ultimul modul din program.

PUBLIC var1,var2,.. ; declarare variabile ca definiţii externe


EXTRN simbol1:tip1, simbol2:tip2,..; declarare referinţe externe spre alte module
Unde tip este – byte, word, dword, qword pentru date specificând lungimea
- near şi far pentru etichete apelate prin Jump sau Call
Tipul permite asamblorului să genereze instrucţiuni pe lungimi corecte. Menţionăm că în limbaj de
asamblare nu există tipuri întregi, reale, logice, caracter ca în alte limbaje.
E2 LABEL far sau near ; definire explicită etichete locale (near) sau externe (far), care se pot
apela din exterior.
Etichetele locale – near se pot specifica urmate de două puncte(:)

Definire segmente
Un segment este cuprins între directivele SEGMENT şi ENDS
nume_seg SEGMENT [align],[combinare],[’clasa’]
....
nume_seg ENDS
align - page - segmentul începe la multiplu de 256
- para - multiplu de 16 (paragraf)
- word - multiplu de 2
- byte - multiplu de 1

19
Combinarea cu alte segmente:
- none -implicit
- public
- common - segmente care se încarcă în paralel în aceeaşi zonă de memorie
- memory -segmente tratate împreună de editor şi plasate la sfârşitul memoriei
- AT adresa - specifică adresa la care se încarcă segmentul
- stack - segment definit ca stivă şi tratat ca public ( bazat cu SS)
ASSUME CS:seg1,DS:seg2,ES:seg3,SS:seg4 precizează registrele segment utilizate la adresarea
datelor din fiecare segment.

Programul următor conţine un singur segment mixt code+date+stiva.


; ---------------------------------------------------Lab3_0.doc
; Scadere doua numere zecimale codificate binar
; de lungime n Z=X-Y
; considerate ca tablouri
; ---------------------------------------------------
pr1 segment
assume cs:pr1,ds:pr1,ss:pr1 ; există un singur segment mixt
st1:
mov ax,pr1 ; initializare registre segment
mov ds,ax
mov ss,ax
mov sp,offset stiva ; iniţializare pointer stiva
mov cx,8 ; numar cifre zecimale
mov si,7 ; index ultima cifra
e1: mov al,x[si]
sbb al,y[si] ; X(I) - Y(I)
das ; corectie zecimala pt.scadere
mov z[si],al ; memorare octet rezultat
dec si ; index octet urmator
loop e1 ; ciclu pina CX > 0
int 3 ; revenire in afd (terminare)
; zona memorie pentru date
; -------------------------------------
x db 32h,13h,33h,72h,29h,46h,51h,29h ; descazut
y db 29h,14h,66h,75h,19h,83h,25h,11h ; scazator
z db 8 dup(0) ; rezultat
; Zona pentru stiva
; -------------------------------------
db 256 dup(?) ; rezervare spaţiu stiva
stiva equ $ ; vârful initial al stivei - $ este adresa curenta contor amplasare
pr1 ends
end st1 ; adresa lansare program

Dacă programul conţine numai câte un segment de fiecare tip se poate simplifica scrirea specificând
unde începe segmentulde code .CODEde date DATA şi stivă .STACK. Rezervarea spaţiului pentru stivă se
face pe lungimea dată şi automat se încarcă reg.SS.

20
Modulul de date se numeşte implicit @DATA referit pentru încărcare registru segment DS. Dacă se
scriu programe complexe cu multe segmente de diferite tipuri trebuie să se utilizeze segmentarea explicită
prin definire segmente cu nume cu directiva SEGMENT.

; ---------------------------------------------------Lab3_1.doc
; Programul numara bitii de 1 din fiecare element
; al tabloului X si memoreaza numarul de biti
; in elementele tabloului NX
; ---------------------------------------------------
Dosseg ; mod DOS de tratare segmente
.model small ; model pe cu segmente de 64Ko
.stack 256 ; rezervare 256 octeti pentru stiva
; Segmentul de date
; -------------------------------------
.data
X dw 7676h,9541h,5463h,2234h,0FFEEh
NX db 5 dup(0) ; nr biti elemente tab X
N equ 5 ; numar elemente tablou X
; Segmentul de code al programului
; -------------------------------------
.code
st1: mov ax,@data ; initializare registrul segment de date DS
mov ds,ax ;
mov si,0 ; index in tabloul X
mov di,0 ; index in tabloul NX
mov dh,N ; nr. elemente tablou
; Ciclu pentru numarare biti element X(I)
c1: mov ax,X[si] ; incarcare element X(I)
mov cx,16 ; numar ranguri binare
c2: shl ax,1 ; deplasare stinga cu un rang
jnc c3 ; bitul este zero
inc NX[di] ; bitul este 1
c3: loop c2 ; urmatorul rang
add si,2 ; urmatorul elment din X(I)
inc di
dec dh ; verificare sfirsit tablou X
jnz c1
int 3 ; terminare program
end st1 ; adresa lansare program

4. INSTRUCŢIUNI DE CONTROL AL PROGRAMULUI


4.1. Instrucţiuni de salt

Programul execută calcule şi funcţie de rezultatele obţinute, se poate ramifica utilizând instrucţiunile
de salt condiţionat şi necondiţionat.

21
După fiecare instrucţiune aritmetică sau logică, funcţie de valoarea rezultatului se poziţionează
indicatorii de condiţie, care pot fi testaţi de instrucţiunile de salt condiţionat. Trebuie menţionat că
instrucţiunile de mutare şi cele de salt nu modifică indicatorii.

Salt necondiţionat JMP (Jump)

Saltul constă în memorarea adresei de destinaţie a saltului în reg. IP (Instruction Pointer).


Există 3 tipuri de salt necondiţionat direct:
Short Jmp - salt scurt cu +127 până la -127 faţă de IP (instrucţiunea curentă)

Cod instr Deplasament


EB -50 Short Jmp deplasament pe 1 octet
IP=IP-50
JMP short etich1

Near Jmp - salt în segmentul curent cu -32K până la +32K faţă de IP

Cod instr Deplasament


E9 25400 Near Jmp deplasament pe 2 octet
IP=IP+25400
Far Jmp - salt în afara segmentului curent şi trebuie modificat IP şi reg. CS
JMP etich2

Cod Deplas. in segm Reg CS


EA 4200 Adresa segment Far Jmp deplasament pe 4 octeţi
IP=4200 CS=adresa segment

Saltul de tip far (îndepărtat) se face între segmente şi se modifica atât IP cât şi registrul de segment CS în
care se încarcă adresa segmentului care conţine eticheta destinaţie.

S1 SEGMENT
EXTRN et5:FAR - definire et5 ca etichetă externă
......
JMP far ptr et5 - salt în segmentul S2 care conţine eticheta et5
.....
S2 SEGMENT
PUBLIC et5 - definire eticheta et5 ca definiţie externă
Et5 LABEL FAR - definire eticheta et5

Salturi indirecte prin registre

La salturile indirecte adresa la care se face saltul se specifică într-un registru. Adresa poate sa să se
refere la un tabel de adrese de salt care pot fi selectate prin modificarea dinamică a registrului folosind
indexarea.

JMP BX - adresa de salt este conţinută în BX

MOV BX,offset et6 - adresa etichetei et6 se încarcă în BX


JMP BX - salt la eticheta et6 din segment (near)

22
JMP word ptr [BX] - BX conţine adresa unei tabele de adrese de salt

JMP dword [BX] - tabela de adrese de salt este de tip FAR(CS:IP)

MOV BX,offset Tadr1 - încarcă în BX adresa unei tabele de adrese de salt


ADD BX,SI - adună poziţia adresei de salt dorite din tabel(* 2 )
JMP word ptr [BX] - salt la adresa et1, et2 sau et3 locale
.....
MOV BX,offset Tadr2 - în BX adresa unei tabele de adrese de salt de tip FAR
ADD BX,4 - adună poziţia adresei de salt dorite din tabel(*4)
JMP dword ptr [BX] - salt la adresa et6 din alt segment
.....

Tadr1: DW et1 - tabel de etichete locale in segment pe 16 biţi(near)


DW et2
DW et3
........
Tadr2: DD et5 - tabel de etichete de tip FAR pe 32 biţi(near)
DD et6 ce conţin şi adresa segmentului
DD et1 - chiar dacă este etichetă locală este pe 4 octeţi

In exemplul de mai sus s-au generat 2 tabele cu adrese de salt. Tabela Tadr1 conţine adrese locale în
segment generate pe 16 biţi (NEAR) ce vor fi încărcate în IP, iar Tadr2 conţine adrese de tip FAR generate
pe 4 octeţi care conţin adresa relativă în segment (deplasament) şi adresa segmentului din care face parte
eticheta şi care va fi încărcată în registru CS. Eticheta et1 care este locală, în Tadr1 se generează pe 2 octeţi
iar în Tadr2 se generează pe 4 octeţi fiindcă face parte dintr-un tabel de adrese de tip FAR.
In registru BX s-a încărcat tabela de adrese locale pe 16 biţi Tadr1 şi în registrul SI adresa relativă a
unei adrese de salt din tabelă ca multiplu de 2. La JMP word ptr [BX] se sare la una din adresele et1,et2 sau
et3. Prin word ptr se precizează că adresele de salt sunt pe 2 octeţi şi valoare se încarcă în registru IP. La
JMP far ptr [BX] se apelează o adresă din tabela Tadr2 şi primi 2 octeţi se încarcă în IP iar următorii 2 în
CS.

4.2. Salturi condiţionate

Instrucţiunile de salt sunt de tip SHORT (+127 la -127) sau NEAR ( procesoa-rele pe 32 de biţi)
şi pot referi etichete numai din segmentul curent. Ele nu pot referi etichete din alt segment. Forma generală
a instrucţiunii este:

Jcond eticheta - dacă condiţia este îndeplinită salt la eticheta specificată

Instrucţiunile aritmetice şi logice poziţionează indicatorii de condiţie funcţie de valoarea rezultatului,


care pot fi testaţi de instrucţiunile de salt condiţionat. La instrucţiunile de comparare se va ţine cont ca se
face o scădere dest - sursa.
Rez < 0 S=1
Rez >0 S=0 si Z=0
Rez=0 Z=1

23
Transport C=1
Paritate para P=1 - numărul biţilor de 1 este par
Depăşire O=1

Prezentăm mai jos principalele mnemonice pentru instrucţiunile de salt condiţionat:

Instrucţiunea Condiţie Comentarii


testată
JS sau JL S=1 Salt la Rez<0 Jump on Sign/Low
JNS sau JGE S=0 Salt la Rez>=0 Jump No Sign/Greater or Equal
JZ sau JE Z=1 Salt la Rez=0 Jump if Zero/Equal
JNZ sau JNE Z=0 Salt Rez # 0 Jump if Not Zero/Equal
JG S=0 si Z=o Salt la Rez>0 Jump Greater
JLE S=1 or Z=1 Rez<=0 Jump if Low or Equal
JC C=1 Salt la transport Jump on Carry
JNC C=0 Salt la Nu transpot Jump if Not Carry
JA C=0 si Z=0 Salt la mai mare Jump if Above (comp. fara semn)
JAE C=0 Salt la mai mare/egal Jump if Above or Equal
JB C=1 Salt la mai mic Jump if Below
JBE C=1 or Z=1 Salt la mai mic/egal Jump if Below or Equal
JP sau JPE P=1 Salt la paritate para Jump Parity Even
JNP sau JPO P=0 Salt la paritate impara Jump Not Parity/ Parity Odd
JO O=1 Salt la depasire Jump if Overflow
JNO O=0 Salt la Nu depasire Jump if Not Overflow
JCXZ CX=0 Salt la CX=0 Jump if CX=0
JECXZ ECX=0 Salt la ECX=0 Jump if ECX=0
LOOP CX # 0 Salt pentru CX # 0 CX=CX-1 si Jump pentru CX#0
Salturile JA, JAE, JB si JBE se refera la comparaţii unde elementele sun fără semn.

Instrucţiunile SETcond memorează 1 la adresa daca se îndeplineşte condiţia testată:


SETS adresa pune 01H la adresa daca S=1
Salturi pentru control cicluri
LOOP adr ; CX=CX-1 şi salt dacă CX # 0
LOOPZ adr ; CX=CX-1 şi salt dacă Z=1 şi CX # 0
LOOPE ; ieşire pentru CX=0 sau Z=0

LOOPNZ adr ; CX=CX-1 şi salt dacă Z=0 şi CX # 0


LOOPNE ; ieşire pentru CX=0 sau Z=1

4.3. Proceduri

Programarea modulară presupune utilizarea subprogramelor, care asigură o dezvoltare ulterioară


simplă a programului şi o depanare uşoară. O procedură este o secvenţă de instrucţiuni care execută un
algoritm pe baza unei descrieri formale. Avantajul procedurilor este că ele sunt reutilizabile.
In limbaj de asamblare există proceduri (nu există funcţii), definite cu directiva PROC şi terminate
cu ENDP. Revenirea din procedură în programul chemător se face cu instrucţiunea RET. Chemarea unei
proceduri se face cu instrucţiunea CALL.

24
Parametrii procedurii se plasează înaintea chemării în registre, intr-o zonă de memorie sau în stivă.
La scrierea procedurii se stabileşte modul de transmitere a parametrilor. Parametrii pot fi transmişi prin
valoare sau prin adresă. Tehnicile de transmitere a parametrilor spre subprograme se vor discuta în capitolul
4.
Vom exemplifica cu utilizarea unei proceduri care face media a 2 numere întregi X şi Z care se
plasează în registrele AX şi BX. Rezultatul se obţine la ieşirea din procedură în AX şi se va plasa la
revenirea în programul principal în variabila Z.
DOSSEG
.MODEL SMALL
.STACK 100H
.DATA
X DW 2540
Y DW 15417
Z DW 0 ; Z=(X+Y)/2 rezultat
C2 DW 2 ; constanta 2
.CODE
; Pregătire parametrii...
ST1: MOV AX,X ; primul parametru
MOV BX,Y ; parametru 2
CALL Pmed ; chemare subpr. Adr.de revenire în stivă (Top stiva=IP)
MOV Z,AX ; memorare rezultat
...
Pmed PROC NEAR ; procedură locală (near)
ADD AX,BX ; AX= X+Y
CWD ; se putea SHR AX,1
IDIV C2 ; AX=(X+Y)/2
RET ; revenire în program la adresa de revenire din stivă (IP=Top stivă)
Pmed ENDP ; sfârşit procedură
END ST1

La chemarea unui subprogram prin CALL, se pune adresa de revenire (IP) în stivă şi se sare la
prima instrucţiune din procedură (IP=offset Pmed). In procedură se execută secvenţa de instrucţiuni până la
instrucţiunea RET, care încarcă în IP adresa din vârful stivei revenind la instrucţiunea următoare după
CALL.
Instrucţiunea CALL se deosebeşte de JMP doar că depune în stivă registru de instrucţiuni IP, care va
fi utilizat de RET pentru a reveni în program şi a continua cu instrucţiunea următoare.
La chemarea unei proceduri de tip FAR, care poate fi în alt segment, instrucţiunea CALL are adresa
pe 4 octeţi şi depune în stivă atât IP cât şi CS şi încarcă din adresa instrucţiunii noile valori pentru IP şi CS.
O procedură de tip FAR se deosebeşte de una de tip NEAR doar prin faptul că instrucţiunea RET
incarcă din stivă atât adresa de revenire în IP cât şi adresa segmentului în CS. Se recomandă ca procedurile
să fie globale (de tip FAR) pentru a putea fi păstrate în orice segment şi să poată fi apelate din oricare
segment de program. Instrucţiunea RET are codul C3H pentru proceduri de tip NEAR şi CBH pentru cele
de tip FAR.

CALL far ptr Pmed ; pune în stivă IP şi CS


....
Pmed PROC FAR
....

RET ; incarcă din stivă IP şi CS


25
Near CALL
- pune în stivă IP
- salt în segmentul curent cu -32K până la +32K faţă de IP

Cod instr Deplasament


CALL 25400 Near CALL deplasament pe 2 octet
IP=IP+25400

Far CALL
- pune în stivă IP şi CS
- salt în afara segmentului curent şi trebuie modificat IP şi reg. CS

Cod Deplas. in segm Reg CS


CALL 4200 Adresa segment Far CALL deplasament pe 4 octeţi
IP=4200 CS=adresa segment

Ca şi la JMP se pot face apeluri de proceduri indirect prin registre:


CALL BX ; adresa procedurii este în BX
CALL word ptr [BX] ; în BX adresa unei tabele de adrese de proceduri locale
CALL dword ptr[BX] ; în BX adresa unei tabele de adrese de proceduri globale

4.4. Exemple de programe

4.4.1. Conversia din zecimal în binar

Dispozitivele periferice ale calculatorului(tastatură, ecran, imprimantă) sunt proiectate să lucreze cu


şiruri de caractere codificate în ASCII. Numerele se introduc ca şir de cifre zecimale codificate în ASCII
având codurile 30, 31h, 32h, 33h,...39h pentru 0, 1, 2, 3,...9. Pentru a putea face calcule în dispozitivul
aritmetic, care lucrează în binar, şirul de cifre trebuie convertit.
Numărul 14257 introdus de la consolă este un şir ASCII reprezentat sub forma:

Adresa sir Cifre max Nr.cifre SI


DX 0A 05 31 34 32 35 37
BX adresa început număr zecimal

Luăm pe rând cifrele şi eliminăm primi 4 biţi (3 din faţă) şi obţinem valoarea lor în binar.
Calculul numărului binar corespunzător îl facem iterativ folosind valoarea cifrele codificate în binar
astfel:
N=1*10000+4*1000+2*100+5*10+7
Se poate calcula iterativ fără a folosi puterile lui 10 după algoritmul
N=0 N=((((0+1)*10+4)*10+2)*10+5)*10+7

Programul prezentat mai jos citeşte de la tastatură un număr ASCII de maxim 5 cifre ASCII
( reprezentabil pe 2 octeţi) memorat la adresa Z1 şi apelează o procedură de conversie care funcţionează
după acest algoritm.

26
Funcţia DOS de afişare mesaj are codul 9 (09H) care se pune în AH şi cere adresa mesajului în DX.
Mesajul de afişat se va termina obligatoriu cu $.
Funcţia DOS de citire mesaj de la tastatură are codul 10 (0AH), care se pune în AH şi cere adresa
şirului de recepţionat în DX. Zona ce recepţionează şirul (Z1) are în primul octet numărul de octeţi maxim
aşteptaţi, iar în octetul 2 numărul de octeţi recepţionaţi (şirul se termină cu enter).
La chemarea procedurii de conversie CZB în BX se încarcă adresa primului caracter din şirul de
cifre zecimale şi în CX numărul de cifre zecimale. Rezultatul va fi returnat în registrul AX

; --------------------------------------
; Conversie zecimal ASCII - binar 2 octeti
; --------------------------------------
.286c
dosseg
.model small
.stack 100
.data
; numar zecimal ASCII introdus de la tastatura
z1 db 10,0,10 dup (30h),10,13,'$' ; nr zecimal
zece dw 10
n db 0 ; numar cifre zecimale
dw 17394 ; pentru verificare rezultat
bin dw 0 ; numar binar rezultat
m1 db 13,10,'Introduceti un numar de 5 cifre:',13,10,'$'
.code
st1: mov ax,@data
mov ds,ax
mov dx,offset m1 ; afisare mesaj dialog
mov ah,9
int 21h
mov dx,offset z1 ; adresa numar zecimal
mov ah,10 ; asteptare numar
int 21h
mov bx,offset z1+2 ; adresa prima cifra
mov cx,0
mov cl,z1+1 ; numar de cifre numar zecimal
call czb ; procedura conversie zec-bin
mov bin,ax ; memorare numar binar
int 3
; -----------------------------------------
; Procedura conversie zecimal ASCII -binar 2 octeti
; - intrare BX = adresa numar zecimal, CX = numar cifre zecimale
; - iesire AX = numar binar
; -----------------------------------------
czb proc
xor ax,ax ; AX = 0
mov si,ax ; index prima cifra
mov n,cl ; numar cifre zecimale
c3: mov cl,[bx+si] ; incarcare cifra ASCII
27
and cl,0fh ; anulare primii 4 biti
mul zece ; N = N*10
add ax,cx ; N = N*10 + cifra
inc si ; urmatoarea cifra
dec n
jnz c3
ret
czb endp
end st1

4.4.2. Conversie binar-zecimal ASCII

Considerăm un număr binar N pe 16 biţi care trebuie afişat pe monitor în ASCII. Conversia în
zecimal se face în procedura CBZ, împărţind repetat numărul cu 10 şi reţinem resturile împărţirii din DX,
care se memorează într-o zonă ZEC din dreapta spre stânga. Ieşirea din ciclu se face când câtul împărţirii
din registrul AX este zero.
La intrarea în procedură se verifică dacă numărul este negativ, caz în care se complementează şi se
poziţionează un indicator (CH=1). Înainte de ieşirea din procedură se verifică indicatorul şi dacă numărul a
fost negativ i se pune un – în faţă, iar dacă a fost pozitiv se pune un +.
La chemarea procedurii se încarcă în AX numărul binar ce trebuie convertit, în BX adresa zonei
ZEC unde se va pune şirul zecimal şi în SI poziţia ultimului octet în şir.
La revenirea din procedură se afişează rezultatul cu functia DOS având codul 9.
Se putea utiliza numai SI care să conţină adresa ultimului octet din şir
MOV SI,offset zec+5

.286c ; --------------------------------------
dosseg ; Conversie binar - zecimal ASCII
.model small ; --------------------------------------
.data
; numarul zecimal ASCII rezultat se afiseaza
zec db 6 dup (20h),10,13,'$' ; rezultat zecimal
zece dw 10
n db 0
bin dw -17394 ; numar binar de convertit
m1 db 13,10,'Numarul in zecimal este:',13,10,'$'
.code
st1: mov ax,@data
mov ds,ax
mov dx,offset m1 ; afisare mesaj de dialog
mov ah,9
int 21h
mov si,6-1 ; index ultima cifra zecimala
mov bx,offset zec ; adresa zona numar zecimal
mov ax,bin ; numar binar
call cbz ; conversie binar zecimal
mov dx,offset zec ; afisare rezultat conversie
28
mov ah,09h
int 21h
mov ah,4Ch ; terminare program – iesire in DOS
int 21h

; Procedura conversie binar - zecimal ASCII


; - intrare AX = numar binar BX = adresa zona pt numar zecimal
; SI = index ultima cifra zecimala
cbz proc
xor cx,cx ; CX = 0
or ax,ax ; pozitionare indicatori
jge d1 ; numar pozitiv
mov ch,1 ; indicator numar negativ
neg ax ; valoare absoluta
d1: mov dx,0 ; pregatire impartire
div zece ; bin/10 CIT in AX
or dl,30h ; corectie ASCII REST din DL
mov byte ptr [bx+si],dl ; memorare cifra zecimala
dec si ; index cifra urmatoare
or ax,ax ; verificare CIT = 0
jnz d1 ; ciclu daca AX > 0
mov byte ptr [bx+si],'+' ; semn implicit
or ch,ch ; verificare indicator negativ
jz sf
mov byte ptr [bx+si],'-' ; semn negativ
sf: ret
cbz endp
end st1

4.4.3. Program înmulţire două numere zecimale ASCII

.286c ;---------------------------------------
Dosseg ; Utilizare subprograme de conversie
.model small ; Calcul c = a*b de la tastatura
.data ; --------------------------------------

; In z1 se transfera numerele zecimale ASCII


z1 db 10,0,10 dup (30h),10,13,'$'
zece dw 10
n db 0
m1 db 13,10,'Introduceti '
a db 10,13,'a: $'
b db 10,13,'b: $'
abin dw 0 ; numere binare
bbin dw 0
cbin dw 0
czec db 13,10,'a*b= ' ; rezultat de afisat
29
zec db 6 dup(20h),13,10,'$'
.code
st1: mov ax,@data
mov ds,ax
; mesaj citeste a
mov dx,offset m1
mov ah,09h
int 21h
; citeste a in ASCII
mov dx,offset z1
mov ah,10
int 21h
; conversie a in binar
mov bx,offset z1+2
mov cx,0
mov cl,z1+1
call czb
mov abin,ax
; mesaj citeste b
mov dx,offset b
mov ah,09h
int 21h
; citeste b in ASCII
mov dx,offset z1
mov ah,10
int 21h
;conversie b in binar
mov bx,offset z1+2
mov cx,0
mov cl,z1+1
call czb
mov bbin,ax
; acum in ax avem bbin
mul abin ; c=a*b
mov cbin,ax
; acum in ax avem a*b
; conversie rezultat binar - zecimal
mov bx,offset zec
mov si,5
call cbz
; afisare c
mov dx,offset czec
mov ah,09h
int 21h
; terminare
mov ax,4C00h
int 21h
; se copiaza procedurile de conversie CBZ si CZB
include convert.asm
end st1
30
5. ISTRUCŢIUNI PENTRU SIRURI DE CARACTERE

5.1. Prelucrare texte

Prelucrarea textelor este o operaţie foarte frecvent întâlnită în editoarele de texte şi compilatoare.
Din acest motiv de la primele calculatoare comerciale, pentru a obţine o performanţă ridicată, s-au introdus
instrucţiuni specializate pentru prelucrarea şirurilor de caractere (în 1965 IBM 360). Din această categorie
fac parte operaţiile:
Mutare şir de caractere MOVS (Move String)
Ştergere zonă de memorie STOS (Store String)
Încărcare ciclică elemente şir LODS (Load String)
Comparare şiruri de caractere CMPS (Compare String)
Căutare caracter în şir SCAS ( Scan String)
Traducere şir dintr-un cod în altul XLAT

Mutare şir

Mutarea unui şir de octeţi (caractere) dintr-o zonă de memorie în alta se poate face printr-un ciclu
utilizând instrucţiunile de transfer, chiar şi între segmente:
MOV SI,offset Sir1 ; adresa sir1
MOV DI,offset,Sir2 ; adresa sir2
MOV CX,Lung ; Lungime şir ( număr de cicluri)
C1: MOV AL,DS:[SI] ; încarcă un caracter din prima zonă
MOV ES:[DI],AL ; Mută în Zona 2 (chiar în alt segment)
INC SI ; incrementare indexi pentru caracterul următor
INC DI
LOOP ; ciclu

DS:Si
Sir1 F A C U L T A T E

ES:Di
Sir2 F A C U L T A T E

Această operaţie poate fi făcută mai simplu utilizând instrucţiunea MOVSB, care nu are argumente şi cele
două şiruri şi lungimea transferată se specifică în registre.:

DS:SI - conţine adresa sirului sursă (sir1)


ES:DI - conţine adresa sirului destinaţie (sir2)
CX - conţine numărul de elemente transferate (de 1,2 sau 4octeţi)
DF - indicator de direcţie D=0 din stânga - dreapta, D=1 din dreapta spre stânga

MOVSB - mută un octet de la adresa DS:SI la adresa DS:DI


- SI=SI+1 pentru D=0 şi SI=SI-1 pentru D=1
MOVSW - mută 2 octeţi (word) de la adresa DS:SI la adresa DS:DI
- SI=SI+2 pentru D=0 şi SI=SI-2 pentru D=1

31
MOVSD - mută 4 octeţi (dword) de la adresa DS:SI la adresa DS:DI
- SI=SI+4 pentru D=0 şi SI=SI-4 pentru D=1

Secvenţa instrucţiuni pentru mutare Sir1 la Sir2 va fi:


CLD ; forţare D=0 pentru direcţie din stânga spre dreapta
MOV SI,offset Sir1 ; adresa sir1
MOV DI,offset,Sir2 ; adresa sir2
MOV CX,Lung ; Lungime şir ( număr de cicluri)
C2: MOVSB ; mută un octet de la adresa DS:SI la adresa DS:DI şi SI=SI+1
LOOP C2

Operaţia poate fi repetată automat fără LOOP prin:


REP MOVSB

După fiecare mutare de octet instrucţiunea poate fi întreruptă.


Dacă indicatorul de direcţie D=1 (STD) se va da adresa ultimului octet din cele 2 şiruri şi prin
decrementarea lui SI şi DI se va continua cu mutarea elementelor şirului spre stânga.
Diferenţa între cele două cazuri apare când cele 2 şiruri nu sunt disjuncte şi se realizează o translaţie pentru
Sir1 spre dreapta (corect cu D=1) sau spre stânga (corect D=0) .

Sir1 Sir2
F A C U L T A T E MOVSB

F A C U F A C U F A C U F D=0 stg-dr

F A C U F A C U L T A T E D=1 dr-stg

LODS (Load String) încarcă un element de la adresa DS:SI în AL, AX, sau EAX şi incrementează
(D=0) sau decrementează (D=1) registrul index SI. Are formele:
LODSB [DS:SI] AL şi SI=SI+/-1,2,4
W AX
D EAX

STOS (Store String) memorează conţinutul registrului AL, AX sau EAX la adresa destinaţie ES:DI
şi incrementează (D=0) sau decrementează (D=1) registrul index DI.
STOSB AL [ES:DI] şi DI=DI+/-1,2,4
W AX
D EAX

SCAS (Scan String) compară succesiv elementele unui şir de la adresa ES:DI cu conţinutul
registrului AL, AX sau EAX şi poziţionează indicatorii de condiţie. Se pot astfel căuta caractere într-un şir.
SCASB AL compară cu [ES:DI] şi DI=DI+/-1,2,4
W AX
D EAX

CMPS compară şirul indicat de DS:SI cu şirul indicat de ES:DI element (caracter) cu element şi
poziţionează indicatorii de condiţie. Comparaţia se face prin scădere din elementul indicat de DS:SI cel

32
indicat de ES:DI. Operaţia se poate face prin repetiţie şi se va opri la primul element diferit din cele 2
şiruri care va poziţiona indicatorii şi va da sensul comparaţiei.
CMPB [DS:DI] se compară cu [ES:DI[ şi SI=SI+/-1,2,4
W AX DI=DI+/-1,2,4
D EAX

5.2. Repetarea ciclică a instrucţiunilor pe şiruri

Toate instrucţiunile pe şiruri pot fi repetate atâta timp cât CX # 0. Ieşirea din ciclu se face când
CX=0 sau funcţie de valoarea indicatorului Z. REP nu se aplică la instrucţiunile aritmetice şi logice.

REP MOVSB ; repetă instrucţiunea atâta timp cât CX # 0


; CX=CX-1
; SI=SI +/- 1,2,4 şi DI=DI +/- 1,2,4

Pentru pregătirea registrelor se pot folosi şi instrucţiunile care încarcă adrese dacă se cer transferuri
de date între segmente:
LDS reg,dwpointer IP=offset adresa, DS =adresa segment
LES reg,dwpointer IP=offset adresa, ES =adresa segment

CLD ; forţare D=0 pentru direcţie din stânga spre dreapta


MOV SI,offset Sir1 ; adresa zona1
MOV DI,offset,Sir2 ; adresa zona2
MOV CX,5000 ; Lungime şir ( număr de cicluri)
REP MOVSB ; transferă 5000 octeţi din zona1 în zona2

REPE instr ; repetă instrucţiunea pentru CX#0 şi Z=1


REPZ ; CX=CX-1

REPNE instr ; repetă instrucţiunea pentru CX#0 şi Z=0


REPNZ ; CX=CX-1

Căutarea unui caracter punct într-un şir se poate face folosind SCASBcu secvenţa:
CLD ; setare direcţie stânga - dreapta
MOV CX,200 ; lungime şir
MOV DI,offset sir ; adresa şir
MOV AL,’.’ ; caracter căutat punct (de referinţă)
REPNZ SCASB ; ciclu atâta timp cât caracterul nu este punct

5.3. Exemple de programe pentru prelucrare texte

; -------------------------------------Lab5_0.doc
; Programul exemplifica modul de utilizare a
; instructiunilor de prelucrare siruri de caractere
; -------------------------------------

33
pr1 segment
assume cs:pr1,ds:pr1,es:pr1
n equ 25
sir1 db 'facultatea calculatoare $'
sir2 db 30 dup(20h)
sir3 db 'facultatea mecanica $'
zona db 50 dup('A'),'$'
st1: mov ax,pr1
mov ds,ax
mov es,ax
; Muta zona de memorie
; -------------------------------------
mov cx,n ; lungime sir
mov si,offset sir1 ; sir sursa
mov di,offset sir2 ; zona destinatie
cld ; df=0 directie stinga dreapta
rep movsb ; mutare sir
; Sterge zona
; -------------------------------------
mov al,'B' ; caracter ce se copiaza
mov di,offset zona ; adresa inceput zona
mov cx,20 ; lungime zona
rep stosb ; memorare reg AL in zona
; Translatie zona spre dreapta
; -------------------------------------
std ; DF=1 directie dreapta-stinga
mov cx,16 ; lungime sir
mov si,offset sir2+15 ; adresa ultim octet din sir
mov di,offset sir2+26 ; adresa ultim octet destinatie
rep movsb ; mutare sir dreapta-stinga
; Comparatie siruri: sir1 cu sir3
; -------------------------------------
mov si,offset sir1 ; adresa sir sursa
mov di,offset sir3 ; adresa sir destinatie
mov cx,16 ; lungime de comparatie
cld ; DF=0 directie stinga-dreapta
repe cmpsb ; repeta atit timp cit octetii sint egali
jl calc ; sir1 < sir3 ( primul octet diferit)
mov dx,offset sir3 ; afisare sir3
jmp short c2
calc: mov dx,offset sir1 ; afisare sir1
c2: mov ah,9 ; functie afisare
int 21h
; Cautare punct in sir1
; -------------------------------------
mov di,offset sir1 ; adresa sir
mov cx,25 ; lung sir
cld ; DF=0
mov al,'.' ; caracter cautat (referinta)
repnz scasb ; cautare octet = AL
34
mov dx,di ; afisare restul sirului
mov ah,09h
int 21h
; Cauta caracter diferit de 'B' in zona
;---------------------------------------
mov di,offset zona ; adresa zona de memorie
mov cx,50 ; lungime zona
mov al,'B' ; caracter de referinta
repz scasb ; cauta primul octet # AL
mov dx,di ; afisare text ce urmeaza
mov ah,09h
int 21h
int 3h ; revenire in AFD
mov ax,4C00h ; revenire in DOS
int 21h
pr1 ends
end st1

; -------------------------------------Lab5_2
; Afisare text fara prima propozitie
; -------------------------------------
pr1 segment
assume cs:pr1,ds:pr1,es:pr1
mesaj db 13,10,'Introduceti un text: ',13,10,'$'
mesaj1 db 13,10,'Textul scurtat este: ',13,10,'$'
sir1 db 50,0,50 dup (' '),'$'
st1: mov ax,pr1
mov ds,ax
mov es,ax
mov dx,offset mesaj
mov ah,09h
int 21h
mov dx,offset sir1 ; asteptare text
mov ah,10
int 21h
mov bl,(sir1+1) ; lungime text introdus
mov bh,0
mov (sir1+2).[bx],'$' ; caracterul $ la sfirsit
cld ; directie stinga dreapta
mov di,offset sir1+2 ; adresa text
mov cx,50 ; lungime maxima
mov al,'.' ; caracter cautat
repnz scasb ; cautare '.'
mov dx,offset mesaj1 ; afisare mesaj
mov ah,09h ; DI poziţionat pe primul octet după punct
int 21h
mov dx,di ; afisare rest text
mov ah,9
int 21h
mov ah,4ch ; terminare program cu iesire in DOS
35
int 21h
pr1 ends
end st1

5.3. Traducere text

XLAT este instrucţiunea care realizează traducerea unui text codificat într-un cod în alt cod folosind un
tabel de traducere plasat la adresa indicată de BX. Codul caracterului din AL este considerat index în tabelul
de coduri şi XLAT returnează în AL caracterul din tabelul de coduri corespunzător indexului .

La intrare: BX - adresa tabelei de coduri


AL - codul caracterului de tradus
La ieşire: AL - codul caracterului tradus

Se consideră mai jos tabela de coduri încărcată în BX:

BX XLAT
Tabel de coduri W A T Z E U F R C pentru AL=03
Index în tabel 0 1 2 3 4 5 6 7 8 .... rezultă AL=K

Codificarea pentru CARTE va fi 08 01 07 02 04

Pentru a converti un text scris cu litere mici în litere mari vom ţine cont că:
Literele mari au codurile: A 41H,B 42H,C 43H, E 44H, F 45H, G 47H, H 48H, I 49H
J 4AH, K 4BH,..... .....Y 59H, Z 5AH

Literele mici au codurile: a 61H, b 62H, c 63H, e 66H, f 65H, g 67H, h 68H, i 69H
j 6AH, k 6BH,..... .....y 79H, z 7AH
Codul lui ‚a’ 61H = 6 x 16 + 1 trebuie să fie index pentru ‚A’ în tabel. Prima literă din tabelul de
coduri va fi plasată la adresa 6 x 16 + 1=65. La începutul tabelei vom plasa 65 de spaţii, care vor înlocui alte
coduri care pot apare în afară de litere mici.
În continuare se trec codurile pentru litere mari în ordine alfabetică.

; -------------------------------------Lab5_1.doc
; Utilizare XLAT pentru codificare text
; Se convertesc literele mici in litere mari
; -------------------------------------
pr1 segment
assume cs:pr1,ds:pr1,es:pr1
n equ 25
; Tabela coduri
tcod db 6*16+1 dup(' '),'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
db 7 dup(' ')
; Text de codificat
text db 'facultatea de matematici aplicate$'
dw 20 dup(0)
; -------------------------------------

36
st1: mov ax,pr1
mov ds,ax
mov es,ax
mov bx,offset tcod ; adresa tabela coduri
mov si,0 ; index in text
mov cx,offset st1 - offset text -1 ; lungime text
c1: mov al,text[si] ; un octet din textul de tradus
xlat ; traducere octet
mov text[si],al ; memorare octet tradus
inc si ; urmatorul caracter de tradus
loop c1
; Afisare text dupa traducere
calc: mov dx,offset text
mov ah,9
int 21h
c2: mov ah,4ch ; iesire in DOS
int 21h
pr1 ends
end st1

5.4. Instrucţiuni de intrare/ieşire

Instrucţiunile de intrare ieşire transferă şiruri de caractere între memoria calculatorului şi


dispozitivele periferice (tastatura, monitor, modem, disc, imprimantă ...). Dispozitivele periferice sunt legate
la porturi ale procesorului prin interfeţe specializate, care asigură funcţii de adaptare şi care pot să aibă
memorii proprii (placi video, sunet).
Prin program informaţia se transferă din memorie intr-un port octet cu octet (OUT), sau se citesc
succesiv din port octeţi care se depun în memorie în zone tampon (buffer). Interfaţa preia octeţii din port şi
îi transmite spre periferic sau asigură transferul succesiv al octeţilor de la periferic spre port de unde sunt
citiţi prin program (IN).
La procesoarele actuale porturile pot să conţină 1, 2 sau 4 octeţi. Adresa portului se poate specifica
direct în instrucţiune, sau se poate indica indirect în registrul DX. Instrucţiunile de intrare-ieşire sunt IN
şi OUT, transferul se face intre port şi acumulator.

OUT port,AL AL port - se scrie în port din AL, AX sau EAX


port,AX AX
port,EAX EAX

IN AL,port port AL - se citeşte din port în AL,AX sau EAX


AX,port AX
EAX,port EAX

Adresare indirectă prin DX

OUT DX,AL AL DXport - se scrie în portul indicat de DX


DX,AX AX din AL, AX sau EAX
DX,EAX EAX

37
IN AL,DX DXport AL - se citeşte din portul indicat de DX
AX,DX AX în AL,AX,EAX
EAX,DX EAX

Intrări ieşiri pentru şiruri de caractere


La procesoarele actuale există posibilitatea transferului unui şir de octeţi de lungime dată în registrul
CX, între o zonă de memorie indicată prin DS:SI sau ES:DI şi un port indicat de un registru DX.
Modul de lucru este similar ca la instrucţiunile pe şiruri de caractere. După fiecare element transferat
se incrementează sau se decrementează registrul index pentru a se pregăti transferul octetului următor. Dacă
indicatorul de direcţie D=0 se dă primul octet al zonei în index şi se incrementează indexul după transferul
unui element, iar dacă D=1 se încarcă în index ultimul element al zonei şi se decrementează indexul.
Se poate utiliza comanda REP instr pentru a repeta automat operaţia de transfer.
Aceste instrucţiuni nu au argumente.
Scriere şir de caractere în port

OUTSB (DS:SI) DXport şi SI=SI+/-1,2,4


OUTSW
OUTSD

DS:SI
Zona

Port
DX Adresa port

Port1 EQU 40 ; număr port utilizat


CLD ; setare direcţie stânga -dreapta
MOV SI,offset Zona ; adresă primul octet din zonă
MOV CX,3000 ; număr de octeţi transferaţi
MOV DX,port1
REP OUTSB ; transferă 3000 de octeţi spre portul 40

Instrucţiunea cu repetiţie se poate utiliza pentru a scrie în cuvintele de comandă ale unor cuploare
(placă video, disc,imprimantă ...). Pentru periferice nu se poate folosi REP, fiindcă nu se poate realiza
sincronizarea între viteza de transmisie DRAM şi viteza redusă a perifericului.

Citire şir de caractere dintr-un port într-o zonă de memorie indicată de ES:DI

INSB (DXport) ES:DI şi DI=DI+/-1,2,4


INSW
INSD

Port2 EQU 50
CLD
MOV DI,offset buffer ; adresă zonă de memorie unde se citeşte
MOV DX,port2 ; adresa port utilizat
MOV CX,2000 ; număr de octeţi de citit

38
REP INSB ; citire 2000 octeţi din portul 50 în buffer

Aceste instrucţiuni simplifică scrierea programelor (driver) pentru comanda perifericelor.

6. TRANSMITEREA PARAMETRILOR SPRE SUBPROGRAME


6.1. Subprograme
Subprogramele asigură o dezvoltare sistematică a programelor pentru aplicaţii prin:
 Programarea modulară – descompunerea aplicaţiei pe funcţiile realizate şi posibilitatea de a lucra
mai mulţi programatori, coordonaţi de un programator şef care stabileşte structura de ansamblu a
programului;
 Posibilitatea de reutilizare a subprogramelor existente pentru alte aplicaţii;
 Claritatea programelor care permite o corectare, modificare sau dezvoltare uşoară a aplicaţiei.

Subprogramele se pot considera nişte cutii negre legate între ele, care realizează o funcţie prin
prelucrarea parametrilor formali de intrare şi returnează rezultate transmise programului chemător prin
parametrii formali de ieşire. Pentru a realiza funcţia dorită se pot folosi algoritmi diferiţi care sunt
transparenţi pentru utilizator. Aceeaşi funcţie poate fi implementată prin subprograme diferite, care pot fi
echivalente.

X1
X2 Y1(X1,X2,...Xn)
... Subprogram Y2(X1,X2,...Xn)
..........
Xn

Definirea unui subprogram se face formal pe baza unui algoritm care primeşte variabile formale de
intrare, care sunt prelucrate de o secvenţă de instrucţiuni care calculează variabilele de ieşire.

Utilizarea subprogramului presupune chemarea subprogramului, transmiterea valorilor parametrilor


efectivi de intrare şi preluarea rezultatelor transmise prin parametrii de ieşire. In limbajele de nivel înalt
parametrii de intrare pot fi expresii de acelaşi tip cu parametrii formali de intrare. Pe programator nu-l
interesează modul de transmitere a parametrilor între program şi subprograme.
În limbaj de asamblare transmiterea parametrilor spre subprograme este mai complicată fiindcă nu există
tipuri definite de date ci numai date de o anumită lungime (1,2,4 octeţi). Tipul datelor este dat de
instrucţiunile care se aplică asupra lor. Aici se permite ca date care sunt de tip caractere ASCII, sau chiar
instrucţiuni să fie prelucrate cu instrucţiuni aritmetice (adunare, scădere, înmulţire, ..) cu rezultate
imprevizibile dar fără să dea erori dacă nu apar depăşiri.
Chemarea unui subprogram este un simplu CALL care pune registrele IP şi eventual CS în stivă şi
face un salt la adresa indicată din acelaşi segment sau din alt segment. Subprogramul stabileşte convenţia
de transmitere a parametrilor de intrare şi de returnare a rezultatelor. Programul chemător care poate fi chiar
subprogram trebuie să pregătească parametrii de intrare înainte de chemare şi să preia rezultatele la ieşirea
din subprogram. Instrucţiunea RET reface numai din stiva adresa de revenire (registrele IP şi CS).

După posibilităţile de utilizare subprogramele pot fi:


 Normale pot chema alte subprograme dar nu se pot chema pe ele însele
 Recursive care se pot chema pe ele însele direct sau indirect (N!=N*(N+1)!)
 Reentrante care pot fi folosite simultan de mai mulţi utilizatori (editare texte)

39
Parametrii se pot transmite spre subprograme:
 prin Valoare caz în care valoare parametrului se transmite subprogramului
 prin Adresă când sunt tabele cu multe elemente şi adresa tabelului se transmite subprogramului,
care va folosi metode de adresare indirectă sau/şi indexată.

Transmiterea parametrilor spre subprograme se poate face:


 Prin registre în cazul în care sunt puţini parametrii şide lungime redusă
 Printr-o zonă de memorie cu structură cunoscută şi a cărei adresă se dă într-un registru
(recomandabil BX)
 Prin stivă care este un caz particular de zonă de memorie
 Prin tabelă de adrese care este cea mai eficientă dar nu poate fi folosită la procesoarele Intel care
nu au adresare indirectă prin adresă de memorie.

6.2. Transmiterea parametrilor printr-o tabelă de adrese


Această metodă presupune memorarea adreselor parametrilor într-o tabelă TA. Adresa Tabelei TA
se încarcă într-un registru şi se transmite subprogramului. Subprogramul transfera tabela de adrese TA într-o
zonă de memorie proprie rezervată pentru adresele parametrilor. La apelarea unui parametru formal se
apelează indirect adresa parametrului din tabela de adrese. Elementele tabelei funcţionează ca parametrii
formali apelaţi ca şi variabilele locale, dar indirect (*).
Ex:
NX dw 20 ; număr elemente tablou X
S dw 0 ; suma elemente tablou
X dw 45,723,890,534,..........
TA dw X,N,S ; adresa tablou X, NX şi suma S
......
MOV SI,offset TA ; adresa tabela de adrese TA
CALL PSUMA ; chemare subprogram
; suma s-a transmis direct in variabila S din program
PROC far
MOV DI,offset Tab ; tabela de adrese rezervata local
MOV cx,6 ; lungime tabela de adrese (3 param*2 octeţi)
REP MOVSB , transfer tabela de adrese din program in subprogram
Mov CX,*N ; încarcare indirectă numar de elemente
Mov SI,0 ; I=1
Mov AX,0 ; Suma=0
C2 ADD AX,*T[SI] ; element Xi
ADD SI,2 ; I=I+1
LOOP C2
MOV *Suma,AX ; memorare suma
RET ; revenire din subprogram
; tabela de adrese locala
T dw 0 ; adresa tablou
N dw 0 ; adresa număr de elemente
Suma dw 0 ; adresa suma în programul principal

Din păcate nu există adresare indirectă prin memorie şi subprogramul nu se poate implementa în
acest mod. S-ar permite exploatarea variabilelor plasate în diferite locuri în programul principal direct din
subprogram. La calculatoarele clasice toate limbajele de programare foloseau această metodă de transmitere
a parametrilor spre subprograme.

40
6.3. Transmiterea parametrilor prin registre
Este cea mai simplă metodă de transmitere a parametrilor, dar este limitată pentru număr redus de
parametrii. In subprogram se recomandă să se salveze registrele care se modifică şi să se refacă înainte de
revenirea din subprogram (RET). Este mai simplă salvarea tuturor registrelor la început prin PUSHA şi
refacerea la sfârşit prin POPA. În registre se pot încărca valorile parametrilor sau adresa lor. In cazul
subprogramelor de conversie zecimal-binară şi binar-zecimală discutate deja, s-a transmis în BX adresa
şirului de cifre zecimale codificate în ASCII şi în AX numărul binar iniţial sau rezultat.

Program de afişare zonă de memorie în hexa.


Se prezintă mai jos un program de afişare a unei zone de memorie în hexazecimal.
Pentru aceasta se ia o zonă de memorie şi se încarcă succesiv în AX câte 2 octeţi din care vor rezulta 4 cifre
hexa. Grupele de 4 cifre hexa se despart printr-un spaţiu.
Problema se reduce la a scrie o procedură (PNUM) care afişează în hexa conţinutul registrului AX
folosind succesiunea de operaţii:
 Se va selecta pe rând câte o cifră hexa (seturi de 4 biţi) din stânga spre dreapta, într-un ciclu prin
deplasarea registrului AX cu 12, 8, 4, 0 biţi spre dreapta.
 Cifra hexa din dreapta registrului AL se transformă în caracter ASCII în procedura PNIB
adăugându-i 30H. Dacă caracterul rezultat nu este cifră ( 9) se face o corecţie prin care i se adaugă
07H. Astfel din caracterul hexa A va rezulta 3AH+07H=41H, care este codul caracterului A în
ASCII şi care poate fi afişat.
 Caracterul ASCII rezultat se va afişa în procedura PUTC folosind funcţia DOS 02H, care afişează
conţinutul registrului DL.
 La unele monitoare trebuie adăugată o secvenţă de întârziere pentru a asigura sincronizarea între
viteza de transfer din memorie şi viteza perifericului. Intârzierile se pot realiza prin decrementarea
ciclică a unor registre, chiar prin 2 cicluri suprapuse. Se pot obţine timpii de întârziere doriţi, care
depind de valoarea iniţială încărcată în registre.

; --------------------------------------Vhexa.doc
; Afisare zona de memorie in hexa
; --------------------------------------
.286c ; set comun 286
dosseg
.model small
.data
date dw 65278,1234h,24,26,62,721

.code
st1: mov ax,@data
mov ds,ax
mov cx,6 ; numar de cuvinte
41
mov si,0 ; index in zona
l1: mov ax,date[si]
call far ptr pnum ; afisare hexa continut AX
add si,2 ; cuvintul urmator
loop l1
; Terminare program
mov ax,4C00h
int 21h

; Procedura afisare hexa continut reg AX


pnumproc far
; la intrare AX=16 biti
; la iesire 4 cifre hexa pe ecran
pusha ; salvare registre
mov cl,12 ; contor deplasari
nib2: push ax ; salvare AX
shr ax,cl ; deplasare dreapta cu 12,8,4,0
call pnib ; afisare cifra hexa din AL
sub cl,4 ; urmatoarea cifra hexa
cmp cl,-4
pop ax ; refacere AX initial
jnz nib2
mov al,' ' ; afisare spatiu intre 4 cifre hexa
call far ptr putc
popa ; refacere registre
ret ; terminare procedura
pnumendp
; Procedura afisare cifra hexa din AL dreapta
pnib proc near
and al,0fh ; selectie 4 biti dreapta
add al,30h ; corectie cifra ASCII
cmp al,3ah ; cifra > 9
jl ph3
add al,07 ; corectie cifra > 9
ph3: call far ptr putc ; afisare caracter ASCII
ret
pnib endp

; Procedura afisare caracter din AL


putc proc far
pusha
mov dl,al ; functie DOS afisare DL

42
mov ah,2
int 21h
ret
; secventa de intarziere
mov cx,0fh ; secventa de asteptare afisare
del: push cx
mov cx,0ffh ; ciclul 2 de asteptare
del2: nop
loop del2
pop cx
loop del
popa
ret
putc endp
end st1
;---------------------------------------
Program de sortare caractere dintr-un text introdus de la tastatură
Se introduce de la tastatură un şir de maxim 80 caractere de lungime variabilă, care se memorează
într-un buffer. Se cheamă o procedură de sortare care utilizează metoda inversiunii şi ordonează caracterele
din buffer funcţie de valoarea codului ASCII. Procedura se poate modifica pentru a primi ca parametru în
BX adresa unui text oarecare precedat de lungimea lui (lungimea poate fi transmisă în CX).

* ====================================SORT.doc
* Sorteaza un sir de caractere prin metoda inversiunii
* ====================================
sdate segment ; segmentul de date
dim equ 80 ; lungime maxima tabel
buf db 80,0,dim dup(?) ; buffer pentru sirul de caractere
in_msg db 'introduceti sirul de caractere:',10,13,'$' ; mesaj dialog
out_msg db 'sirul sortat:',10,13,'$' ; mesaj de dialog
cr db 10,13,'$' ; carriage return si line feed
sdate ends ; sfarsit segment date
sstiva segment stack ; segment de stiva
db 100 dup(?) ; rezervare spatiu stiva
stiva equ $ ; eticheta baza stiva
sstiva ends ; sfarsit segment stiva
cod segment ; segment de cod
assume cs:cod,ss:sstiva,ds:sdate,es:sdate ; afectare reg.segment
start: mov ax,sdate ; incarcare adresa segment date in registrul DS
mov ds,ax
mov es,ax ; incarcare adresa segment date in registrul ES
mov ax,sstiva
mov ss,ax ; incarcare adresa segment stiva in registrul SS

43
mov sp,offset stiva ; incarcare adresa top stiva in registrul SP
mov ah,09h ; cod functie DOS afisare mesaj
mov dx,offset in_msg ; adresa mesaj
int 21h ; intrerupere DOS
mov ah,0ah ; cod asteptare sir de la tastatura
mov dx,offset buf; adresa buffer intrare
int 21h
mov ah,09h ; afisare CR,LF
mov dx,offset cr
int 21h
; pregatire chemare procedura
call sortare ; chemare procedura de sortare sir
mov ah,09h ; afisare mesaj - sirul sortat:
mov dx,offset out_msg
int 21h
mov ah,09h ; afisare sir sortat
mov dx,offset buf[2]
int 21h
mov ah,4ch ; terminare program, iesire in DOS
int 21h

* ================================
* Procedura sortare sir de caractere in zona buf
* ================================
sortare proc near ; declaratie procedura
sta: mov dx,0
mov cx,0
mov cl,buf[1] ; lungime sir introdus in CL
dec cx ; numar cicluri L-1
jz s_end ; nu s-au introdus caractere

next: mov al,buf[si] ; primul element considerat cel mai mare


cmp al,buf[si+1] ; se compara cu urmatorul
jle cont ; sunt in ordine
xchg al,buf[si+1] ; se inverseaza
mov buf[si],al
mov dx,1 ;marcarea unei inversari
cont: inc si
loop next ; cx = cx - 1 si salt daca cx > 0
; pregatire urmatoarea trecere
cmp dx,0
jnz sta

44
s_end: mov bl,buf[1] ; lungime sir
mov bh,0
mov buf[bx+2],'$' ;inserarea $ dupa sirul sortat
ret ; iesire din procedura
sortare endp ;sfarsit procedura
cod ends ; sfarsit segment
end start ; adresa de lansare si sfarsit program

* =========================================

6.4. Transmiterea parametrilor printr-o zonă de memorie


In cele mai multe cazuri trebuie transmişi spre subprograme un număr mare de parametrii şi numai
pot fi folosite registrele care sunt într-un număr foarte mic. Atunci se foloseşte transmisia parametrilor
printr-o zonă de memorie. Metoda este mai puţin performantă decât transmiterea parametrilor prin tabelă de
adrese, deoarece toţi parametrii trebuie grupaţi în zona de memorie ( nu pot fi dispersaţi în program).
Zona de memorie pentru parametrii se alocă în programul principal şi trebuie să fie un spaţiu
continuu în care să se memoreze toţi parametrii. Structura zonei este cea cerută la definirea procedurii care
implementează algoritmul de calcul. Dacă se utilizează mai multe tablouri trebuie stabilite dimensiuni
maxime pentru fiecare tablou. Dacă se utilizează un singur tablou se plasează ultimul dintre parametrii şi
poate fi de dimensiune variabilă. La chemarea subprogramului adresa zonei de parametrii, din programul
principal se va încărca într-un registru (ex.BX). In subprogram se descrie structura zonei de memorie ce
conţine parametrii, care vor fi apelaţi indirect prin registru (BX).
Pentru exemplificare se consideră un subprogram care calculează media elementelor unui tablou de
N numere întregi cu semn. Parametrii transmişi subprogramului vor fi:
Media elementelor calculată ca parametru de ieşire din procedură (S)
Numărul de elemente ale tabloului (N)
Tabloul de X de N elemente pentru care se calculează media

BX X
Zona memorie S N X(1) X(2) X(3) .........
(parametrii)

In programul prezentat se consideră tabloul X cu 5 elemente, dar el poate avea oricâte, deoarece el este
ultimul parametru. La chemarea procedurii in se încarcă în BX adresa zonei de memorie care conţine
parametrii. In procedură se descrie structura zonei de parametrii prin adresa lor relativa in zonă cu directiva
EQU. Mnemonicele S1, N1, X1 vor fi folosite în procedură pentru referirea indirectă prin BX a
parametrilor. Adresarea lui S pentru iniţializare se face prin:
mov word ptr [bx+s1],0 ; s=0
Trebuie folosit word ptr fiindcă nu se utilizează registru şi trebuie precizată lungimea operanzilor
folosiţi. Adresa BX + s1 este echivalentă cu BX +0. Pentru a referi un element de tablou direct în programul
principal se foloseşte şi indexarea cu SI:
c1: mov ax,[bx+x1+si] ; x[i]

; --------------------------------------Lab7_0

45
; Calcul medie elemente tablou X
; Parametrii spre subpr. transmisi prin zona de memorie
; --------------------------------------
DOSSEG
.MODEL SMALL
.STACK 256
.286C
.DATA
s dw 0 ; s = media
n dw 5 ; nr. elem. din tabloul x
x dw 1,-92,83,-424,53
.CODE
st1: mov ax,@DATA
mov ds,ax
mov bx,offset s ; adresa zona parametrii
call sp1 ; chemare subprogram
int 3 ; valoarea medie s-a memorat in S de catre procedura

; -----------------------------------------
; Procedura calcul medie elemente tablou
; Intrare: BX adresa zona parametri
; -----------------------------------------
sp1 PROC near
; Adrese in zona de parametrii
s1 equ 0 ; Suma rezultata
n1 equ 2 ; numar de elemente
x1 equ 4 ; Tabloul de elemente
pusha ; salvare registre
mov si,0 ;i=1
mov word ptr [bx+s1],0 ; s = 0
mov cx,[bx+n1] ; numar elemente
c1: mov ax,[bx+x1+si] ; x[i]
add [bx+s1],ax ; s=s+x[i]
add si,2 ; i=i+1
loop c1
mov ax,[bx+s1] ; AX = suma elemente
cwd ;extindere pentru impartire
idiv word ptr [bx+n1] ; s = s/n media
mov [bx+s1],ax ; memorare medie
popa ; refacere registre
ret
sp1 endp

46
end st1

6.5. Definire şi utilizare structuri de date

Definirea structurii unei zone de memorie se poate face cu directiva STRUC, care creează o machetă şi
ataşează fiecărei etichete o adresa relativă la începutul zonei. Definirea echivalentă pentru zona de
parametrii din procedura anterioară se poate face:

Zona STRUC ; definire machetă pentru structura zonei


S1 DW ?
N1 DW ?
X1 DW 50 dup (?) ; definire tablou virtual pentru care nu se aloca spatiu
ENDS ; sfarsit definire structura

Pentru variabilele din structură nu se rezervă spaţiu de memorie. Directiva DW este utilizată
numai pentru a preciza lungimile operanzilor şi a calcula adresele relative ataşate etichetelor. Folosind acest
mod de definire pentru o structura nu trebuie să calculăm poziţiile parametrilor în zonă. Dacă adăugăm noi
parametrii sau le modificăm lungimea, nu trebuie să ne preocupe ce adrese se generează, ca în cazul
utilizării directivei EQU.
O structură de date defineşte un tip ca o colecţie de una sau mai multe variabile, de tipuri diferite,
grupate sub un singur nume pentru utilizare.

nume_struc STRUC
-------- ; definiţie variabile formale
-------- ; care compun structura

nume_struc ENDS

Variabilele dintr-o structură pot fi declarate cu sau fără valori iniţiale. Valorile iniţiale sunt cele
implicite care servesc la generarea unei zone cu acea structură.
Putem defini tipul compus dată pe 4 octeţi format din zi, lună, an;
date STRUC ; definire structura data
zi db 0 ; ziua
luna db 0 ; luna
anul dw 0 ; anul
date ENDS
Putem defini o variabilă structurată de tip date şi cu valori ale câmpurilor:
D1 date <15,2,1978> ; 15 februarie 1978

Vom declara structura STUDENT care conţine date personale:


Student STRUC
Nume db 15 dup(20H) ; nume student
Adresa db ’ Timisoara ’ ; adresa (implicit Timisoara)
Varsta db 18 ; varsta
Datan db 0,0,0 ; zi luna, an
Cods db 5 dup(0) ; cod student fac,sectie,an,grupa,nr
Student ENDS

47
Pentru a genera datele personale pentru un student vom scrie:
Radu <’Radu’,’Arad,25,15,9,75,’AC34F’> ; nume,adresa,varsta,datan,Cods

Valorile câmpurilor dintr-o structură pot fi referite în instrucţiunile programului:


MOV BX,D1.Anul ; se încarcă 1978
MOV AL,Radu.Varsta ; se încarcă 25
MOV DX, offset Radu.Adresa ;se încarcă ARAD

6.6. Transmisia parametrilor spre subprograme prin stivă

Toate limbajele de nivel înalt folosesc transmiterea parametrilor prin stivă, care este un caz
particular de transmitere a parametrilor printr-o zonă de memorie. In procedură trebuie definită structura
datelor din stiva.
In stivă procedura va găsi mai multe tipuri de date:
 Parametrii subprogramului transmişi de programul principal
 Adresa de revenire în programul principal (după CALL) - valoare lui IP şi CS
 Registrele salvate de procedură
 Variabilele locale ale procedurii
 Stiva procedurii, care poate şi ea sa cheme subprograme

Pentru orice procedură se începe cu proiectarea structurii stivei şi definirea ei printr-o structură de date,
care se va folosi la adresarea parametrilor şi variabilelor locale.
Vom concepe un program care utilizează o procedură de calcul a mediei numerelor pozitive şi cele
negative dintr-un tablou de numere întregi cu semn.
 Parametrii de intrare vor fi adresa tabloului (atx) şi numărul de elemente (nv)
 Parametrii de ieşire sunt media elementelor pozitive MP şi negative MN
 Variabile locale suma si numărul elementelor pozitive şi negative(S1,K1,S2,K2)
 Se vor salva în stivă registrele BP, BX, FLAGS şi CX.
Cu aceste precizări structura stivei văzută de procedură va fi:

SP -16 Stiva procedurii


-14 S1 Suma pozitive
-12 K1 Nr.elemente pozitive
-10 S2 Suma negative
-8 K2 Nr.elemente negative
-6 CX
-4 FLAGS Registre salvate
-2 BX
BP +0 BP BP registru de bază adresare stivă
+2 IP Adresa instrucţiunii următoare
+4 CS Adresa segment
+6 Adresa tablou MP Adresa tabel (medie pozitive)
+8 N MN Nr elemente (medie negative)
In programul principal s-au pus în stiva adresa tabloului X şi N numărul de elemente. Se apelează
subprogramul prin CALL far ptr care pune în stiva CS şi IP. La revenirea din procedură se iau din stivă
rezultatele MP(medie elemente pozitive) şi MN (medie elemente negative).

48
In procedură se fac secvenţele de operaţii;
 Se salvează registrele şi se memorează SP în BP, care va deveni referinţa pentru adresarea
elementelor din stivă.
 Se alocă spaţiu în stivă pentru cele 4 variabile locale (S1,K1,S2,K2) prin decrementarea cu 4*2=8 a
lui SP
 Registrul SP va adresa în continuare stiva procedurii
 Se defineşte structura Z şi adresele variabilelor locale faţă de BP
 Se iniţializează variabilele locale
 Se calculează printr-un ciclu suma elementelor pozitiveS1, a celor negative S2 şi numărul lor k1
respectiv k2
 Se calculează media elementelor pozitive peste adresă tablou(ATX) şi negative peste N
 Se eliberează spaţiul ocupat de variabilele locale prin incrementarea lui SP cu 8
 Se refac registrele salvate
 Se revine în programul principal cu RET care încarcă din stivă IP şi CS
Dacă la revenirea din procedură mai rămân parametrii reziduali în stivă se utilizează
RET N unde N este valoarea cu care se incrementează SP.
La revenirea în programul principal trebuie ca stiva să fie goală adică sa aibă aceeaşi poziţie ca la apelul
procedurii.

; -----------------------------------------Lab8_1
; Transmiterea parametrilor prin stiva
; Subprogram calcul medie elemente pozitive
; si negative dintr-un tablou X
; -----------------------------------------
NAME MEDIA1
SSTIVA segment 'stack'
dw 100 dup (?)
stiva equ $ ; virful stivei
SSTIVA ends
;------------------
;segment date
;------------------
SDATA segment
MP dw 0 ; medie elemente - pozitive
MN dw 0 ; - negative
N dw 10 ; numar elemente tabel X
X dw 15,-12,-6,19,-7,17,18,0,-1,1
SDATA ends
;-------------------------
;segment program principal
;-------------------------
SPR segment
assume cs:SPR,ds:SDATA,ss:SSTIVA
st1: mov ax,SDATA ; initializare registre segment
mov ds,ax
49
mov ax,SSTIVA
mov ss,ax
mov sp,offset stiva
; ------------------
; Chemare subprogram
; ------------------
push N ; depune in stiva - nr.elemente
mov ax,offset X ; - adresa tablou
push ax
call far ptr medie ; chemare subprogram
; rezultatele s-au depus in stiva peste parametrii de intrare
pop MP ; extrage medie elem. - pozitive
pop MN ; - negative
int 3
; ------------------------------------------
; Subprogram calcul medie elemente pozitive
; si negative dintr-un tablou X
; ------------------------------------------
MEDIE proc far
; Pregatire stiva
push bp ; salvare reg BP
mov bp,sp ; reg bp baza in stiva
push bx ; salvare registre
pushf
push cx
sub sp,8 ; alocare spatiu variabile locale
; --------------
; Corp procedura
; --------------
; Structura stiva relativ la adr. de baza din BP
; Zona variabile locale
s1 equ -14 ; suma elemente pozitive
k1 equ -12 ; contor elemente pozitive
s2 equ -10 ; suma elemente negative
k2 equ -8 ; contor elemente negative
z struc ; descriere structura parametrii
bpv dw ? ; reg BP vechi
ipv dw ? ; reg IP - adresa de revenire
csv dw ? ; CS - adresa segment prog.principal
atx dw ? ; adresa tabel X
nv dw ? ; nr. de elemente tablou X
z ends

50
; -------------
; initializare variabile
mov cx,word ptr [bp+nv] ; contor cicluri
mov bx,word ptr [bp+atx] ; BX adresa tablou X
mov ax,0 ; initializari
mov si,0 ; index adresare in X
mov [bp+s1],ax ; variabile locale
mov [bp+k1],ax
mov [bp+s2],ax
mov [bp+k2],ax

; Ciclu de calcul sume elemente pozitive si negative


c1: mov ax,word ptr [bx+si] ; element X(I)
or ax,ax ; pozitionare indicatori
jl minus ; X(I) < 0
add word ptr [bp+s1],ax ; S1 = S1 + X(I)
inc word ptr [bp+k1] ; K1 = K1 + 1
jmp short c2
minus: add word ptr [bp+s2],ax ; S2 = S2 + X(I)
inc word ptr [bp+k2] ; K2 = K2 + 1
c2: add si,2 ; urmatorul element din tabel
loop c1
; Secventa calcul medii
mov ax,word ptr[bp+s1]
cwd
idiv word ptr [bp+k1] ; S1 = S1/K1
mov [bp+6],ax ; memorare medie in stiva
mov ax,[bp+s2]
cwd
idiv word ptr [bp+k2] ; S2 = S2/K2
mov [bp+8],ax ; memorare medie negative
;---------------
;secventa iesire
;---------------
add sp,8 ; eliberare spatiu variabile locale
pop cx ; refacere registre salvate
popf
pop bx
pop bp
ret ; iesire din subprogram
MEDIE endp ; rezultatele MP si MN in stiva
SPR ends

51
end st1
; -----------------------------------------

6.7. Subprograme recursive


Subprogramele normale pot apela alte subprograme, dar nu se pot apela pe ele însele, fie direct, fie
indirect prin alte subprograme pe care le apelează.
Subprogramele recursive permit ca în secvenţa de definiţie (sau în subprogramele apelate) să se
apeleze pe ele însele. Apelul se face înainte de a se termina procedura.
Există aplicaţii care pot fi rezolvate prin algoritmi iterativi sau/şi algoritmi iterativi. La apelarea
subprogramului nu ne interesează ce tip de algoritm se utilizează. Ne interesează ca rezultatul obţinut să fie
corect.

Funcţia factorial are atât o definiţie iterativă cât şi una recursivă.


 Definiţia iterativă este un ciclu de N înmulţiri:
N! = 1*2*3*4*5*6*.....*N

Algoritmul iterativ ce poate fi folosit este:


F=1 F=F * I pentru I=1....N

 Definiţia recursivă se bazează pe valoarea funcţiilor anterioare care nu sunt cunoscute


N! = N*(N-1)! cunoscând că 1! =1, care este condiţia de ieşire din ciclul recursiv

Se scrie programul principal, care transmite în AX valoarea lui N, iar procedura Fact va returna în
AX rezultatul N!.
S-a făcut o exemplificare grafică a algoritmului pentru N=5.
La intrarea în procedură vom găsi în stivă adresa de revenire notată C2.
In procedură se decrementează AX şi se cheamă recursiv procedura Fact.
La fiecare Call de procedură se pune în stivă adresa de revenire C3.
Când AX=1 se sare la eticheta C1 unde se initializează AX=1!=1 şi BX=I=1.
Prin RET se revine la adresa din vârful stivei C3 unde se face BX=I+1=2 şi se calculează 2!.
Prin RET se revine la C3 unde se calculează BX=I+1=3 şi AX=I*2!=3!
Prin RET se revine la C3 unde se calculează BX=I+1=4 şi AX=I*3!=4!
Prin RET se revine la C3 unde se calculează BX=I+1=5 şi AX=I*4!=5!
Prin următorul RET se revine la C2 în programul principal şi AX=5!

; ----------------------------------------------------
; Program recursiv pentru calcul factorial
; Intrare AX=N Iesire AX=N!
;-----------------------------------------------------
Pfact Segment 'code'
assume cs:pfact,ds:sdate,ss:stiva
st1: mov ax,sdate ; initializare registre segment
mov ds,ax
mov ax,stiva
mov ss,ax

52
mov sp,offset top ; initializare stiva
mov ax,n ; AX=N pregatire apel subprogram
call Fact ; chemare subprogram recursiv N!

c2: mov f1,ax ; F1= N! memorare rezultat din AX


; int 3 ; terminare program
mov ax,4c00h
int 21h

; Procedura recursiva calcul N!


Fact Proc near |
dec ax |
jz c1 ; N=1 si 1!=1 N| Stiva BX AX
call Fact ; apel recursiv |
c3: inc bx ; N=N+1 1| C3 1 1!
imul bx ; N!=N*(N-1)! 2 | C3 2 2!
ret ; revenire 3| C3 3 3!
c1: mov ax,1 ; 1!=1 4| C3 4 4!
mov bx,1 ; N=1 SP 5 | C2 5 5!
ret ; revenire
Fact endp
Pfact ends
Sdate Segment 'data' ; segment de date
f1 dw 0
n dw 5
Sdate ends
stiva Segment 'stack' ; segment de stiva
dw 256 dup(?)
top equ $
stiva ends

end st1
Dacă se transmite prin stivă şi valoarea lui N la fiecare apel recursiv, atunci procedura PFACT se
modifică, fără a modifica programul principal.
In acest caz evoluţia stivei este cea din figura următoare. Este o succesiune de adrese de revenire şi de valori
ale lui N la chemarea procedurii.

N Stiva AX
1 1!=1
C3
2 2 2!=2*1!
C3
3 3 3!=3*2!

53
C3
4 4 4!=4*3!
C3
5 N=5 5!=5*5!
SP Adresa C2

FACT PROC
CMP AX,1
JZ GATA ; N=1 si 1!=1
PUSH AX
DEC AX ; N=N-1
CALL FACT ; apel recursive
C3: POP BX ;N=N+1
IMUL BX ;N! = N*(N-1) !
GATA : RET
FACT ENDP

Se observă că deşi există un singur RET efectul lui este diferit, fiindcă el face un salt la o adresă din
vârful stivei, care depinde de structura stivei.

6.8. Subprograme reentrante

Subprogramele reentrante conţin cod pur care nu se modifică în timpul rulării:


 Instrucţiuni
 Constante, mesaje sau tabele
Nu se acceptă ca un subprogram reentrant să conţină variabile care îşi modifică valoarea în timpul
prelucrării. Starea lui nu depinde de „instoria sa”. Programul poate fi memorat într-o memorie de tip ROM
(Read Only Memory).

Principalele caracteristici ale programelor reentrante sunt:


1. Subprogramul reentrant poate fi folosit simultan de mai mulţi utilizatori.
2. El poate fi întrerupt înainte de a se termina (aşteptări de date sau întreruperi de timp).
3. Pe perioada întreruperii poate fi folosit de un alt utilizator, care la rândul lui poate fi întrerupt.
4. Un program întrerupt continuă la relansare din punctul din care a fost întrerupt.
5. Fiecare utilizator va avea propria zonă de memorie care are aceeaşi structură pentru toţi, în care sunt
memorate toate variabilele din program pentru acel utilizator.
6. Programul va lucra pe o structură de date virtuală declarată cu STRUC, care se aplică peste zona
utilizatorului activ.
7. Zona de lucru activă se specifică printr-un registru de segment care se încarcă la activarea unui
utilizator.
8. La fiecare întrerupere de program starea programului întrerupt se memorează în zona de lucru a
utilizatorului care a fost activ (registre, IP, Flag-uri).
9. La activarea unui nou utilizator se va încărca din zona sa de lucru starea programului şi se va
continua din punctul în care a fost întrerupt.

54
In figura următoare se prezintă schematic modul de structurare a datelor la un program reentrant.

CS Program reentrant
------------
------------ cod pur
------------

DS DS
Zona date user1 Zona date user2 Zona date user3
N -------- -------
S -------- -------
X------- -------- -------
--------- -------- ------

Stare registre

Program reentrant pentru introducere şi afişare texte pe linii


Considerăm mai mulţi utilizatori care lucrează simultan de la 3 console şi introduc fiecare câte un
text şi pot fi întrerupţi după fiecare rând introdus.
Fiecare utilizator are o zonă de date proprie de 10 linii x 40 caractere, dar cu aceeaşi structură. Numărul de
linii N introduse de fiecare utilizator este diferit şi se tine la începutul zonei. Prima adresă liberă din text
unde se va scrie următoarea linie este dată în al 2-lea cuvînt al zonei (N*40). Indexarea liniilor de text se
face cu DI.

Structură Zonă
0 Număr linii introduse
2 Index prima linie liberă în zona
4 Linie 1
44 Linie 2
84 Linie 3
--------

Deoarece folosim pentru simulare consola unui singur calculator vom stabili structura liniei de text care va
conţine:
NA – Număr de caractere aşteptate
NR – Număr de caractere recepţionate
NRT – Numar terminal 0,1,2 (număr user)
CDA – Comanda introdusă care poate fi A – afişare text introdus
Text – linie text de maxim 40 carctere I – introducere linie de text
S – Stop oprire lucru pentru utilizatorul curent
Structură liniei de la consolă
BUF NA NR NRT CMD Linie text (max 40 caractere)

55
Comanda (A-afişare,I-introducere,S- stop)
Număr terminal (nr user)
Număr caractere recepţionate
Număr caractere aşteptate
Deoarece liniile introduse sunt de lungime variabilă, trebuie păstrată lungimea lor în zona de lucru.
Pentru afişarea acestor linii s-a utilizat o macroinstrucţiune de afişare AFIS, care pune după ultimul caracter
din fiecare linie semnul $, pentru ca restul de caractere până la 40 să nu se afişeze.
Pentru a putea calcula adresa fiecărei zone, care se va încărca în registru BX, s-a generat o tabelă de
adrese zone TZ. De aici adresa zonei se ia indexat cu numărul terminalului.

tz dd z1,z2,z3 ; adrese zone de date utilizator (far)


-----
mov bh,0
mov bl,buf+2 ;nr terminal
and bl,0fh
shl bx,2 ;NT*4
lds ax,tz[bx] ;adresa zona
mov bx,ax

; ----------------------------------------------------------------------
; REENTR * Program reentrant de introducere si afisare texte (Lab8)
; -----------------------------------------------------------------
; structura buf NA - nr caractere asteptate
; buf+1 NR - nr caractere receptionate
; buf+2 TR - nr terminal
; buf+3 c-da A-afisare, I-introducere, S-stop
; buf+4 linie text, lung=40 caractere
.286
stiva SEGMENT stack ; segment stiva
dw 100
top equ $ ; virful stivei
stiva ENDS

Sd1 SEGMENT ; segment de date


tz dd z1,z2,z3 ; adrese zone de date utilizator (far)
mes db 10,13,'Introduceti nr utiliz,c-da (A,I),text ',10,13,'$'
db 10,13
buf db 40,0,45 DUP(0),'$' ; bufer receptie
z1 dw 0,4 ;nr linii si index
db 400 dup(0) ; max 10 linii*40 caractere
z2 dw 0,4
db 400 dup(0) ; zona date 2
z3 dw 0,4
db 400 dup(0) ; zona date 3

56
Sd1 ENDS

Z STRUC ;structura zona date utilizator


n dw 0 ;nr linii introduse
index dw 0 ;index linie libera
tx dw 40*10 dup(?) ;linii de text
Z ENDS

; Segment de code
prr SEGMENT 'code'
assume cs:prr,ds:sd1,es:sd1,ss:stiva
; afisare text cu lung pe octet 1 si urmat de CR,LF
afis MACRO buf1
pusha
mov ah,0
mov al,buf1 ;lungime
mov si,ax
mov word ptr buf1[si+1],0a0dh ;CR si LF
mov buf1[si+3],'$'
mov dx,offset buf1+1 ;inceput text
mov ah,9 ;afisare
int 21h
popa
ENDM
;
st1 label far
mov ax,sd1
mov ds,ax
mov es,ax
mov ax,stiva
mov ss,ax
mov sp,offset top
c1: mov ah,9
mov dx,offset mes ;afisare mesaj
int 21h
mov dx,offset buf;asteptare mesaj
mov ah,10
int 21h
cmp buf+3,'s' ;terminat
jnz c2
mov ah,4ch ; sfarsit program

57
int 21h
c2: mov ch,0
mov cl,buf+1 ;nr caractere receptionate
inc cx ;se memoreaza si lungimea
mov bh,0
mov bl,buf+2 ;nr terminal
and bl,0fh
shl bx,2 ;NT*4
lds ax,tz[bx] ;adresa zona
mov bx,ax
cmp buf+3,'i' ;introducere
jnz c3
; Introducere rind text
mov di,bx ;inceput zona
add di,[bx+index] ;adresa rind liber
mov si,offset buf+1 ; adresa rind in bufer cu lung
rep movsb ;transfer rind in zona
inc [bx+n] ;nr inregistrari in zona
add [bx+index],40 ;index rind curent in zona
jmp c1
c3: cmp buf+3,'a' ; afisare text zona selectata
jnz c1
; Afisare text introdus
mov dx,[bx+n] ;nr linii text
mov si,bx ; SI=adresa zona
add si,4 ;prima linie
c4: mov cx,40 ;lungime
mov di,offset buf+1 ; adresa rind curent
rep movsb ; mutare rind in bufer
afis buf+1 ;afisare sir cu lung pe octet 1
dec dx ;contor linii
jnz c4 ;afisare rind urmator
jmp c1 ;dialog - Terminare prin S la dialog
prr ENDS
END ST1

7. MACROINSTRUCTIUNI
7.1. Funcţii DOS de intrare/ieşire

58
Funcţiile DOS sunt un caz particular de subprograme existente în sistemul de operare DOS, care
se apelează prin întreruperi. Apelul funcţiilor DOS este independent de Versiunea sistemului de operare.
Transmiterea parametrilor se face prin registre sau prin zonă de memorie.
Oricare comandă DOS are o funcţie corespondentă care poate fi apelată din programe scrise în limbaj de
asamblare. Se pot construi aplicaţii care utilizează comenzile DOS în programe. Din această categorie face
parte şi Norton Commander, sau Windows Commander.

Apelarea unei funcţii DOS de intrarea ieşire se face printr-o secvenţă de forma:

MOV AH,cod_funcţie ; codul funcţiei DOS se încarcă în registrul AH


MOV reg1,par1 ; pregătire parametrii în registre
MOV reg2,par2
INT 21H ; apel funcţie (subprogram) prin întrerupere 21H

Intreruperea 21H serveşte la apelarea a zeci de funcţii indicate prin codul funcţiei ce se încarcă în
registrul AH. Fiecare funcţie necesită un număr de parametrii care se încarcă în registre.

Oprire program cu revenire în DOS se realizează cu funcţia care are codul 4CH
MOV AH,4CH ; cod funcţie revenire în DOS
INT 21H

Funcţiile de intrare ieşire referitoare la dialogul cu operatorul sunt:

01H Citire de la tastatură un caracter ASCII cu ecou în registrul AL.


Ecou înseamnă afişare caracter tastat şi pe pe ecran.

02H Afişare un caracter ASCII din registru DL pe monitor.

03H Citire în AL un caracter de la intrarea AUX, care este în mod normal portul de
comunicaţii seriale COM1 (2400 bauds, fără paritate ,1bit de Stop, 8 biţi de date).

04H Trimite din DL un caracter ASCII spre portul serial AUX.


05H Tipăreşte din DL un caracter ASCII la imprimantă.

06H Intrare ieşire directă fără ecou serveşte la transmiterea caracterelor funcţionale(CTRL+)
Dacă DL=FFH aşteaptă un caracter în AL de la tastatură
Z=1 dacă nu s-a tastat caracter şi se aşteaptă
Z=0 dacă s-a apăsat o tastă caracterul se găseşte în AL
AL=0 indică recepţia unui caracter funcţional a cărui cod se citeşte prin următoarea c-dă
Dacă DL#FFH se afişează caracterul din DL

07H Citire directă în AL de la tastatură fără ecou (nu verifică CTR/BRK)

09H Afişare la consolă şirul de caractere terminat cu $ indicat în registrul DX


0AH Citire de la tastatură un şir de caractere cu ecou terminat cu ENTER, la adresa din DX.

DX
NA NR Text

59
NA - număr de caractere maxim aşteptate (dacă se introduc mai multe de NA-1 se ignoră)
NR - număr de caractere recepţionate până la ENTER

2AH Obţinerea datei curente AL – ziua în săptămână (0 duminică, 1 luni,...)


CX – anul ( 1980-2098)
DH – luna (1...12)
DL – ziua (1....31)
2BH Setare dată în calculator CX- anul, DH – luna, DL – ziua

2CH Obţinere ora curentă CH - ora (0..23), CL – minutul, DH secunda, DL – Sutime secundă

2DH Setare ora în calculator CH - ora, CL – minutul, DH secunda, DL – Sutime secundă

7.2. Citire caractere funcţionale


In aplicaţiile actuale ( editoare de texte, programe de baze de date, programe de grafică,..) se
folosesc foarte des caractere funcţionale( Extended ASCII- Coded Keyboard Data) , care sunt filtrate de
către funcţiile DOS de citire şi afişare şir de carctere (09H, 0AH, 01H, 02H). Codurile acestor caractere se
suprapun peste codurile caracterelor ASCII uzuale. Din această categorie fac parte tastele funcţionale
F1..F12, săgeţile, PageUp, PageDown,End, Home, Del, Shift +Fi, ESC şi caracterele însoţite de CTRL
(Controle) şi ALT (Alternate). Numărul acestor coduri este foarte mare şi pentru citirea lor în registrul AL
fără a fi filtrate se utilizează funcţia 06H din DOS şi se setează DL=0FFH. La recepţia unui caracter
funcţional AL=00 şi trebuie apelată încă odată funcţia DOS (INT 21H) când se primeşte codul caracterului
ce se va interpreta prin program ca un caracter funcţional. Pentru funcţia 06H nu se aşteaptă apăsarea unei
taste. Prin program trebuie testat dacă s-a apăsat o tastă lucru indicat prin Z=0. Cât timp Z=1 se aşteaptă prin
ciclu de apel.
Prezentăm mai jos o procedură care poate citi de la tastatură şi caractere funcţionale. Pentru
caractere funcţionale se poziţionează C=1, pentru a putea să fie tratat caracterul ca funcţional în programul
care a apelat procedura

ReadF PROC far


C1: MOV AH,6 ; cod funcţie citire afişare fara ecou
MOV DL,0FFH ; funcţie citire tastă in AL
INT 21H ; apel DOS
JZ C1 ; Z=1 ciclu de asteptare nu s-a apasat tasta
OR AL,AL ; test dacă AL =00H şi C=0
JNZ C2 ; nu este caracter funcţional
INT 21H ; apel 2 care dă codul caracterului în AL
STC ; poziţionare C=1 pentru a indica programului caracter functional
C2: RET
CARF ENDP

CALL ReadF ; chemare procedura citeste un caracter (inclusiv functional)


JC Funct ; eticheta secventa analiza caracter functional
MOV Text1[SI],AL ; caracter ASCII uzual memorat intr-o zona de text
.......... ; continuare program

60
61
7.3. Definire macroinstrucţiuni

Macroinstrucţiunile sunt secvenţe de instrucţiuni definite ca machetă pe baza unor parametrii


formali prin directiva MACRO. Utilizarea unei macroinstrucţiuni se face ca şi pentru o instrucţiune
cablată. Macroinstrucţiunile permit o programare modulară simplă prin:
 Extinderea setului de instrucţiuni recunoscute de Asamblor
 Simplificarea scrierii secvenţelor de cod utilizate repetat, prin înlocuirea lor cu macroinstrucţiuni.
 Simplificarea apelului funcţiilor sistem prin definirea lor ca macroinstrucţiuni
 Apelul simplu al subprogramelor, prin înlocuirea secvenţelor de apel şi pregătirea parametrilor cu
macroinstrucţiuni.

Definirea unei macroinstrucţiuni se face ca pentru un subprogram din limbajele de programare de nivel
înalt specificând:
 numele macroinstrucţiunii prin eticheta directivei MACRO
 lista de parametrii formali utilizaţi
 secvenţă de instrucţiuni care definesc algoritmul pe baza parametrilor formali, ai variabilelor şi
constantelor din program
 sfârşitul unei macroinstrucţiuni se specifică prin directiva ENDM
 etichetele din secvenţa de instrucţiuni cu directiva LOCAL

nume_macro MACRO param1,param2,..... ; lista de parametrii formali


LOCAL etich1,etich2,... ; listă de etichete locale
........
; Secvenţă de program care utilizează parametrii formali
........
ENDM ; sfârşit secvenţă de program de definiţie

Utilizarea unei macroinstrucţiuni definite se face ca pentru o instrucţiune, specificând parametrii


efectivi care vor înlocui în secvenţa de program generată parametrii formali. Definirea macroinstrucţiunii
trebuie făcută înainte de utilizare, în cadrul programului.
Nume_macro par1,par2,....

Exemplul 1. Afişare şir de caractere prin apel funcţie DOS definită ca macroinstrucţiune.
AFIS MACRO mesaj ; definire macroinstrucţiune AFIS
MOV DX,offset mesaj ; adresă text de afişat terminat cu ’$’
MOV AH,9 ; cod funcţie DOS
INT 21H ; apel funcţia de afişare
ENDM ; sfârşit secvenţa de definiţie

Utilizare macroinstrucţiune AFIS în program pentru afişare text :


AFIS text1 ; afişare şir de la adresa text1

In program unde s-a utilizat macroinstrucţiune se va genera secvenţa:


MOV DX,offset text1
MOV AH,9
INT 21H

62
Exemplul 2. Medie aritmetică a două numere definită ca macroinstrucţiune:
MED MACRO X,Y,Z ; definire medie Z= (X+Y)/2
MOV AX,X
ADD AX ,Y ; AX=X+Y
SHR AX,1 ;AX=(X+Y)/2
MOV Z,AX ; Z=AX memorare rezultat
ENDM
Media C între două numere A şi B se va calcula prin:
MED A,B,C

Exemplul 3. Conversia zecimal-binară a unui număr definită ca macroinstrucţiune, care apelează


procedura de conversie CZB definită anterior.
C_ZB MACRO zec,n,bin ; conversie nr. zecimal de la adresa zec în binar la adresa bin
MOV BX,offset zec ; adresa numar zecimal ASCII
MOV CX,n ; numar de cifre zecimale
CALL CZB ; apel procedura conversiecare returneaza numar binar in AX
MOV bin,AX ; memorare numar binar la adresa bin
ENDM

Pentru conversia unui număr Xzec din zecimal în binar la adresa X se va scrie:
C_ZB Xzec,5,X ; este similară unei instrucţiuni cablate

Etichetele locale din MACRO se definesc prin directiva LOCAL.


Dacă avem etichete în definirea MACRO acestea nu pot fi folosite direct, deoarece secvenţa de
program se generează de mai multe ori şi etichetele se duplică. Etichetele definite cu directiva LOCAL vor
fi modificate la fiecare utilizare a MACRO, folosind elemente de timp din momentul generării şi vor fi
unice în program.

MAC1 MACRO X,Y


LOCAL E1,E2 ; definire etichete locale
CMP X,Y
JZ E2 ; ieşire din secvenţa de calcul
E1: MOV AX,X
......
DEC word ptr X
JNZ E1 ; salt la eticheta locala care va fi modificata la compilare
E2 LABEL near ; eticheta dupa ultima instructiune din MACRO
ENDM

7.4. Macroinstrucţiuni şi subprograme.

Macroinstrucţiunile se folosesc pentru algoritmi care se realizează prin secvenţe scurte de câteva
instrucţiuni. La fiecare utilizare se generează secvenţa de program din definirea MACRO. Nu se vor defini
macroinstrucţiuni pentru algoritmi care se realizează cu un număr mai mare de instrucţiuni (conversii,
înmulţire de matrici, etc.).
Pentru cazul unei aplicaţii cu algoritmi mai complecşi se va folosi programarea modulară:
 Se vor analiza funcţiile ce trebuie realizate, pentru care se vor definii proceduri.

63
 Se va defini fiecare procedură pentru a specifica algoritmul folosit şi se vor stabili convenţiile de
transmitere a parametrilor spre procedură.
 Se va defini o macroinstrucţiune pentru fiecare procedură, care va defini secvenţa ce pregăteşte
parametrii, apelează procedura şi memorează rezultatele.
 Se va scrie un program principal care va utiliza macroinstrucţiuni pentru a realiza funcţiile dorite.
Apelul subprogramelor devine transparent la acest nivel şi programarea se simplifică

Exemplul 4. Program complex care utilizează proceduri şi macroinstrucţiuni care pregătesc parametrii
pentru apelul procedurilor. In cadrul programului se realizează funcţiile:
 Se citesc 10 numere zecimale de la tastatură de 1...5 cifre ( numărul de cifre în octet buf+1)
 Se converteşte în binar pe 2 octeţi fiecare număr citit şi se memorează într-un tabel
 La conversia zecimal binară se verifică fiecare caracter introdus dacă este cifră( 0...9)
 Se afişează tabelul nesortat
 Se sortează tabelul în ordine crescătoare
 Se afişează tabelul sortat convertind în zecimal fiecare număr binar în buffer

Programul are următoarea structură:


 Definire date într-un segment de date
 Definire macroinstrucţiuni ce pregătesc parametrii şi apelează subprogramele definite sau funcţii
DOS şi se folosesc în programul principal sau proceduri.
 Definire subprograme necesare, care se apelează prin macroinstrucţiunile definite
 Programul principal care utilizează numai macroinstrucţiuni prin care se apelează procedurile.

In cadrul programului s-au definit procedurile:


 CBZ şi PRINTR realizează conversie binar zecimală şi afişează numărul zecimal
 DECTOBIN conversie zecimal binară , verificare că avem numai cifre şi + sau - .
 SELSORT sortare tabel de N numere binare pe 2 octeţi

Macroinstrucţiunile sunt definite la începutul programului şi sunt folosite în programul principal şi


în proceduri:
 PRINT afişare text terminat cu ’$’ (apelare funcţie 09H dinDOS).
 GET citire şir de caractere de la tastatură (funcţia 0AH din DOS) şi trecere la rând nou.
 PUTC Afişare un caracter pe monitor din DL (funcţia 02H din DOS)
 CONVBIN conversie număr zecimal( lung. pe primul octet din şir) în binar, care apelează procedura
DECTOBIN şi îi transmite adresa numărului zecimal în SI şi lungimea în CX.
 SORT sortare tabel de n numere binare pe 2 octeţi
 SCRIE afişare tabel de n numere binare pe 2 octeţi după ce sunt convertite în zecimal

64
; Program care utilizeaza macroinstructii pentru chemare subprograme
; - Citire un sir de numere ; Conversie zecimal binar ; Memorare in tabel
; - Sortare tabel ; Conversie binar zecimala ; Afisare elemente tabel sortat
; ------------------------------------------------------------------------------------
dosseg
.model small
.data
buf db 7,8 dup(?) ; buffer primire 7 cifre
table dw 10 dup(?) ; tabel numere binare receptionate
mes db 'Introduceti 10 nr. intregi cite unul pe linie',13,10,'$'
smsg db 'Nr. sortate sunt:',13,10,'$'
bufs db 10 dup (20h),13,10,'$'
inval db 'Nr. invalid',13,10,'$' ; mesaj pentru numar invalid (litera semn,)
zece dw 10 ; constanta 10 pentru conversiiBinar zecimale
cr db 13,10,'$ ; cr si lf
.stack 256 ; segment stiva
.code ; segment de cod program
PRINT MACRO msg ; afisare mesaj terminat cu $
mov dx,offset msg
mov ah,09h
int 21h
endm
GET MACRO buff ; citire sir
mov dx,offset buff ; adr. buf. receptie
mov ah,10
int 21h
print cr ; rind nou
endm
PUTC MACRO ; afisare caracter din DL
push ax
mov ah,2
int 21h
pop ax
endm
CONVBIN MACRO buff ; conversie zecimal binara sir
mov si,offset buff
inc si
mov cl,[si] ; contor nr. cifre
inc si ; prima cifra
xor ch,ch
call dectobin ; chemare subprogram
endm
SORT MACRO tab,cnt ; sortare tabel de n elem
mov si,offset tab ; adresa tabel intregi
mov cx,cnt ; nr elemente tabel
call selsort ; subpr. sortare tabel
endm
SCRIE MACRO tab,cnt ; afisare tabel n elemente intregi
Local s1
mov cx,cnt ; nr. elemente
65
mov di,0 ; index in tabel
s1: mov ax,tab[di] ; T(I)=>AX
mov bx,offset bufs ; adresa bufer conversie
mov si,7
call cbz ; subpr. conv. bin-zec si afisare
add di,2
loop s1
endm
; include bindec.inc ; se pot copia subprogramele de conversie bin-zec si zec-bin
;------------------------------
CBZ PROC near
; Afiseaza un numar binar din ax dupa ce il
; converteste in zecimal cu + sau - in fata
;------------------------------
or ax,ax ; pozitionare indicatori
jns pos ; numar pozitiv
neg ax ; val absoluta
mov dl,'-'
putc ; afisare un caracter din dl
pos: call printr ; procedura recursiva conv bin-zec
print cr ; rind nou
ret
CBZ ENDP
; ---------------------------
PRINTR PROC near
; In AX nr pozitiv binar, resturile MOD 10
; afisate in ordinea inversa obtinerii
cwd ; pregatire impartire DX=0
idiv zece ; N/10 restul in dx, citul in AX
or ax,ax ; cit=0 ?
jz gata1 ; da
push dx ; memorare rest
call printr ; apel recursiv
pop dx ; reface restul
gata1: or dl,30h ; cifra ASCII
PUTC ; afisare cifra din dl
ret
PRINTR ENDP
; ---------------------------
SELSORT PROC near
; Procedura sortare tabel elemente binare
; SI - adresa primul element; CX - nr. de elemente
; ----------------------------
mov bx,si
c1: dec cx
jz gata
push cx
mov si,0
mov dh,0
c2: mov ax,[bx+si]
66
cmp ax,[bx+si+2]
jl c3
xchg ax,[bx+si+2]
mov [bx+si],ax
inc dh
c3: add si,2
loop c2
or dh,dh
pop cx
jz gata
jmp c1
gata: ret
SELSORT ENDP
;--------------------------------------
SELS PROC near ; Subprogram sortare prin selectie
; SI - adresa primul element ; CX - nr elemente
; -------------------------------------
cld ; directie stg-dr
dec cx
nextp: push cx ; n-1 cicuri
lodsw ; primul element [SI]
mov di,si ; cautare in sir nesortat
nexte: scasw; ; compara ax cu[DI]
jle ismin ; ax<=[DI]
xchg ax,[DI-2] ; noul minim
ismin: loop nexte
mov [si-2],ax ; memorare minim
pop cx
loop nextp ; cauta urmatorul minim
ret
SELS ENDP
;--------------------------------------
DECTOBIN PROC near
; Procedura conversie zec-binara cu semn
; SI - adresa prima cifra
; CX - numar cifre
dec cx ; ciclu semn
cld ; df=0
lodsb ; primul caracter
cmp al,'-' ; semn minus
stc ; cf=1
jz minus
cmp al,'+' ; semn plus
jz plus
inc cx ; fara semn, corectie contoare
dec si
plus: clc ; cf=0
minus: pushf ; salvare indicatori
xor bh,bh
xor ax,ax ; N=0
67
cwd
next: mov bl,[si] ; o cifra zecimala
cmp bl,'0' ; verificare numeric
jl nodigit ;err.
cmp bl,'9'
jg nodigit ;nu-i cifra
sub bl,30h
mul zece ; N=N*10
add ax,bx ; N=N*10+cifra
inc si
loop next ; urmatoarea cifra
popf ; reface indicatori
jnc pozitiv
neg ax ; numar negativ
clc
pozitiv: ret
nodigit: print inval ; mesaj numar invalid
popf
xor ax,ax
stc ; setare CF=1 nr.invalid
ret
dectobin endp
; -------------------------------------
; Program principal
; -------------------------------------
pp: mov ax,@data ;initializare reg segment
mov ds,ax
mov es,ax
print mes ; mesaj dialog
mov cx,10 ; numere de introdus
mov di,0 ; prima pozitie in tabel
cit label near
push cx
push di
get buf ; asteapta un numar
convbin buf ; AX nr. binar rezultat
pop di
pop cx
jc cont ;daca c=1 atunci nr citit este invalid
mov table[di],ax ; memorare numar binar in tabel
inc di
inc di
cont: adc cx,0 ; neglijare numar eronat
loop cit
scrie table,10 ; afis. tabel nesortat
sort table,10 ; sortare tabel
scrie table,10 ; afisare tabel sortat
mov ah,4ch ; stop
int 21h
end pp
68
8. UTILIZAREA FISIERELOR PE DISC

8.1 Organizarea fişierelor pe disc

In memoria centrală se poate memora un volum redus de date care pot fi adresate într-un timp
foarte scurt de ordinul 10nsec. Aceste date nu sunt persistente ele fiind pierdute la deconectarea
calculatorului.
Pe hard/floppy disc se memorează persistent ca fişiere volumele mari de informaţii şi programele,
care pot fi ulterior regăsite şi citite în memoria centrală pentru prelucrare. Informaţiile pe disc se pot
memora numai ca fişiere pentru care se asigură gestiunea spaţiului de memorare şi securitatea accesului
prin utilizarea funcţiilor DOS. Timpul de acces la informaţiile de pe disc de cca 10msec este de 1 milion de
ori mai mare decât la RAM.

Timp acces disc 10ns


------------------- = ------ = 1.000.000
Timp acces RAM 10ms

Din acest motiv nu se recomandă utilizarea directă a informaţiilor din fişierele disc ci se citesc
blocuri întregi de informaţie în RAM unde se va face prelucrarea.

Organizarea fizică a informaţiilor pe disc

Floppy discul de 3 ½ inch are ambele fete active şi câte un cap de citire pentru fiecare faţă rezultând
o capacitatea de 1.44Mocteţi.
2 feţe x 80 piste x 18 sectoare/pistă x 512 octeţi/sector = 1.44Mo
Sectoarele sunt subdivizini ale pistei pentru a putea adresa mai fin informaţia. Uzual se folosesc sectoare de
512 octeţi atât pentru floppy cât şi pentru hard discuri. Sectoarele sunt separate de spaţii goale ’gap’
corespunzător a cca 10-12 octeţi.

Pista 0

Hard discul este format dintr-un pachet de 2-5 discuri de 3½ inch, ce au ambele feţe active şi au un
sistem de capete magnetice de citire mobile, câte unul pentru fiecare faţă activă. Scrierea se face serial prin
dipoli magnetici pe cercuri concentrice numite piste. Un disc are funcţie de capacitate peste 10.000 de piste.
O pistă este împarţită în sectoare, a căror număr diferă de densitatea permisă de tehnologie. Pistele de pe
aceeaşi verticală formează un cilindru. Poziţionarea blocului capetelor de citire pe un cilindru este realizată
automat de electronica de pe disc şi de interfaţa cu discul. Pentru a minimiza mişcările mecanice,

69
parcurgerea şi numerotarea pistelor se face pe cilindrii de sus în jos. La un moment dat este selectat un
singur cap de citire, deci o singură pistă de pe cilindru. Cilindrii se numerotează de la exterior spre interior.
Selectarea unui sector de pe pistă se face dinamic prin numărul său plasat ca informaţie de control la
începutul sectorului. Discul se învârte continuu cu viteză constantă de 2400, 3600, 5200 sau 7200rot/minut.
La turaţii mai mari debitul instantaneu de octeţi transferaţi este mai mare ( de 3 ori mai mare la 7200rot faţă
de 2400).
Structura unui sector este:

gap iiiiii Cilindru Cap Sector iii Informaţie utilă par


Sync Adresa sector syn 512 octeţi

Gap - spaţiu intersector ( 16 biţi de 0)


Sync - informaţii de sincronizare (64 biti de 1) indică început sector
Cilindru – număr cilindru pe care se găseşte sectorul
Cap - numărul pistei de pe sector (cap de citire ce trebuie selectat)
Sector - număr sector pe pistă
Syn - biţi de 1 pentru aşteptarea verificării adresei sectorului căutat
Par - 1 octet pentru control ciclic de paritate pentru octeţii din sector

Prezentăm ca exemplu un hard disc de 40Mo care mai respectă structura fizică:
 5 feţe active pe 3 discuri fizice în pachet (5 capete de citire)
 976 cilindri =82.960 sectoare x 512 octeţi =40Mo
 1cilindru = 5 piste x 17 sectoare/pistă = 85sectoare x 512octeţi =42.5Ko
 1 pistă =17sectoare x 512octeţi = 8.5Ko
DiamondMax Plus 9 PATA MAXTOR Ultra DMA133 7200 RPM:
MODEL CYL HDS :SECT MaxCil Max LBA GB Capacity

6Y060L0 119,150 16:63 16,383 120,103,200 60GB

6Y080L0 / 6Y080P0 158,816 16:63 16,383 160,086,528 80GB

6Y120L0 / 6Y120P0 238,216 16:63 16,383 240,121,728 120GB

6Y160L0 / 6Y160P0 317,632 16:63 16,383 320,173,056 160GB

6Y200P0 395,136 16:63 16,383 398,297,088 200GB

6Y250L0 / 6Y250P0 486,344 16:63 16,383 490,234,752 250GB

“L” in model denotes ATA/133 2 MB Transfer, “P” - 8 MB Buffer PATA = Parallel ATA MAXTOR.com
NOTE: NEVER enter more than 16,383 cylinders in the system BIOS. This may potentially cause data loss.

Adresa sectorului se ia la discurile actuale global fiindcă numărul de biţi alocaţi iniţial pentru cilindru
este insuficient şi nu se mai poate respecta structura. Apare în acest caz o structură logică de adresare (LBA)
care pentru discurile Maxtor de 80GB (LBA=160 milioane de sectoare) avem CIL=16.000, HEAD=16 şi
SECT=63, în timp ce numărul real de cilindrii este de 160.000. Se foloseşte aceeaşi tehnologie, dar
capacitatea diferă funcţie de densitatea radiară (nr. cilindri ) şi numărul de discuri în pachet.
Logic un disc este văzut în program ca o memorie cu N sectoare de 512 octeţi, 160.000.000 pentru un
disc de 80MB.

Discul cuprinde 4 zone:

70
 Sectorul de boot conţine programul de preîncărcare în RAM a nucleului DOS format din fişierele
sistem IO.SYS şi MSDOS.SYS
 File Alocation Table (FAT) conţine tabela de alocare discului
 Root directory conţine directorul rădăcină pentru 128 fişiere disc (4K)
 Zona fişiere împărţite în clustere. Unele fişiere pot fi director.
Cluster-ul este unitatea de alocare pe disc şi poate fi de 1-64 sectoare (0.5-32K). Numărul total de
clustere este limitat la 64.000 de capacitatea de adresare a tabelei de alocare FAT, care conţine intrări pe 16
biţi. La floppy disc alocarea se face la nivel de sector (cluster=512oct), iar la discurile mari pentru
cluster=32K capacitatea de adresare este de 2GB. Aceasta a dus la mărirea adresei de cluster din FAT la 32
biţi, care permite 2 miliarde de clustere. In ultimii 15 ani s-au trecut 10 bariere de capacitate, care au impus
modificarea nucleului BIOS (Basic Input/Output System).

Tabela de alocare a discului (FAT) conţine o intrare pentru fiecare cluster de forma:

Număr cluster alocat Adresa urmatoare în FAT Nr.cluster=00 liber


16 sau 32 biţi 16 biţi FFFF pt cluster defect

Directorul rădăcină conţine 128 intrări de 32 octeţi de forma:


0 8 11 12 22 24 26 28
Nume fişier Ext Atrib Neutiliz timp data Intr.FAT Lung fis

FAT
Nr.clust Ch

Intrarea de director a unui fişier conţine adresa primei intrări în FAT, care specifică adresa primului
cluster alocat şi următoare intrare (Ch) din FAT pentru fişier. La crearea unui fişier i se alocă un cluster şi
când acesta este plin i se alocă următorul.
Pentru discul curent se ţine în memorie în 2 exemplare tabela de alocare FAT.
Fiecare fişier are un atribut care indică modul de acces:
Atribut
00 A D V S H R A-archive, D-subdirector, V-etichetă volum, S-sistem,
H-hide, R-Read-only

Spaţiul pentru un fişier este discontinuu pe disc, fiind format din clustere plasate în diferite zone
ale discului, unde s-a găsit un cluster liber. La ştergerea unui fişier clusterele alocate se eliberează pentru a fi
realocate. Pentru programator un fişier este un spaţiu continuu, care se adresează relativ la începutul
fişierului.

8.2. Exploatarea fişierelor pe disc prin FCB

Sistemul de operare DOS asigură gestiunea şi securitatea informaţiilor pe disc ca fişiere (inclusiv
sistem). Pentru crearea, ştergerea, scrierea, citirea şi actualizarea fişierelor există funcţii DOS care se
apelează din program prin INT 21H. Parametrii necesari se transmit prin registre sau printr-o zonă de
71
memorie pentru dialog ataşată fişierului numită FCB (File Control Bloc). Există 2 modalităţi de exploatare
a fişierelor, care au concepte diferite şi funcţii specifice, dar aceeaşi organizare fizică:
 Utilizare FCB pentru comunicare cu sistemul şi se citesc/scriu înregistrări de lungime dată.
Adresarea se face la nivel de înregistrare.
 Utilizare indicator logic (handle), care face referire la un FCB din sistem şi permite adresarea
fişierului la nivel de octet relativ la începutul fişierului.

Exploatarea cu FCB presupune declararea unui FCB pentru fiecare fişier utilizat.
Structura FCB cuprinde pe 36 octeţi informaţii furnizate de program şi informaţii returnate de sistem după
executarea unei operaţii (funcţii):
DS:DX
0 1 9 12 14 16 20 22 24 32 33
Cod Nume Ext Nr.bloc Lung Lung Data Timp rez Nr.inreg Nr. inreg.
disc fişier inreg fişier in bloc acc direct

Pentru FCB s-ar putea declara o structură de date de forma:

FCB SRUC
Drive db 0 ; cod disc utilizat
Fnume db 8 dup (20h) ; nume fişier
Fext db 3 dup (20h) ; extensie nume
Lrec dw 80 ; lungime înregistrare
Lfis dd 0 ; lungime fisier
Fdate dw 0 ; data de creare
Ftime dw 0 ; ora de creare
Frez db 8 dup(0) ; rezervat
Fnrc db 0 ; număr articol curent în bloc
Frand dd 0 ; numar inregistrare in acces direct (random)
FCB ENDS

Funcţii DOS pentru exploatarea fişierelor cu FCB

Orice citire de informaţie de pe disc în acces direct necesită o poziţionare pe disc pentru că FAT
este păstrată în memorie. Când se specifică adresa unui sector ce trebuie citit din fişier (relativ la începutul
fişierului), din FAT se stabileşte rapid numărul clusterului care îl conţine şi rezultă numărul sectorului fizic
în care se găseşte.

Inaintea apelării unei funcţii DOS se va încărca în DS:DX adresa FCB fişier utilizat.
După executarea unei funcţii DOS A=00 indică operaţie reuşită.

0EH - Selectare disc a cărei adresă este în DL (0-A,1-B, 2-C,..).


Se citeşte directorul rădăcină şi FAT în memoria RAM.
0FH - Deschide fişier existent în directorul curent cu numele din FCB dat de DX.
10H - Inchide fişier indicat de FCB-ul indicat de DX.
11H - Căutare primul fişier cu numele generic dat în FCB (ex.*.asm).
12H - Căutare următorul fişier cu nume generic indicat în FCB.
13H - Sterge fişier indicat în FCB, chiar şi cu nume generic

72
14H - Citeşte secvenţial o înregistrare din fişierul indicat în FCB, de lungime precizată în octet 14 din
FCB. Adresa bufer este zona curentă DTA (Disc Transfer Area). Octetul 32 din FCB (nr.înreg.în
bloc) se pune iniţial pe zero şi ulterior se
incrementează automat după fiecare citire. Se trece automat de la un bloc la altul.
15H - Scrie secvenţial o înregistrare din DTA în fişier de lungime dată de FCB+14 . Extinderea
fişierului se face automat dacă un cluster s-a umplut.
16H - Deschidere fişier nou cu numele dat în FCB. Scrie o intrare în directorul curent.
Dacă nu există spaţiu AL=0FFH.
17H - Redenumeşte fişier din FCB cu numele din octeţii FCB +17H
19H - Obţine cod disc curent în AL
1AH - Stabileşte adresa DTA (Disc Transfer Area) zonă tampon curentă dată în DX.
La iniţializare sistem adresa DTA=80H.
21H - Citire în acces direct de pe fişier, de pe sectorul dat în FCB+33.
22H - Scriere în acces direct din DTA cu specificare adresă sector disc în FCB+33.
Scrierea pe ultimul sector din fişier se face pentru rezervare spaţiu.

Exemplu de program pentru citire scriere în fişier utilizând FCB

Pentru a simplifica scrierea programului se vor folosi macroinstrucţiuni pentru apelul funcţiilor
DOS.
 Scrieţi un fişier cu un editor de texte (NotePad, F4 din Windows Commander) şi citiţi-l cu un
program, care foloseşte macroinstrucţiunilele definite.
 Modificaţi conţinutul textului din fişier şi afişaţi-l cu un editor.
 Modificaţi lungimea înregistrărilor FCB+14 şi afişaţi fişierul

; *********************************************
; Utilizare fisiere prin fcb DS:DX contine adresa FCB
; Citire text tastatura
; Scrire text pe fisier
; Citire de pe fisier si afisare
; Se utilizeaza macro definiti si control erori
; **********************************************

dosseg
.model small
.stack 100
.data
b1 db 10,13,10,13 ; CR si LF
buf db 20,80 dup(20h),10,13,'$' ; Buffer I/O
FIS db 0,'fisier txt',0,0,0,20 ; FCB fisier
db 26 dup (?)
er db ' Operatie eronata',10,13,'$'
start db ' Dialog:',10,13,'$'
LFCR db 10,13,'$'
.stack 256
.code

eroare macro coder ; Afisare eroare daca AL # 0


local gata

73
or al,al ; test eroare
jz gata ; operatie corecta
mov ah,coder
mov er,ah
afis er ; cod eroare pt fiecare macro
gata label near
endm

afis macro msg ; afisare mesaj pe ecran


mov dx,offset lfcr ; rand nou
mov ah,9
int 21h
mov dx,offset msg
mov ah,09h
int 21h
endm

cit macro buf1 ; citire sir de la tastatura


mov dx,offset buf1 ; adr. bufer receptie
mov ah,10
int 21h
endm

open macro fcb1 ; deschidere de fisier existent


mov word ptr FCB1+14,20 ; lungime inregistrare (RCS)
mov dx,offset FCB1 ; adresa FCB
mov ah,0fh ; functie DOS deschidere fisier existent
int 21h
mov FCB1+32,0 ; initializare nr. inregistrare in bloc = 0
eroare 31h ; cod eroare = 1
endm

close macro fcb1 ; inchidere fisier


mov dx,offset FCB1 ; adresa FCB
mov ah,10h
int 21h
eroare 32h ; cod eroare = 2
endm

create macro fcb1 ; creare fisier nou


mov dx,offset FCB1 ; adresa FCB
mov ah,16h ; cod functie DOS
int 21
eroare 33h ; cod eroare = 3
endm

writef macro fcb1,buf ; scrie in fisier o inreg. din zona buf


mov ah,1ah ; functie DOS setare zona DTA(disc transfer area)
mov dx,offset buf+2 ; specificare zona tampon utilizata
int 21h
74
mov dx,offset FCB1 ; adresa FCB
mov ah,15h ; functie DOS scriere secventiala pe disc
int 21h ; din zona DTA de lungime RCS din FCB+14
eroare 34h ; cod eroare = 4
endm

readf macro fcb1 ; citire inregistrare de pe disc in zona DTA


mov ah,1ah ; setare DTA
mov dx,offset buf+2
int 21h
mov dx,offset FCB1 ; adresa FCB
mov ah,14h
int 21h
endm

; Program principal
pp: mov ax,@data ;
mov ds,ax
mov es,ax
; afis buf
open fis ; deschidere fişier existent
mov fis+14,30 ;lungime inregistrare RCS
; create fis ; se crează la prima rulare
mov fis+32,0 ;nr inreg.=0
mov cx,5 ;contor nr inregistrari

; Citire text de la consolă şi scriere in fisier


c5: afis start ;afisare dialog
cit buf ;introducere rand text
writef fis,buf ;scriere pe disc
afis buf ;afisare pe disc
loop c5
close fis ;inchidere fisier

; Secventa de citire din fişier


mov cx,5 ;contor inregistrari
open fis
mov fis+32,0 ;adresare imediata
mov fis+14,30 ;lungime inreg. RCS
c6: readf fis ;citire inreg. din fisier
afis buf ;afisare inregistrare
loop c6
c1 : nop
mov ah,4ch
int 21h
end pp

75
9. EXPLOATAREA FIŞIERELOR CU INDICATOR LOGIC (HANDLE)

9.1. Conceptul de indicator logic (handle)

Alocarea fişierelor pe disc este discontinuă pe clustere a căror adresă se află din tabela de alocare a
discului (FAT). Programatorul vede fişierul ca fiind continuu, iar adresa unei informaţii se dă relativ la
începutul fişierului. Există un singur mod de organizare a fişierelor pe disc, cel prezentat la începutul
capitolului şi două moduri de exploatare:
 Exploatarea fişierelor cu utilizare FCB a fost prima modalitate existentă în DOS şi realizează
citirea/scrierea din fişier la nivel de înregistrare, specificând lungimea înregistrării şi numărul
înregistrării transferate.
 Exploatarea fişierelor cu indicator logic permite adresarea informaţiei la nivel de octet faţă de
începutul fişierului, specificând lungimea transferată în octeţi. Metoda a apărut în DOS V3, când
prin apariţia hard-disc-ului pe PC XT (10MB), sau introdus subdirectoare şi trebuia specificat
numele fişierului şi calea. In FCB se putea specifica numai numele fişierului.

In DOS V3 s-a adăugat un nou set de funcţii pentru exploatarea informaţiilor din fişiere schimbând şi
principiile de lucru. La iniţializarea sistemului se alocă un număr de peste 100 de FCB-uri gestionate de
sistem. Aceasta este limita numărului de fişiere care vor putea fi deschise simultan în aplicaţii. Numele
fişierului inclusiv calea se dă într-un text ASCII de lungime variabilă terminat cu 00H definit sub forma:

Fis1 DB ’C:\Prog\Laborator\PLA\Fisier1.txt’,0

La deschiderea fişierului se încarcă în DS:DX adresa textului care dă numele fişierului. Se caută
fişierul în directorul specificat şi i se alocă un FCB sistem al cărui handler (pointer) se returnează în
registrul AX şi se va încarcă în BX înaintea apelării altor funcţii care se referă la acel fişier. După
executarea oricărei funcţii CF=0 dacă operaţia a reuşit şi CF=1 dacă a apărut o eroare.

Dacă se utilizează exploatarea cu indicator logic atunci trebuie specificată adresa primului octet
citit/scris din fişier şi lungimea în octeţi a informaţiei transferate. Adresa octetului curent referit din fişier se
ţine în pointerul de citire/scriere (din FCB-ul alocat), care se modifică cu funcţia de poziţionare (41H). La
deschiderea fişierului adresa curentă este 0 şi se referă la începutul fişierului.

Fisier.txt
Adr.in fisier
(Pointer cit/scr)

BX=handler CX=lung in octeti

76
Memorie

DS:DX

9.2. Funcţii DOS

3CH Creare fişier (Create) Creează în directorul specificat o etichetă de fişier nouă.
AH=3CH codul funcţiei de creare fişier nou
DS:DX =adresă şir ASCII cu numele fişierului urmat de 00H
CX conţine atributul fişierului
00 – fişier normal
01 – fişier read/only (protejat la scriere)
02 – fişier ascuns
04 – fişier sistem
Ieşire dacă CF=0 atunci AX conţine indicatorul logic (handle) atribuit fişierului
CF=1 operaţie eronată şi AX conţine codul erorii
(3 nu s-a găsit calea, 4 prea multe fişiere deschise, 5 acces interzis)

3DH Deschidere fişier existent (Open) se poate deschide orice fişier inclusiv cele ascunse.
Intrare AH=3DH codul funcţiei DOS
AL conţine codul de acces
(0 citire permisă,1 scriere permisă, 2 scriere citire, primii biţi acces partajat)
DS:DX =adresă şir ASCII cu numele fişierului urmat de 00H
Ieşire AX conţine indicatorul logic (handle) sau cod de eroare (CF=1)

3EH Inchidere fişier Inchide fişierul al cărui indicator logic s-a dat în BX
AH=3EH cod funcţie DOS închidere fişier
BX =indicatorul logic al fişierului

3FH Citire dintr-un fişier (Read) indicat prin BX care conţine indicatorul alocat (handle), într-o zonă de
memorie dată prin DS:DX de la adresa de fişier indicată de pointer-ul de citire/scriere şi lungime în număr
de octeţi dată în CX.
Intrare AH = 3FH cod funcţie DOS de citire din fişier
BX = indicator logic fişier referit (handle)
DS:DX =adresă zonă de memorie (buffer)
CX =număr de octeţi transferaţi (lungime)
Ieşire AX =număr de octeţi citiţi dacă CF=0 (AX=0 este EOF sfârşit de fişier).
Incrementare automată pointer citire/scriere cu lungimea citită.

40H Scriere într-un fişier (Write) indicat prin BX, care conţine indicatorul alocat (handle), dintr-o zonă de
memorie dată prin DS:DX, la adresa de fişier indicată de pointer-ul de citire/scriere şi lungime în număr de

77
octeţi dată în CX. Pointerul de scriere/citire se incrementează automat cu lungimea transferată după
operaţie.
Intrare AH = 3FH cod funcţie DOS de scriere în fişier
BX = indicator logic fişier referit (handle)
DS:DX =adresă zonă de memorie (buffer)
CX =număr de octeţi transferaţi (lungime)
Ieşire dacă CF=0 operaţie reuşită

41H Ştergerea unui fişier a cărui nume se dă ca text ASCII în DS:DX (inclusiv calea). Dacă se omite
discul sau calea se ia din directorul curent.
AH=41H cod funcţie DOS ştergere fişier
BX=indicator logic fişier referit (handle)

42H Poziţionare pointer citire/scriere (LSEEK) pentru fişierul asociat indicatorului logic (handle) dat în
BX şi păstrat în FCB-ul alocat de sistem, precizând referinţa (adresa curentă, începutul sau sfârşitul
fişierului). După fiecare transfer pointerul de citire/scriere se actualizează cu lungimea transferată.
AH=42H cod funcţie poziţionare pe fişier
AL codul metodei de poziţionare
0 – faţă de începutul fişierului
1 – faţă de poziţia curentă
2 – faţă de sfârşitul fişierului
BX = indicatorul logic al fişierului referit (handle)
CX:DX =adresa relativă în fişier în octeţi a informaţiei ce se transferă

43H Citire/Setare atribute fişier permite schimbarea atributelor fişierului setate la creare sau pe parcurs.
AH=43H funcţie DOS setare atribute fişier
AL = cod subfuncţie (0 – citire atribute, 1 – setare atribute)
DS:DX = adresă nume fişier ca text ASCII
CX valoare atribute citite sau de setat
(0 – normal, 1 –read/only,2 – ascuns, 4 sistem, 20H arhiva).

9.3. Program de scriere si citire texte în fişier

Prezentăm mai jos un exemplu de scriere şi citire rânduri de text într-un fişier exploatat cu indicator
logic. Se observă modul de definire a numelui fişierului.
La început se definesc macroinstrucţiunile utilizate la apelarea funcţiilor DOS, care pot fi plasate
într-un fişier program separat pentru a putea fi utilizate şi din alte programe. Prin directiva INCLUDE
fişierul de macroinstrucţiuni se copiază în secţiunea .CODE din program.
Se vor concepe alte programe care să utilizeze macroinstrucţiunile definite.

; UTILIZARE FISIERE PRIN IDENTIFICATOR LOGIC


; DEFINIRE MACROINSTRUCTIUNI FOLOSITE
; =========================================

; CITIRE SIR DE LA CONSOLA SI COMPLETARE LF SI $


; -----------------------------------------
cit_sir macro sir1 ; completare CR,LF şi ’$’ după textul introdus
mov dx,offset sir1 ; adresa de receptie

78
mov ah,0Ah ; functie dos citire sir
int 21h
xor bh,bh ; in BX lungime sir receptionat
mov bl,sir1+1
mov sir1[bx+3],10 ; cod LF (linie noua) la sfirsit
mov sir1[bx+4],'$' ; indicator sfirsit sir
mov dl,10 ; linie noua dupa receptie
mov ah,02h ; functie afisare un caracter
int 21h
endm

; AFISARE SIR TERMINAT CU $ PE ECRAN


; -----------------------------------------
tip_sir macro sir2
mov dx,offset sir2 ; adresa sir de afisat
mov ah,09h ; functie afisare sir
int 21h
endm

; AFISARE EROARE DUPA EXECUTIE MACRO


; -----------------------------------------
tip_err macro nr ; afişare numar eroare
tip_sir err ; afisare mesaj de eroare
mov dl,nr ; urmat de numar eroare
or dl,30h
mov ah,02h ; afisare un caracter
int 21h
mov dl,10 ; rind nou - LF si CR
int 21h
mov dl,13
int 21h
mov ah,4Ch ; terminare program
int 21h
endm

; DESCHIDERE FISIER EXISTENT


; -----------------------------------------
op_fis macro nume1,handle ; nume si adresa indicator logic
local cont ; eticheta locala in macro
clc ; anulare fanion CF
mov ah,3dh ; functie deschidere fisier
mov dx,offset nume1 ; adresa zona cu nume fisier
mov al,02h ; mode de deschidere R/W
int 21h
jnc cont ; CF = 0 operatie corecta
tip_err al ; CF = 1 afisare eroare din AL
cont label near ; definire eticheta locala
mov handle,ax ; salvare indicator logic din AX
79
endm

; INCHIDERE FISIER
;------------------------------------------
cl_fis macro handle1 ; adresa indicator logic
local cont
clc
mov ah,3eh ; functie inchidere fisier
mov bx,handle1 ; incarcare indicator logic
int 21h
jnc cont ; CF = 0 operatie corecta
tip_err al ; CF = 1 afisare eroare din AL
cont label near
endm

; CITIRE SIR DE LUNGIME DATA DIN FISIER


; de la adresa data de pointerul de citire/scriere
; -----------------------------------------
cit_fis macro handle1,lung,buff ; handle,lungime,tampon
local cont
clc
mov ah,3fh ; functie citire fisier
mov bx,handle1 ; BX = indicator logic
mov cx,lung ; numar octeti cititi
mov dx,offset buff ; adresa zona memorie
int 21h
jnc cont ; CF = 0 citire corecta
tip_err al ; afisare eroare din AL
cont label near
endm

; SCRIERE IN FISIER UN SIR DE CARACTERE


; la adresa disc data de pointerul de citire scriere
;------------------------------------------
scr_fis macro handle1,lung,buff ; handle,lungime,tampon
local cont
clc
mov ah,40h ; functie scriere in fisier
mov dx,offset buff ; adresa zona memorie
mov cx,lung ; numar octeti transferati
mov bx,handle1 ; BX = indicator logic fisier
int 21h
jnc cont ; CF = 0 scriere corecta
tip_err al ; afisare eroare din AL
cont label near
endm
; POZITIONARE POINTER DE CITIRE SCRERE IN FISIER
; adresa octet referitor la inceputul fisierului CX,DX
; -----------------------------------------
80
lseek macro handle,tip,lung1,lung2
local cont
mov ah,42h ; functie setare pointer cit/scr
mov cx,lung1 ; adresa octet din fisier in CX,DX
mov dx,lung2
mov bx,handle ; BX = indicator logic fisier
mov al,tip ; referinta inceput=0, pozitia curenta =1, sfirsit=2;
int 21h
jnc cont ; CF = 0 operatie reusita
tip_err al ; tiparire cod eroare din AL
cont label near
endm

; PROGRAM PRINCIPAL
;=========================
dosseg
.model small
.stack 256

.data
nume_fis db 'C:\Stud\Pla\fis.txt',0 ; numele fisierului
handle dw 0 ; indicator logic fisier
buf db 50,0,50 dup (?) ; zona tampon pentru dialog
mes db 'Introduceti 10 siruri de caractere:',13,10,'$'
mes1 db 13,10,'Continutul fisierului:',13,10,'$'
err db 13,10,'Eroare scr/cit fisier nr: $'

.code
includedisclogi.inc ; definiri macro lucru cu fisiere

start: mov ax,@data


mov ds,ax
op_fis nume_fis,handle ; deschidere fisier
tip_sir mes ; mesaj dialog
mov cx,10 ; numar de rinduri citite
l1: push cx
cit_sir buf ; citire rind tastatura
scr_fis handle,15,buf+2 ; scriere rind in fisier
pop cx
loop l1 ;ciclu citire rinduri
tip_sir mes1 ; mesaj afisare fisier
lseek handle,0,0,0 ; pozitionare inceput fisier
mov cx,10 ; contor inregistrari citite
l2: push cx
cit_fis handle,15,buf+2 ; citire din fisier 15 octeti
tip_sir buf+2 ; afisare octeti cititi
pop cx
loop l2 ; ciclu citire de pe fisier
cl_fis handle ; inchidere fisier
mov ax,4C00h ; terminare program
81
int 21h
end start ; adresa de lansare

;======================================================
;program de exploatare fiserere disc cu indicator logic
;======================================================
;fisierul cu numele fis.txt se va crea vid din Norton Commander
; sau se va introduce macro de creare fisier vid(ah=3ch)
;indicatorul sfarsit de fisier(eof) este dat de ax=0
; normal dupa citire ax indica numarul de octeti cititi
;inainte de executie operatie i/e:
; bx=handle fisierului ds:dx=adresa buffer
; cx=lungime de transferat
dosseg
.model small
.stack 256
.data
nume_fis db 'fis.txt',0 ;numele fisierului
buf db 50,0,50 dup(?) ;zona dialog
mes db 'introduceti 10 siruri de caractere:',13,10,'$'
mes1 db 13,10,'continutul fisierului:',13,10,'$'
err db 13,10,'eroare scriere/citire fisier nr:$'
handle dw 0 ;indicator logic fisier
.code
include disclogic.inc ;definiri macro lucru cu fisiere

start:
mov ax,@data
mov ds,ax

op_fis nume_fis,handle ;deschidere fisier


tip_sir mes ;mesaj dialog
mov cx,10 ;numar de randuri citite
l1:
push cx
cit_sir buf ;citire rand tastatura
scr_fis handle,15,buf+2 ;scriere rand in fisier
pop cx
loop l1 ;ciclu citire randuri
tip_sir mes1 ;mesaj afisare fisier
lseek handle,0,0,0 ;pozitionare inceput fisier
mov cx,10 ;contor inregistrari citite
l2:
push cx
cit_fis handle,15,buf+2 ;citire din fisier 15 octeti
tip_sir buf+2 ;afisare octeti cititi

82
pop cx
loop l2 ;ciclu citire de pe fisier
cl_fis handle ;inchidere fisier
mov ax,4c00h ;terminare program
int 21h
end start ;adresa de lansare
---------------------------------------
Fisier disclogic.inc
;===========================================
;UTILIZARE FISIERE PRIN IDENTIFICATOR LOGIC
;DEFINIRE MACROINSTRUCTIUNI FOLOSITE
;===========================================
;CITIRE SIR DE LA CONSOLA SI COMPLETARE LF SI $
;==============================================
cit_sir macro sir1
mov dx,offset sir1 ;adresa de receptie
mov ah,0ah ;functie dos citire sir
int 21h
xor bh,bh ;in bx lungime sir receptionat
mov bl,sir1+1
mov sir1[bx+3],10 ;cod lf(linie noua) la sfarsit
mov sir1[bx+4],'$' ;indicator sfarsit sir
mov dl,10 ;linie noua dupa receptie
mov ah,02h ;functie afisare un caracter
int 21h
endm
;AFISARE SIR TERMINAT CU CARACTER PE ECRAN
;==========================================
tip_sir macro sir2
mov dx,offset sir2 ;adresa sir de testat
mov ah,09h ;functie afisare sir
int 21h
endm
;AFISARE EROARE DUPA EXECUTIE MACRO
;====================================
tip_err macro nr
tip_sir err ;afisare mesaj eroare
mov dl,nr ;urmat de numar eroare
or dl,30h
mov ah,02h ;afisare un caracter
int 21h
mov dl,10 ;rand nou LF si CR
int 21h
mov dl,13
int 21h
mov ah,4ch ;terminare program
int 21h

83
endm
;DESCHIDERE FISIER EXISTENT
;============================
op_fis macro nume1,handle ;nume si adresa indicator logic
local cont ;eticheta locala in macro
clc ;anulare fanion CF
mov ah,3dh ;functie deschidere fisier
mov dx,offset nume1 ;adresa zona cu nume fisier
mov al,02h ;mod de deshidere R/W
int 21h
jnc cont ;cf=0 operatie corecta
tip_err al ;cf=1 afisare eroare din al
cont label near ;definitie eticheta locala
mov handle,ax ;salvare indicator logic din ax
endm
;INCHIDERE FISIER
;====================
cl_fis macro handlel ;adresa indicator logic
local cont
clc
mov ah,3eh ;functie inchidere fisier
mov bx,handle1 ;bx= indicator logic
int 21h
jnc cont ;CF=0 operatie corecta
tip_err al ;CF=1 afisare eroare din AL
cont label near
endm

;CITIRE SIR DE LUNGIME DATA DIN FISIER


;======================================
;de la dresa data de pointerul de citire/scriere
;dupa operatie daca cf=0 ax=lungime transferata
;sfarsit fisier daca ax=0
;------------------------------------------------
cit_fis macro handle1,lung,buff
local cont
clc
mov ah,3fh ;functie citire fisier
mov bx,handle1 ;BX=indicator logic
mov cx,lung ;nr octeti cititi
mov dx,offset buff ;adresa zona memorie
int 21h
jnc cont ;CF=0 => corect
tip_err al ;afisare eroare
cont label near
endm
;SCRIERE IN FISIER UN SIR DE CARACTERE

84
;la adresa disc data de pointerul de citire/scriere
;--------------------------------------------------
scr_fis macro handle1,lung,buff
local cont
clc
mov ah,40h ;functie scriere fisier
mov dx,offset buff ;adresa zona mamorie
mov cx,lung ;nr octeti transferati
mov bx,handle1 ;BX=indicator logic fisier
int 21h
jnc cont ;CF=0 => corecta citirea
tip_err al ;afisare eroare
cont label near
endm

;pozitionare pointer de citire/scriere in fisier


;adresa octet referitor la inceputul fisierului cx,dx
;----------------------------------------------------
lseek macro handle,tip,lung1,lung2
local cont
mov ah,42h ;functie setare pointer citire/scriere
mov cx,lung1 ;adresa octet din fisier in cx,dx
mov dx,lung2
mov bx,handle ;BX=indicator logic fisier
mov al,tip ;referinta inceput=0,sfarsit=1 pozcrt=2

int 21h
jnc cont ;CF=0 => operatie reusita
tip_err al ;tiparire cod eroare
cont label near
endm
------------------------------------------------------

; Se compara doua siruri sir1 si sir2.


; E = '0' daca sir1 <> sir2
; E = '1' daca sir1 == sir2
.model small
.stack 100
.data
sir1 db 'Sir egal cu 2'
sir1l EQU $ - offset sir1
sir2 db 'Sir egal cu 2'
db 'E : '
E db ?
.code
st1: mov ax, @data
mov ds, ax

85
mov es, ax

cld
mov si, offset sir1
mov di, offset sir2
mov cx, sir1l ; se compara pe lungimea unui sir
mov E, '1' ; se considera ca sunt egale
repz cmpsb ; se repeta pana se intalneste o diferenta
jz egal ; daca ZF = 1 sirurile sunt egale
mov E, '0' ; nu exista egalitate
egal: nop

int 3
end st1
------------------------------------
; Procedura calcul factorial ( N! )
; intrare -
; ax - N (numarul)
; iesire -
; ax - N!
; Modifica bx !
factor1 proc far
dec ax
jz fact1
call factor1
inc bx ;N=N+1
imul bx ; N! = N * (N - 1)!
retf
fact1: mov bx,1 ;N=1
mov ax, bx ; 1! = 1
retf
factor1 endp
; varianta (necesita stiva !)
factor2 proc far
cmp ax, 1
jle fact2
push ax
dec ax
call factor2
pop bx ; N
imul bx ; N! = N * (N - 1)!
fact2: ret
factor2 endp
; macro pentru apelul procedurii recursive
; salveaza registrele folosite si pregateste parametrii pentru procedura
; returneaza valoarea calculata
; ax se modifica !

86
factor macro N, Nfact
push bx
mov ax, N
call factor1
pop bx
mov Nfact, ax
endm
------------------------------
;program de calcul exp(x)
.model small
.stack 256
.8087
.data
eps dd 0.00001
x dd 2.541
ex dd 0.
.code
start:
mov ax, @data
mov ds, ax
fld x
fld1
fld st
fld st
fld st
ciclu:
fmul st, st(4)
fdiv st, st(1)
fadd st(2),st
fincstp
fadd st, st(2)
fdecstp
fcom eps
; fstsw ax
fwait
sahf
jl gata
jmp ciclu
fld st(2)
fst ex
gata:
mov ah, 4ch
int 21h
end start
---------------------------------------

; se cauta sir2 in sir1

87
pr1 segment
assume cs:pr1, ds:pr1, es:pr1
l1 equ 26
l2 equ 4
sir1 db 'facultatea de calculatoare $'
sir2 db 'dexy'
mem dw 0
st1:
mov ax, pr1
mov ds, ax
mov es, ax

mov di, offset sir1


mov mem, di
mov cx, l1
mov si, offset sir2
bucla:
mov al, byte ptr [si]
repne scasb
jne not_found
push cx
mov cx, l2
dec cx
inc si
mov ax, di
repe cmpsb ;facultatea de calculatoare
je found
sub si, cx
sub di, cx
pop cx
add cx, 1
jmp bucla
found:
sub ax, mem
jmp finish
not_found:
mov ax, 0FFFFh
finish:
int 3
pr1 ends
end st1
-----------------------------------
; calcul medie elemente poz., neg.
; intrare (pe stiva)
; - adresa tabloului
; - nr. de elemente
; iesire (pe stiva, in loc de parametrii)

88
; - media elementelor pozitive
; - media elementelor negative
;
medie_s struc
vsp dw ? ; variabila locala pt. suma el. pozitive
vnp dw ? ; variabila locala pt. nr. el. pozitive
vsn dw ? ; variabila locala pt. suma el. negative
vnn dw ? ; variabila locala pt. nr. el. negative
vbp dw ? ;
vip dw ? ;
vcs dw ? ;
vne dw ? ; parametrul nr. elemente
vat dw ? ; parametrul adresa tablou
medie_s ends
m_z EQU [bp - vbp] ; constanta pentru acces la parametrii si variabile locale
medie1proc far
push bp
mov bp, sp ; setare bp
sub sp, vbp ; alocare spatiu pentru variabile locale
;
push dx ; salvare registre folosite
push cx ;
push si ;
push ax ;

mov m_z.vsp, 0 ; initializare variabile locale


mov m_z.vnp, 0 ;
mov m_z.vsn, 0 ;
mov m_z.vnn, 0 ;

mov cx, m_z.vne ; cx - nr elemente


mov si, m_z.vat ; si - adresa tablou
med11: lodsw ; in ax primul element
or ax, ax ; verificare ax < 0
jz med1z ; salt daca ax = 0
js med1n ; salt daca ax < 0
inc m_z.vnp ; ax > 0, inc nr. el. pozitive
add m_z.vsp, ax ; vsp = vsp + ax
jmp med1z ; salt peste partea cu ax < 0
med1n: inc m_z.vnn ; ax < 0, inc nr. el. negative
add m_z.vsn, ax ; vsn = vsn + ax
med1z:loop med11 ; continuare
mov ax, m_z.vsp ; ax = suma elementelor pozitive
xor dx, dx ; pregatire pentru impartire (valoarea ax > 0 -> dx = 0)
div m_z.vnp ; calcul medie
mov m_z.vne, ax ; se suprascrie al II-lea parametru cu media poz.

89
mov ax, m_z.vsn ; ax = suma elementelor negative
cwd ; pregatire pentru impartire
idiv m_z.vnn ; calcul medie
mov m_z.vat, ax ; se suprascrie primul parametru cu media neg.

pop ax ; restaurare registre folosite


pop si ;
pop cx ;
pop dx ;
;
add sp, vbp ; refacere stare stiva
pop bp ; restaurare bp
retf ; end
medie1endp
*****Program care foloseste ce-I mai sus
.model small
.stack 256
.data
X dw 20, 30, 10, -10, -20
Xl EQU $ - offset X
.code
include medie.asm
st1: mov ax, @data
mov ds, ax

mov cx, Xl ; cx - lungimea totala a tabloului


shr cx, 1 ; cx (= cx / 2) - nr. de elemente
; (fiecare element ocupa 2 octeti ->
; lungimea tabloului = 2 * nr elemente)
mov bx, offset X
push bx ; adresa tabloului
push cx ; numarul de elemente
call medie1 ; apel procedura
pop ax ; media el. pozitive
pop bx ; media el. negative

mov ax, 4c00h ; terminare


int 21h
end st1
-------------------------------
; Sortare sir folosind bubblesort
; intrare
; bx - adresa sirului de sortat
; cx - nr. de caractere din sir
; iesire
; sirul [bx] sortat
bubble proc far
cmp cx, 1 ;
jg bb1 ; continuare daca sunt cel putin 2 caractere in sir

90
retf
bb1: push di
push dx
push cx
push bx ; salvarea registrelor folosite
dec cx ; se compara pe max cx-1 caractere
mov dx, cx ; salvare contor
bbl: mov si, bx ; index folosit
mov cx, dx ; restaurare contor
mov di, 0 ; (0 - sir sortat)
bbli: mov al, [si] ; bucla interna de parcurgere a sirului
cmp al, [si+1]
jle bbok ; salt daca [si] <= [si+1]
xchg al, [si+1] ; schimbarea valorilor [si] <-> [si+1]
mov [si], al ;
mov di,1 ; (1 - schimbare)
bbok: inc si
loop bbli ;
or di,di ; pozitionare indicatori logici
jnz bbl ; di = 1, sir neordonat
pop bx
pop cx
pop dx
pop di ; restaurare registre
retf
bubble endp
------------------------

12. UTILIZAREA COPROCESORULUI MATEMATIC

12.1 Arhitectura coprocesorului 8x87

Coprocesoarele 8x87/80287/80387, corespunzatoare celor trei game ale microprocesoarelor INTEL


80x86, sint module procesor specializate pentru calcule matematice, care lucreaza cu numere reprezentate in
virgula flotanta (VF). Microprocesoarele 80486 şi Pentium au integrat in ele si modulul deVF 80387 alaturi
de un modulul binar 80386.

Coprocesorul asigura cresterea considerabila a vitezei de executie a operatiilor aritmetice,


calculul functiilor trigonometrice sau logaritmice si o crestere a preciziei de calcul (numarul de cifre
semnificative). El este o extindere a resurselor procesorului de baza 80x86, ca registre si set de instructiuni,
folosind in comun memoria centrala. Cele doua procesoare pot lucra in paralel, programul putind contine
atit instructiuni de baza cit si in VF. Pentru sincronizarea lor in program se va folosi instructiunea
FWAIT,inaintea instructiunilor 8x86, care folosesc date rezultate in memorie din prelucrari in 8x87.
Mnemonicele coprocesorului incep cu litera F (FLD,FADD,..).

MEMORIE CENTRALA

91
Programe 8x86/87

Date 8x86/87

PROCESOR PROCESOR VF

8 x8 6 8x87

Cele doua procesoare folosesc aceleasi magistrale de date si adresa (BUS). Coprocesorul nu are
mecanism propriu de calcul al adreselor (segment,baza,index), acest calcul se face in 8x86, care-i
furnizeaza adresa instructiunii curente (IP-instr.pointer) si adresa operandului (OP-operand pointer) in forma
reala. Sunt admise toate modurile de adresare, dar adresa se calculează în procesorul de bază 8x86.
Coprocesorul 8x87 nu are instrucţiuni propri de salt.

Fazele executiei unei instructiuni 8x87 sint:


- Citire instructiune de catre 8x86
- Calcul adresa operand in 8x86
- Comunicare adresa operand si cod instructiune spre 8x87
- Executie instructiune VF in 8x87 si memorare rezultat
- Anuntare procesor 8x86 ca s-a terminat executia

Instructiunile de VF sint recunoscute dupa primii 5 biti din codul operatiei, care sint aceeasi 11011 si
se numesc ESCAPE. Cind lucreaza coprocesorul pune BUSY=1 (primul bit din status word), pentru a putea
fi testat de procesorul 8x86 in WAIT.

Coprocesorul 8x87 contine:


- Unitatea de comanda si control a transferurilor de informatii
- Unitatea de executie a instructinilor in virgula flotanta - Registre generale de VF organizate ca stiva
ST(0),ST(1),..ST(7)
Registrele si caile interne ale coprocesorului VF sint de mare viteza si 80 biti (1-semn,15-
exponent,64-mantisa).

Unitatea de comanda si control contine 5 registre (14 octeti), care pastreaza starea momentana a lui
8x87 (ENVIRONMENT). Ele pot fi memorate la adrese consecutive prin FSTENV (store environment) si
ulterior incarcate prin FLDENV (load environment).

15 0
+0 CONTROL WORD -precizie,masti de intrerupere
+2 STATUS WORD - indicatori,stare si intrerupere
+4 TAG WORD - indicatori reg
+6 INSTRUCTION - adresa reala,
+8 POINTER cod instructiune curenta
+10 OPERAND - adresa reala
+12 POINTER operand

92
Starea completa a coprocesorului cuprinde si cele 8 registre generale (stiva) de 10 octeti fiecare
(14+8*10=94 octeti),se poate memora prin FSAVE si restaura prin FRSTORE.Salvarea registrelor se face
cu octetii mai putin semnificativi in fata si in ordinea ST(0),ST(1),....ST(7), dupa registrele
ENVIRONMENT.

Registrul INSTRUCTION POINTER pastreaza pe 20 biti adresa reala si codul instructiunii


curente ( fara primii 5 biti 11011).

15 0
INSTRUCTION POINTER -low (bitii 15-0)
IP -high | 0 | OPERATION CODE
15 12 10 0

Registrul OPERAND POINTER contine pe 20 biti adresa reala (calculata de 8x86) a operandului
din memorie utilizat in instructiunea curenta.

15 0
OPERAND POINTER -low adress (bitii 15-0)
OP high | 0 0 0
15 12 0

Registrele generale organizate ca stiva circulara are fiecare 80 biti,pentru precizie maxima (1-
semn,15-exponent, 64- mantisa sau "significand"). Toate datele primite din memorie se convertesc si se
pastreaza in VF format lung (temporary).Din memorie se pot incarca numere intregi binare,numere in
zecimal codificat binar (BCD) de 18 cifre si numere codificate in VF. Conversiile necesare se fac la citirea
sau scrierea in memorie utilizind instructiuni specifice.
15 biţi 64 biţi
S EXPONENT MANTISA
R0 ST(6)
R1 ST(7)
R2 ST(0) <--TOP=2
R3 ST(1)
ST(2)

R7 ST(5)
79 63 0

La un moment dat oricare registru poate fi virful stivei ST(0), iar urmatorul ST(1).Celelalte registre
vor avea o adresa relativa fata de ST(0). Numarul registrului virf de stiva se gaseste memorat in zona TOP
din STATUS WORD. Operatiile de incarcare decrementeaza TOP cu 1 si incarca in noul registru
ST(0). Operatiile de memorare cu "pop" memoreaza din ST(0) si incrementeaza TOP cu 1.

Registrul STATUS WORD contine:

93
- indicatorii de conditii, pozitionati dupa efectuarea instructiilor de comparatie/test, care se pot memora
cu FSTSW (store status word) pentru a fi analizate de 8x86, cind trebuie sa se faca salturi conditionate
(8x87 nu are instructiuni de salt).
- bitii care indica aparitia unor cereri intreruperi spre 8x86, sau datorate rezultatelor obtinute
- indicatorul registrului virf de stiva TOP

15 14 13 10 9 8 7 6 5 4 3 2 1 0
B C3 TOP C2 C1 C0 IR P U O Z D I

B =1 - coprocesor 8x87 ocupat


C3--C0 - indica rezultatul unei comparatii sau test
C0 =1 - ST(0) < sursa (echivalent cu S la 8x86)
C3 =1 - ST(0) > sursa (echivalent cu Z la 8x86)
TOP =0...7 - indica nr. registru virf de stiva
IR =1 - cerere intrerupere la 8x86 (intrerupt request)
P U O Z D I - indicatori intreruperi datorate rezultatului
P =1 - precision -s-a pierdut un bit si rezultatul rotunjit
U =1 - underflow -exponent prea mic (depasire inferioara)
0 =1 - overflow - prea mare (depasire superioara)
Z =1 - zero divide - impartire numar # 0 cu zero
D =1 - denormalized - numar nenormalizat
I =1 - invalid operation - 0/0, infinit/infinit,nenumeric
Intreruperea se poate anula cu FCLEX (clear 8x87).

Registrul CONTROL WORD contine indicatori de stabilire precizie si masti de intrerupere:

15 12 11 9 7 5 4 3 2 1 0
rezervat IC RC PC IEM x PM UM OM ZM DM IM

IC - Infinit Control 0 - nu face distinctie intre + si - infinit


1 - face distinctie intre + si - infinit
RC - Rounding Control - stabileste modul de rotunjire
00 - rotunjire la cel mai apropiat ( implicit )
01 - rotunjire in sus
10 - rotunjire in jos
11 - trunchiere
PC - Precizion Control - precizie de lucru prescrisa(rotunjire)
00 - 24 biti pentru mantisa - short real
01 - rezervat
10 - 53 biti - long real
11 - 64 biti - temporary real ( implicit )
IEM - Intrerupt Enable Mask - implicit = 1 (mascate)
0 - intreruperile nemascate,tratate prin procedura utilizator
1 - toate intreruperile sint tratate standard de 8x87
x - rezervat (bit 6)

Mastile specifice intreruperilor pot avea valorile:


0 - intrerupere exceptie tratata prin procedura utilizator
1 - intreruperea exceptie este mascata (implicit)

94
Raspunsurile la fiecare exceptie mascata (masca = 1)sint:
PM - Precision Mask - furnizeaza rezultatul rotunjit
UM - Underflow Mask - rezultat = 0
OM - Overflow Mask - rezultat = numar maxim cu semn
ZM - Zero divide Mask -rezultat = numar maxim cu semn
DM - Denormalized - continua calculul cu nr.nenormalizat
IM - Invalid operation Mask - rezultatul este valoarea nenumerica a operandului
(ex: radical din numar negativ)

Registrul TAG WORD contine 8 grupe de 2 biti numite TAG(0), TAG(1),...TAG(7)


corespunzatoare celor 8 registre generale ST(0), ST(1),....ST(7). Fiecare TAG(I) indica continutul lui ST(I) :
TAG(I) = 00 - valoare valida in ST(I) normalizata sau nu
01 - zero in ST(I)
10 - continut special nenumeric,+ sau - infinit,anormal
11 - valoare zero de initializare

12.2 Tipuri de date

Sint admise 7 tipuri de date, care pot fi operanzi din memorie si care prin incarcare se convertesc in
format intern Virgula Flotanta (VF) pe 80 biti numit Temporary Real.In registrele interne se pastreaza datele
numai in format VF de unde se pot memora in alte formate prin instructiuni specifice, care asigura si
conversia. Specificarea adresei operandului se poate face in toate modurile admise de 8x86, care asigura
calcularea adresei. In toate tipurile primul bit este considerat semn, iar bitii din stinga sint cei mai
semnificativi. Caracteristicile tipurilor admise sint date in tabelul urmator:

Tip date Biti Cifre zec. Precizie Exponent*


WORD INTEGER 16 4-5 16 biti nu
SHORT INTEGER 32 9 32 biti nu
LONG INTEGER 64 18 64 biti nu
PACKED DECIMAL 80 18 18 cif.zec nu
SHORT REAL 32 6-7 24 biti 127 (8)
LONG REAL 64 15-16 53 biti 1023 (11)
TEMPORARY 80 19-20 64 biti 16383 (15)
REAL
*Exponentul este utilizat ca putere a lui 2, iar in paranteza se da puterea corespunzatoare a lui 10
pentru domeniul maxim.

In real mantisa este pozitiva si da precizia, iar semnul este al mantisei (S = 1 negativ). Bitii de
exponent dau caracteristica (CAR), care este pozitiva. Valoarea exponentului (EXP) se calculeaza:
EXP = CAR - 7FH - pentru SHORT REAL
- 3FFH - pentru LONG REAL
- 3FFFH - pentru TEMPORARY REAL

Valoarea unui numar real - N (reprezentat in virgula flotanta) se calculeaza dupa formula:
N = M*2**EXP unde: M - este valoarea mantisei 1 < M < 2
EXP - valoare calculata exponent

Tipurile intregi cu semn sint cele acceptate de procesorul 8x86 si de Macroasamblor prin
directivele de definire date:
95
DW - define word - pentru WORD INTEGER ( 16 biti )
DD - define double-word - pt. SHORT INTEGER ( 32 biti )
DQ - define quad-word - pt. LONG INTEGER ( 64 biti )

Tipul PACKED DECIMAL utilizeaza 10 octeti si este un numar zecimal codificat binar cu semn
(BCD), avind 18 cifre zecimale, codificate fiecare pe 4 biti (doua pe octet). Primul octet contine doar
semnul pe primul bit.

79 71 63 56 .......... 15 7 0
S * D17D16 D15D14 D13 .......... D4 D3D2 D1D0
Tipul este recunoscut de macroasamblor prin definitia:
DT -define ten-byte in care valoarea se specifica in hexa

Tipurile reale sint numere codificate in virgula flotanta


unde reprezentarea se face prin mantisa pozitiva (significant), caracteristica si semn. Mantisa se trece
intotdeauna intr-o forma normalizata 1 < M < 2 de forma:
1^ffffffff unde: ^ - este punctul zecimal virtual
f - sint biti fractionari (23, 52 sau 63)
Bitul intreg este implicit dar nu exista in memorie pentru formatul SHORT si LONG, el existind fizic numai
la TEMPORARY REAL.

SHORT REAL
31 30 22 0
S E7 ... EO f1 f2 .... f22 f23 - in mantisa 1 este implicit
- EXP < 127 (7FH)
exponent mantisa - mantisa 6-7 cifre zecimale

LONG REAL
63 62 51 0
S E10 E0 f1 f2 f3 ....... f51 f52 EXP < 1023 (3FFH)
- mantisa 15-16 cifre zec.

TEMPORARY REAL
79 78 63 0
S E14.... E1 E0 1^f1 f2 f3 f14 ...... f62 f63

EXP < 16383 (3FFFH) - mantisa 19-20 cifre zecimale

12.3 Asamblarea programelor

Pentru generare de cod pentru coprocesor Macroasamblorul se poate lansa in doua moduri
MASM ...... /R - genereaza cod real executabil pe 8x87 existent
/E - emulare - genereaza chemari de subprograme din biblioteca pentru
mnemonice 8x87 intilnite

Codurile instructiunilor 8x87 generate in modul /R pot fi executate fara a exista fizic coprocesorul daca se
lanseaza inainte :
EM87 /L

96
Acesta incarca un emulator 8x87 rezident in memorie, care se apeleaza prin intreruperile de exceptie
instructiune inexistenta, declansate de codurile 8x87 din program. La terminarea programelor care utilizeaza
mnemonici 8x87 emulatorul se elimina prin:
EM87 /U - descarcare emulator 8x87 din memorie

Pentru ca macroasamblorul sa recunoasca mnemonicele 8087 in program, trebuie inainte sa se dea


comanda:
.8087
Daca se utilizeaza alte coprocesoare se vor da comenzile:
.287 - pentru 80287
.387 - daca se utilizeaza 80387 sau procesorul 80486

Pentru specificarea setului de instructiuni se utilizeaza:


.286C - set comun neprivilegiat 80286
.286P - set privilegiat 80286
.386 - set instructiuni 80386
Pentru testarea programelor care utilizeaza coprocesorul, depanatorul AFD nu poate fi folosit,
deoarece nu recunoaste setul de instructiuni al coprocesorului si se recomanda CODVUE.
OBSERVATIE In macroasamblor nu exista definitii de tipuri speciale de date pentru coprocesorul
8x87, ele fiind recunoscute prin lungimea definita de instructiunile de VF ce le utilizeaza:
X1 dw 4530 - intreg pe 2 oct. utilizabil de 8x86 sau 8x87
X2 dd 4530 - intreg pe 4 oct. utilizabil de 80386 sau 8x87
X3 dq 4530 - intreg pe 8 oct. utilizabil de 8x87 (LONG)
X4 dt 4530H - packed decimal (10 oct.) utilizabil de 8x87
X5 dd 45.30 - short real (4 oct.) utilizabil de 8x87
X6 dq 4.53E+4 - long real (8 oct.) utilizabil de 8x87
X7 dt 4530.0 - temporary real (10 oct.) direct utiliz. 8x87

12.4 Instructiuni pentru transfer de date la 8x87

Coprocesorul 8x87 executa 69 instructiuni (72 la 80287). Instructiunile de transfer 8x87 executa
incarcarea(sau memorarea) datelor, de tipurile precizate, din memorie in registrul ST(0), sau intre registrele
8x87. Schimbul de date cu memoria este insotit de conversia lor in temporary real daca e cazul, sau
ajustarea mantisei si exponentului,pentru SHORT si LONG REAL.
Toate instructiunile de incarcare decrementeaza inainte stiva.Nu exista instructiuni imediate. Pentru
transferul datelor intre locatii de memorie se folosesc instructiunile 8x86 cunoscute. Pentru precizarea unei
adrese de operand din memorie se pot folosi toate modurile de adresare. Reg. ST(0) se poate nota ST.
Prezentam sintetic instructiunile din aceasta grupa:

Transferuri de numere intregi:


FILD intreg - integer load - incarca din memorie in ST
FIST intreg - integer store - memorare ST ca intreg
FILDP intreg - idem FILD urmat de decrem. stiva reg. (pop)
FRNDINT - rotunjire la intreg a lui ST

Transferuri de numere zecimale codificate binar:


FBLD decimal - BCD load - incarcare nr. zecimal din memorie
FBST decimal - BCD store - memorare ST ca nr.zecimal

97
Transferuri de numere reale intre ST si memorie:
FLD real - incarcare numar real din memorie in ST
FST real - memorare ST la o adresa de memorie
FSTP real - idem ca FLD urmat de decrem. stiva registre

Transferuri intre ST si registrele stiva:


FLD ST(I) - ST(I) -> ST
FLD ST - copiaza ST in sus in stiva de registre
FST ST(I) - ST -> ST(I)
FSTP ST(I) - ST -> ST(I) si incrementare stiva reg.(pop)
FXCH - ST <=> ST(1) interschimb
FXCH ST(I) - ST <=> ST(I)
FXTRACT - exp(ST) => ST , mantisa(ST) => ST(1) si push
FDECSTP - decrementare stack pointer registre
FINCSTP - incrementare stack pointer

Incarcari de constante in ST:


Pentru a suplini lipsa incarcarilor imediate exista instructiuni care incarca in ST anumite constante,
des folosite in calculele matematice. Incarcarea incepe cu decrement
FLDZ 0.0 => ST - constanta zero in VF
FLD1 1.0 => ST - constanta 1.
FLDPI 3.14.. => ST - constanta PI
FLDL2E log in baza 2 din E => ST
FLDL2T log in baza 2 din 10 => ST
FLDLG2 log in baza 10 din 2 => ST
FLDLN2 log natural din 2 => ST
Pentru incarcarea altor valori de constante, ele se vor defini in memorie cu un tip recunoscut in VF si
vor fi incarcate prin instructiunile corespunzatoare tipului.

Instructiuni pentru registrele de stare


FSTSW dest - memorare STATUS WORD la o adresa de memorie
FSTSW AX - memorare STATUS WORD in AX (la 80287)
FCLEX - sterge flag-uile exceptie,intrerupere,busy

Prin instructiunea FSTSW indicatorii de conditii 8x87, pozitionati dupa executia instructiunilor de
VF, se depun in memorie sau AX de unde se pot depune in reg. FLAGS al lui 8x86 prin SAHF (instructiune
8x86). Valoarea acestor indicatori se poate testa prin instructiunile de salt conditionat (Jcond), uzuale pentru
a realiza ramificari ale programului. Mentionam ca 8x87 nu are instructiuni proprii de salt. Indicatorii
C3 - C0 se vor memora automat peste Z si S. Reg. FLAGS se poate incarca in AH prin LAHF.

FSTCW dest - memoreaza reg. CONTROL WORD


FLDCW sursa - incarca din memorie reg. CONTROL WORD
FSTENV dest - memorare reg. ENVIRONMENT (14 octeti)
FLDENV sursa - incarca din memorie reg. ENVIRONMENT
FSAVE dest - salvare ENVIRONMENT + reg.generale (94oct)
FRSTORE sursa - restaurare ENVIRONEMENT si reg.generale

98
Toate unstructiunile din aceasta clasa includ un FWAIT pentru sincronizare cu 8x86. Ele au si forma
fara FWAIT cind au prefixul FN (ex: FNSTSW,FNSTCW, ...FNSAVE, FNRSTORE).

12.5.Instructiuni aritmetice in VF

Aceasta grupa cuprinde instructiuni puternice de calcul matematic, pentru care a fost conceput
coprocesorul matematic. La 80287 fata de 8x87, se adauga doar 3 instructiuni pentru control in mod
protejat. Setul lui 80387 cuprinde citeva instructiuni in plus care vor fi indicate.
FWAIT - asteapta terminarea unei instructiuni 8x87
FNOP - nici o operatie
FABS - valoare absoluta din ST |ST| => ST

Adunari real - real


FADD ST(1) + ST => ST(1) -adunare registre
FADD ST,ST(I) ST + ST(I) => ST
FADD ST(I),ST ST + ST(I) => ST(I)
FADD real ST + real => ST -real din memorie
FADDP ST(I),ST ST + ST(I) => ST(I) -adunare urmata
de incrementare stiva registre (pop)
Scaderi real - real
FCHS - schimba semnul lui ST (change sign)
FSUB ST(1) - ST => ST(1) - scadere reg.
FSUB ST,ST(I) ST - ST(I) => ST
FSUB ST(I),ST ST(I) - ST => ST(I)
FSUB real ST - real => ST -real din memorie
FSUBP ST(I),ST ST(I) -ST => ST(I) -scadere si pop

Scaderi reale inverse (reversed)


FSUBR ST - ST(I) => ST(I) -substract real reversed
FSUBR ST(I),ST ST - ST(I) => ST(I)
FSUBR ST,ST(I) ST(I) - ST => ST
FSUBR real real - ST => ST -real din memorie
FSUBRP ST(I),ST ST - ST(I) => ST(I) -scadere si pop reg

Comparatii numere reale


FCOM ST - ST(1) => pozitionare indicatori de conditie
FCOM ST(I) ST - ST(I) => pozit.indic.conditie
FCOM real ST - real => pozit.indic.conditie
FCOMP ST(I) ST - ST(I) -comparatie si apoi pop reg
FCOMPP -compara ST cu ST(1) si apoi dubla incrementare(pop)
FTST -compara ST cu 0 ST - 0 => pozit.indic.(test ST)
FXAM -examineaza ST si poz.indicatorii C3,C2,C1,C0 pentru cazul unor rezultate
anormale(depasiri inferioare sau superioare)
Comparatia consta dintr-o scadere a operandului specificat din valoarea lui ST si pozitionarea
indicatorilor de conditie, functie de rezultat (valoarea operanzilor nu se shimba) astfel:
C3(Z) C0(S)
0 0 pt. ST > referinta (rezultat > 0)

99
0 1 ST > referinta (rezultat < 0)
1 0 ST = referinta (rezultat = 0)
1 1 -rezultat +infinit sau -infinit
Indicatorii C3--C0 fac parte din primul octet din STATUS WORD, se memoreaza cu FSTSW
AX, in AX de unde se depun cu SAHF in reg FLAGS si se pot testa cu instructiuni de salt
conditionat.

Operatii real - intreg


FIADD intreg ST + intreg => ST -intreg din memorie
FISUB intreg ST - intreg => ST
FISUBR intreg intreg - ST => ST -substract reversed
FICOM intreg ST - intreg => pozitioneaza indicatorii
FICOMP intreg comparatie ST cu intreg si pop reg
FIMUL intreg ST*intreg => ST -inmultire cu intreg
Operandul intreg, de orice lungime, este citit din memorie, convertit in VF (real) si utilizat in instructiune.

Operatii de inmultire si impartire in VF


FMUL ST(1)*ST => ST(1) -inmultire real - real
FMUL ST(I),ST ST(I)*ST => ST(I)
FMUL ST,ST(I) ST*ST(I) => ST
FMUL real ST*real => ST -real din memorie
FMULP ST(I),ST ST(I)*ST => ST -inmultire si pop

FDIV ST(1)/ST => ST(1) -impartire real - real


FDIV ST(I),ST ST(I)/ST => ST(I)
FDIV ST,ST(I) ST/ST(I) => ST
FDIV real ST/real => ST -real din memorie
FDIVP ST(I),ST ST(I)/ST => ST -impartire si pop
FDIVR ST/ST(1) => ST(1) -divide reversed
FDIVR ST(I),ST ST/ST(I) => ST(I)
FDIVR ST,ST(I) ST(I)/ST => ST
FDIVR real ST/real => ST -real din memorie
FDIVRP ST(I)/ST ST(I)/ST => ST(I) -divide rev. si pop

Instructiuni speciale

In aceasta grupa am cuprins instructiuni de calcul functii exponentiale, logaritmice si trigonometrice


usuale:
FPREM pentru ST/ST(1) da restul partial (modul) in ST
FSQRT radicalul din ST => ST pt. ST > 0
FCOS cos(ST) => ST - calcul cos(x) numai 80387
FSIN sin(ST) => ST - calcul sin(x) numai 80387
FPTAN tang(a) - pentru 0 < a < PI/4
- rezultatul sub forma x/y in ST si ST(1)

FPATAN arctg(x/y) => ST - unde x in ST si y in ST(1)


- rezultatul in noul ST care este dupa pop in locul lui y

FSCALE calculeaza f= ST*2**ST(1) => ST


- interpreteaza ST(1) ca intreg si il adauga la exponentul
100
lui ST pentru a obtine inmultirea cu 2 la puterea N

FYL2X calculeaza f= Y*log2(X) =>ST (peste Y dupa pop)


- se cere X>0 in ST si Y -real in ST(1)

FYLN2XP1 calculeaza f= Y*log2(X+1) =>ST (peste Y dupa pop)


- se cere X>0 in ST si Y -real in ST(1) pt.X<rad(2)/2 (0.75)

F2XM1 calculeaza f= 2**X-1 =>ST -unde X in ST


Aceasta functie permite calculul functiilor exponentiale pentru orice baza prin formulele cunoscute:
10**X = 2**X*log2(10)
e**X = 2**X*log2(e) - unde e este baza log. naturali
Y**X = 2**X*log2(Y)
Constantele logaritmice se incarca prin FLDL2T si FLDL2E.

12.6 Exemple de programe cu instructiuni 8x87

Folosind instructiunile prezentate si exemplele de program se vor scrie programe, care sa utilizeze
numere reale, intregi si zecimale codificate binar (BCD) pentru calcule matematice utizind coprocesorul
8x87, real s-au emulat cu EM87 /L. - Se va asambla programul si pentru datele constante generate cu
diferite lungimi se va studia modul de codificare si se vor calcula valorile in zecimal pentru numerele reale.
- Se va studia modul de codificare a instructiunilor de VF
- Se va scrie un program pentru una din problemele:
- rezolvarea unei ecuatii de gradul 2,
- calcul sin(x) si cos(x) prin dezvoltare in serie,
- extragerea radacinii patrate dupa formula iterativa:
X(i)= [N/X(i-1)+X(i-1)]/2 - unde X(1)=N/2
- calculul unei integrale definite cu metoda trapezelor

Prezentam mai jos listingul unui exemplu de program simplu in care se declara diferite tipuri de
variabile si se executa citeva instructiuni. Programul va trebui lansat din DOS sau CodeView. El va afisa pe
ecran rezultatul adunarii a doua numere zecimale codificate binar Y3 = Y1 + Y2. Cele doua numere au fost
alese incit rezultatul sa fie de "tip ASCII" pentru a putea fi afisat direct pentru verificare. Se va afisa 8754.

EM87 / l -incarcare emulator rezident in memorie


MASM ex1f.asm,ex1f,ex1f /r - macroasamblare cu instr.VF reale
----------------------------------------------------------------
Microsoft (R) Macro Assembler Version 5.00 6/9/93 23:29:14
Page 1-1
adresa cod generat etic. instructiuni

.model small
0100 .stack 256
* segment de date *
0000 .data
0000 1B2F5D40 x1 dd 3.456
0004 33338340 x2 dd 4.1
0008 08070504000000000000 y1 dt 4050708h
0012 30303030000000000000 y2 dt 30303030h

101
001C 00000000000000000000 y3 dt 0
0026 24 db '$'
0027 00000000 x3 dd 0
002B 0000803F x4 dd 1.0
002F 0000A040 x5 dd 5.0

* segment de cod cu specificare coprocesor *


.8x87
0000 .code
0000 B8 ---- R st1: mov ax,@data
0003 8E D8 mov ds,ax
0005 9B D9 06 0000 R fld x1
000A 9B D8 06 0004 R fadd x2
000F 9B D9 16 0027 R fst x3
0014 9B DF 26 0008 R fbld y1
0019 9B DF 26 0012 R fbld y2
001E 9B D8 C1 fadd st,st(1)
0021 9B DF 36 001C R fbstp y3
* afisare text pe ecran *
0026 BA 001C R mov dx,offset y3 0029 B4 09 mov
ah,9
002B CD 21 int 21h
002D B4 4C mov ah,4ch
002F CD 21 int 21h
0031 end st1

Microsoft (R) Macro Assembler Version 5.0 6/9/93 23:29:14


Segments and Groups:

Name Length Align Combine Class

DGROUP .. . . . . . . . . . . GROUP
_DATA . . . . . . . . . . 0033 WORD PUBLIC 'DATA'
STACK . . . . . . . . . . 0100 PARA STACK 'STACK'
_TEXT . . . . . . . . . . . 0031 WORD PUBLIC 'CODE'

Symbols:
Name Type Value Attr

ST1 . . . . . . . . . . . . L NEAR 0000 _TEXT


X1 . . . . . . . . . . . . . L DWORD 0000 _DATA
X2 . . . . . . . . . . . . . L DWORD 0004 _DATA
X3 . . . . . . . . . . . . . L DWORD 0027 _DATA
X4 . . . . . . . . . . . . . L DWORD 002B _DATA
X5 . . . . . . . . . . . . . L DWORD 002F _DATA
Y1 . . . . . . . . . . . . . L TBYTE 0008 _DATA
Y2 . . . . . . . . . . . . . L TBYTE 0012 _DATA
Y3 . . . . . . . . . . . . . L TBYTE 001C _DATA

102
@CODE . . . . . . . . . . . . . TEXT _TEXT
@CODESIZE . . . . . . . . . . . TEXT 0
@DATASIZE . . . . . . . . . . . TEXT 0
@FILENAME . . . . . . . . . . . TEXT ex1f

30 Source Lines
30 Total Lines
23 Symbols

50940 + 309892 Bytes symbol space free

0 Warning Errors
0 Severe Errors
-------------------------------------------------------------------

Se observa ca numerele zecimale Y1 si Y2 se aliniaza la stinga unde cifrele au si ponderea cea mai
mare.
Numerele X1 si X2 care sint reprezentate in VF (reale) au octetii inversati, incit exponentul si
ponderile mai mari apar in dreapta. Variabila X3=0 are atit mantisa cit si exponentul 0.

X4 = 1. are reprezentarea 00 00 80 3F care in registru va fi:


3F 80 00 00
Deoarece primul bit din octetul 2 este din exponent printr-o deplasare spre stinga obtinem: 7F
00 00 00 deci EXP = 7F - 7F = 0
Mantisa este aparent 0 dar contine un 1. care in SHORT REAL nu se reprezinta. Ea este pentru
numerele normalizate:
1 =< Mantisa < 2 deci Mantisa = 1 pentru X4
Valoarea lui X4 va fi:
X4 = M*2**EXP = 1.*2**0 = 1.

Procedam la fel pentru X5 = 5. care e reprezentat 00 00 A0 40


In registru va fi 40 A0 00 00 si dupa o deplasare stinga devine:
81 40 00 00 avind deci EXP = 81 - 7F = 2
Mantisa este M = 1. + 4/16 + 0/256 = 1.25
X5 = M*2**EXP = 1.25*2**2=1.25*4 = 5. care e valoarea corecta
Se observa ca pentru a simplificarea calculului mantisei lucram cu puterile negative a lui 16 si cu
cifrele hexa din mantisă.

Calculam si valoarea lui X2 = 4.1 care se reprezinta prin:


33 33 83 40 si devine dupa inversarea cifrelor 40 83 33 33 iar dupa o deplasare dreapta 81 06 66
66 .Rezulta exponentul:
EXP = 81 - 7F = 2 iar mantisa:
M = 1. + 0/16 + 6/(16*16) + 6/(256*16) + 6/(256*256) + ...
X2 = 2**2 *M = 4*M = 4 + 24/256 + 24/(256*16) +..=4.09375+0.00586
X2 = 4.09961 cu o aproximatie sub destul de buna sub 1% desi am neglijat ultimele 3 cifre hexa din
mantisa

Program de calcul pentru functia exponentiala

Calculam valoarea functiei exponentiale prin descompunerea in serie dupa formula:


103
E**x = 1 + x/1! + x**2/2! x**3/3! + x**4/4! + ....
Calculam suma iterativ S = S + T pina cind termenul T devine mai mic decit EPS = 0.0001
Un termen Ti il calculam dupa formula T = T*X/I
Variabilele folosite si valorile initiale sint:
S - suma partiala, initial S = 1
T - valoarea termenului curent, initial T = 1
I - rangul termenului curent, initial I = 1
In dreapta programului se vede structura considerata pentru stiva de registre a coprocesorului in momentul
initial.
; -----------------------------------------------
; PROGRAM DE CALCUL EXP(X)
; ------------------------------------------------
.MODEL SMALL
.STACK 256
.80287
.DATA
EPS DD 0.00001 ;precizie
X DD 2.541
EX DD 0. ;valoare calculata ST-----> +0 T=1
.CODE +1 I=1
START: MOV AX,@DATA +2 S=1
MOV DS,AX +3 1
; Fiecare incarcare de registru e precedata de +4 X decrem. stiva reg.
FLD X ; incarcare X real +5
FLD1 ; incarcare constanta 1.
FLD ST ; S=1
FLD ST ; I=1
FLD ST ; T=1
CICLU: FMUL ST,ST(4) ; T=T*X =>ST
FDIV ST,ST(1) ; T=T*X/I
FADD ST(2),ST ; S=S+T
FINCSTP ; incrementare pointer reg.
FADD ST,ST(2) ; I=I+1
FDECSTP ; refacere pointer reg.
FCOM EPS ; T < EPS ?
FSTSW AX ; salvare indicatori si test
FWAIT ; asteptare terminare instr. VF
SAHF ; memorare indicatori in reg. FLAGS
JL GATA ; test S=1 (indicator C0)
JMP CICLU
FLD ST,ST(2) ; memorare rezultat
FST EX
GATA: MOV AH,4CH
INT 21H ; iesire in DOS
END START

12.7. Conversie numere din intreg in flotant

104
Consideram un numar binar intreg pe 4 octeti (32 biti), care il vom converti in virgula flotanta (VF)
pe 4 octeti (SHORT REAL)

23c.b.
Numar intreg N
, - virgula pentru mantisa VF , - virgula intreg

CAR 127+23 - caracteristica initiala numar intreg

Consideram numarul pozitiv intreg N, care are virgula virtuala in dreapta, ca o mantisa supraunitara
cu o caracteristica CAR asociata:
N = N*2**0 => EXP = 0 => CAR = EXP+127 = 127

Daca N este considerat o mantisa pentru reprezentarea VF short real, atunci virgula va fi vazuta
deplasata cu 23 c.b. spre stinga. Pentru a nu schimba valoarea numarului, care devine N*2**(-23), trebuie sa
marim caracteristica cu 23. Pastrind separat mantisa si caracteristica vom avea un numar in VF cu:
M = N*2**(-23) si CAR = 127+23 = 150 -caracteristica initiala

Cum numarul nostru in VF este in general nenormalizat, il vom supune unei normalizari, utilizind o
macroinstructiune NF4, pe care o vom defini si care apeleaza un subprogram SNF4. Numarul ce se
normalizeaza va fi dat prin mantisa M1 si caracteristica C1 separate. Ele vor fi incarcate in DX:AX si
respectiv in BX de macroinstructiunea NF4, care dupa chemarea subprogramului SNF4 obtine numarul in
flotant in DX:AX si il memoreaza peste mantisa initiala (vezi programul alaturat).
Subprogramul SNF4 considera ca mantisa este nenormalizata, existind 2 cazuri:

a) - Este ocupata zona caracteristicii (primul octet), caz in care se fac deplasari spre dreapta a
mantisei si incrementari corespunzatoare ale caracteristicii, pentru a nu modifica valoarea numarului.
b) - Mantisa are zerouri pe primele pozitii dupa virgula si in acest caz se fac deplasari spre stinga si
decrementari ale caracteristicii, pina cind primul bit din octetul 2 al mantisei devine 1.

Deplasarile spre stinga sau dreapta ale mantisei, ce se gaseste in registrele DX:AX se face combinind
o deplasare a unui registru cu rotirea prin carry a celuilalt. Dupa ce mantisa a fost normalizata, primul bit
care este 1 implicit se sterge si mantisa se concateneaza cu caracteristica.
Daca avem macroinstructiunea de normalizare NF4, atunci conversia unui numar intreg in VF se
reduce la o normalizare cu o caracteristica initiala CAR=150

Pentru exemplificare consideram numarul intreg N = 5


N = 00 00 00 05 si CAR = 127 + 23 = 150 = 96H
Pentru normalizare sint necesare 21 deplasari spre stinga:
M = 00 A0 00 00 si CAR = 150 - 21 = 129 = 81H
Prin suprimarea bitului 1 implicit rezulta:
M = 00 20 00 00
Adaugind caracteristica obtinem numarul in flotant:
NF = 40 A0 00 00 care reprezinta in flotant numarul intreg 5.

; --------------------------------

105
; PROGRAM DE CONVERSIE INTREG REAL
; ---------------------------------
.286c
.287
dosseg
.model small
.stack 100
.data
x dd 51420 ; nr intreg
xf dd 51420. ; nr in vf
cx1 dw 127+23 ; caracteristica implicita

.code
; Definitie macro pt normalizare vf
nf4 MACRO c1,m1 ; caract. si mantisa
PUSHA ; salvare registre
mov ax,word ptr m1 ; mantisa pe 4 octeti
mov dx,word ptr m1+2
mov bx,c1 ; caract. pe 2 octeti
CALL SNF4 ; subprogram normalizare
mov word ptr m1,ax ; memorare nr. normalizat
mov word ptr m1+2,dx ; peste mantisa initiala
POPA
ENDM

; ---------------------------
; Subprogram normalizare VF
; - intrare mantisa 4 oct in DX:AX si caract in BX
; - iesire nr in vf pe 4 oct in DX:AX
; ---------------------------
snf4 PROC near
; normalizare prin depl dreaapta mantisa si increm. CAR
c11: cmp dh,0 ; test octet1 din mant =0
jz c2 ; octet1=0 depl. stinga
inc bx ; car =car+1 si depl. dreapta DX:AX
shr dx,1 ; DX -> CF -> AX
rcr ax,1
jmp c11

; normalizare prin depl. stinga mantisa si decrem. CAR


c2: mov cl,80h ; verif. bit1 din octet2 mantisa
and cl,dl ; selectie bit1
cmp cl,80h
jz c3 ; terminare normalizare
dec bx ; car=car-1 si depl. stinga mantisa
shl ax,1 ; DX <- CF <- AX
rcl dx,1
jmp c2
; Concatenare CAR cu mantisa normalizata
106
c3: and dl,7fh ; sterge bit 1 din mantisa (implicit=1)
shl dx,1
or dh,bl ; concatenare CAR si mantisa
shr dx,1
ret
snf4 ENDP

; ------------------------------
; program principal conversie intreg flotant
; ------------------------------
st1: mov ax,@data
mov ds,ax
;
cif: nf4 cx1,x ; conversie intreg real
;
end st1
---------------------------------------------------

12.8. Conversia numerelor din VF in intreg

Si in acest caz separam caracteristica (CAR) de mantisa (M). Mantisa va furniza cifrele
semnificative ale numarului ( 6-7 la short real), iar caracteristica va da ordinul de marime. Algoritmul va fi
invers decit la conversia intreg - flotant.
8c.b. 23c.b.
MANTISA
'- virgula mantisa vf ' -virgula pt.numar intreg

CAR - caracteristica

Valoarea numarului in VF este:


NF = M*2**EXP

Pentru a avea deplasari numai intr-un singur sens, deplasam initial mantisa la stinga cu 8 c.b. si
completam 1 implicit pe primul bit. Vom considera numarul intreg rezultat dupa mutarea virgulei mantisei
(care se gaseste acum dupa primul bit), spre dreapta cu nr. de pozitii indicate de exponent ( EXP = CAR-127
).
Exponentul specifica nr. de cifre binare intregi ale numarului, iar restul fiind biti ce dau zecimale, care se
pierd in cazul numerelor intregi. Vom avea urmatoarele cazuri:

a) EXP = 31 - virgula se va deplasa cu 31 c.b. spre dreapta, chiar peste virgula corespunzatoare numerelor
intregi. Mantisa va reprezenta chiar numarul intreg.

b) EXP < 0 - virgula va trebui mutata spre stinga si numarul va fi < 1, deci intregul rezultat va fi N = 0.

c) EXP > 31 - virgula trebuie mutata cu mai mult de 31 pozitii spre dreapta, rezultind depasire (numar cu
mai mult de 32 c.b.)

107
d) 0 =< EXP < 31 - virgula se va deplasa spre dreapta cu mai putin de 31 c.b. si va trebui adusa pe ultima
pozitie din dreapta, corespunzatoare numerelor intregi. Aceasta se realizeaza cu 31 - EXP deplasari spre
dreapta.

Vom exemplifica algoritmul pe numarul


NF = 3.456 care in hexa este NF = 40 5D 2F 1B
CAR = 40H => EXP = CAR - 7FH = 80H - 7FH = 1
M = 00 5D 2F 1B - mantisa
Dupa deplasarea stinga cu 8 c.b. si completare 1 implicit:
M = DD 2F 1B 00
Pentru transformarea in numar intreg sint necesare
31 - EXP = 31 - 1 = 30 deplasari spre dreapta si rezulta:
N = 00 00 00 03 restul bitilor fractionari s-au pierdut

; -------------------------------------
; PROGRAM DE CONVERSIE FLOTANT - INTREG
; ---------------------------------------
.286c
.287
dosseg
.model small
.stack 100
.data
mdep db 10,13,'Depasire!! Nr. in VF prea mare $'
xf dd 51420. ; numar in VF x
dd 0 ; numar convertit intreg
xr dd 51420 ; numar intreg de referinta

; Definitie macro pentru conversie pozitiv flotant - intreg


CFI MACRO N,NF ; numar intreg si flotant
pusha ; salvare registre
mov dx, word ptr nf+2 ; nr. flotant pe 4 oct. in DX:AX
mov ax,word ptr nf
CALL SCFI ; chemare subpr. conv. flotant -intreg
mov word ptr n+2,dx ; memorare numar intreg
mov word ptr n,ax
ENDM
; -------------------------------------------

; Subprogram conversie flotant - intreg


; - intrare DX:AX numar flotant
; - iesire DX:AX numar intreg convertit
; --------------------------------------------
SCFI PROC NEAR
mov bx,dx ; verificare NF=0
or bx,ax
jnz c1 ; NF > 0
108
RET ; NF = 0 => N = NF
c1: mov bx,dx ; bx = CAR
shl bx,1 ; bh = CAR
mov cx,8 ; 8 depl. stinga mantisa
d8: shl ax,1 ; DX <- CF <- AX
rcl dx,1
loop d8
or dh,80h ; fortare bit implicit 1 mantisa
sub bh,127 ; EXP = CAR-127
cmp bh,31 ; comparare EXP cu 31
jnz c3
RET ; EXP = 31 => N=NF nu se fac deplasari
c3: js c4 ; EXP < 31
mov dx,offset mdep ; EXP >31 - mesaj depasire
mov ah,9
int 21h
RET
c4: cmp bh,0 ; comparare EXP cu 0
jns c5 ; 0 =< EXP < 31
xor ax,ax ; EXP<0 => N=0
mov dx,ax
RET
c5: mov cl,31 ; 0 =< EXP < 31
sub cl,bh ; CL = 31-EXP nr.deplasari dreapta
mov ch,0
c6: shr dx,1 ; 31-EXP deplasari dreapta mantisa
rcr ax,1 ; DX -> CF -> AX
loop c6
RET
SCFI ENDP
; -------------------------------------------
; Program principal conversie flotant intreg
; -------------------------------------------
ST1: mov ax,@data mov ds,ax
;
conv: CFI x,xf ; conversie X -> XF
;
int 3 ; terminare
END ST1
------------------------------------------------------------------

109

You might also like