Sunteți pe pagina 1din 210

Prof. dr.

Sever Spânulescu

Programarea în limbaj de asamblare a microprocesoarelor

-Lucrări de laborator-

Editura Victor

2004

1
Introducere

Deşi limbajele de programare s-au perfecţionat continuu pe parcursul


ultimelor decenii, se pare că suntem încă departe de apariţia unui limbaj absolut
optimal care să îmbine toate avantajele celorlalte limbaje şi să evite dezavantajele lor.
De altfel, majoritatea limbajelor de programare actuale au evoluat tocmai în direcţia
eliminării propriilor puncte slabe şi a achiziţionării celor mai moderne concepte din
teoria programării. A rezultat o tendinţă de apropiere reciprocă a acestora şi nu este
exclus ca în viitor să se constate o tendinţă de unificare într-un standard care să preia
soluţiile optimale ale diverselor limbaje de programare, ceea ce ar micşora eforturile
de învăţare şi chiar cele de căutare a celui mai adecvat limbaj pentru o aplicaţie dată.
S-ar putea spune însă că problema limbajului unic este principial
nerezolvabilă şi coexistenţa mai multor nivele în complexitatea actului de programare
este obligatorie.
Intr-adevăr, în dialogul om-maşină se constată în permanenţă o anume
distribuţie a eforturilor se dezvoltare şi utilizare a unui program. Se poate folosi un

2
limbaj care să necesite un efort mai mic din partea programatorului în partea de
dezvoltare şi mai mare din partea maşinii în partea de execuţie (rulare) , sau invers.
Se constată că, invariabil, în primul caz performanţele programului rezultat sunt mai
scăzute , iar în al doilea caz mai ridicate. Aceasta se datorează nivelurilor mai înalte şi
respectiv mai scăzute ale instrucţiunilor folosite.
Astfel, instrucţiunile unui limbaj de programare sunt de fapt grupuri mai mari
sau mai mici de operaţii care se petrec în interiorul calculatorului – instrucţiunile
maşină. Când grupurile respective sunt mari, programatorul are de scris mai puţin
cod, efortul său fiind scăzut, şi se spune că nivelul instrucţiunilor şi al limbajului este
înalt. Astfel de limbaje sunt: Basic, Pascal, etc. Dacă numărul de instrucţiuni maşină
dintr-o instrucţiune a limbajului este mai scăzut, efortul programatorului creşte, el
trebuind să scrie un cod mai complex pentru o sarcină dată. Astfel de instrucţiuni şi
de limbaje se numesc de nivel mediu, cum ar fi de exemplu C.
La extrema opusă există un limbaj ale cărui instrucţiuni coincid chiar cu
instrucţiunile maşinii – limbajul de asamblare. Aici efortul programatorului este
evident maxim şi limbajul respectiv este de nivel scăzut.
Problema esenţială a nivelului unui limbaj de programare este că nivelul său
se află într-o dependenţă invers proporţională cu eficienţa codului generat. Intr-
adevăr, cu cât instrucţiunile unui limbaj conţin mai multe instrucţiuni maşină, cu atât
viteza lor de execuţie scade. În plus, scade şi probabilitatea ca o anumită instrucţiune
să fie soluţia optimă pentru o problemă dată.
Programatorul are la dispozţie anumite tipuri de “prefabricate” - instrucţiunile
din care trebuie să alcătuiască programul, îmbinându-le pe cele mai apropiate de
necesităţile sale reale, chiar dacă acestea sunt uneori departe de prototipul cu eficienţa
optimă. Pe măsură ce dimensiunile acestor blocuri scad este mai posibil ca ele să se
îmbine mai eficient, mărind şi performanţa ansamblului. În fine, atunci când
performanţa este critică se pot folosi blocurile cu cele mai mici dimensiuni posibile -
instrucţiunile maşină ale limbajului de asamblare. Eficienţa codului este în acest caz
maximă, la fel şi efortul programatorului.
O altă variantă de adaptare eficientă a unui limbaj la o gamă largă de aplicaţii
o constituie diversificarea instrucţiunilor acestuia pentru a oferi soluţii prefabricate
într-un număr cât mai mare de situaţii. În acest caz se constată însă o creştere
anormală a numărului de instrucţiuni ale limbajului respectiv, mărind atât efortul de
învăţare căt şi pe cel de lucru ( de căutare) cu aceste instrucţiuni. Astfel, de exemplu,
funcţiile API (Application Programming Interface) utilizate de Visual C ajunseseră
deja de la varianta Windows 3.1 la un număr de peste 1300, pentru versiunile viitoare
de Windows evitându-se chiar menţionarea numărului total. Fiind scrise de mai multe
grupuri şi chiar generaţii de programatori, ele se suprapun uneori, mărind confuzia
utilizatorului.
In schimb, utilizarea limbajului de asamblare permite scrierea cu
instrucţiunuile cele mai adecvate posibile a oricărei porţiuni de program, aducând
prin aceasta viteza maximă care se poate astepta de la un anumit procesor. In plus, se
pot obtine creşteri de performanţă datorită posibilităţii repartizării eficiente a
variabilelor între registre şi memorie. Se ştie că, din considerente hardware, lucrul cu
registrele este mult mai rapid dacât cel cu memoria RAM şi incomparabil mai rapid
decât lucrul cu discul. Aria de registre constituie însă o resursă limitată a sistemului,
de aceea corect ar fi să fie cât mai mult utilizată de către variabilele care sunt cel mai
frecvent folosite într-o zonă de program dată. Compilatoarele repartizează în mod
oarecum arbitrar variabilele între registre şi memorie, neputând “intui” frecvenţa lor
aşa cum poate face un programator în limbaj de asamblare.

3
O bună soluţie de compromis o reprezintă utilizarea nivelului mediu, în
variantele limbajului C, al cărui succes este de altfel recunoscut. Dar chiar şi în cazul
folosirii limbajelor de nivel mediu, şi cu atât mai mult a celor de nivel înalt, pot
apărea porţiuni de program în care viteza este un parametru critic iar instrucţiunile
proprii conduc la soluţii innaceptabile din acest punct de vedere. În aceste cazuri,
soluţia deja clasică o constituie inserarea de porţiuni scrise în limbaj de asamblare.
Acesta este unul din principalele motive în favoarea cunoaşterii limbajului de
asamblare şi cel mai frecvent câmp de aplicare a acestuia.
În general, nu mai este recomandabilă în momentul de faţă scrierea unui
program folosind exclusiv limbajul de asamblare. Din analiza algoritmului unei
aplicaţii date pot rezulta insă porţiunile mari consumatoare de timp şi porţiunile de
interfaţare cu o pondere slabă în durata totală. In aceste cazuri, programul poate fi
scris într-un limbaj înalt sau mediu, iar porţiunile care necesită viteză - în limbaj de
asamblare.
Prin urmare, cunoaşterea limbajului de asamblare constituie calea naturală de
mărire a nivelului de performanţă al unui programator, acesta având posibilitatea să
rezolve cazurile cele mai dificile prin soluţii principial optimale.
Lucrarea de faţă prezintă numai acele aspecte ale programării în limbaj de
asamblare care prezintă o importanţă şi frecvenţă mai mare în situaţiile curente. Nu s-
au tratat probleme de mare complexitate, care ar putea descuraja un începător şi care
rareori sunt utile în practică, încercându-se în schimb o prezentare gradată, care să
asigure un antrenament sistematic al cursantului. Se recomandă ca, pe parcurs, să se
integreze astfel de programe, in programe scrise într-un limbaj de nivel înalt sau
mediu deja cunoscut.
De asemenea, se recomandă ca programele propuse să fie scrise şi rulate
efectiv pe calculator. În faza de execuţie (depanare), se vor putea observa deseori
diferenţe faţă de ceea ce s-ar aştepta în momentul scrierii programului. Tocmai astfel
de situaţii, în care apar probleme, sunt mai eficiente pentru fixarea cunoştinţelor de
programare şi ele au fost de multe ori incluse în mode deliberat în programele
propuse.
Această lucrare constituie rezultatul experienţei didactice de peste 14 ani,
perioadă în care au fost selectate prin feedback metodele cele mai eficiente de
învăţare rapidă a limbajului de asamblare. Prin respectarea ritmului şi etapelor din
lucrare, se poate constata chiar că învăţarea limbajului de asamblare este mai uşoară
decât a unui limbaj de nivel înalt.
Trebuie, totuşi, subliniat că utilizarea sa necesită cunoaştera realităţii
hardware a procesorului şi chiar a sistemului, iar scrierea unor programe complexe
necesită mult mai mult timp decât alte limbaje. Dacă, însă, decizia de a folosi
instrucţiuni maşină în porţiunui ale unui program este luată în mod corect, creşterea
de performanţă va fi evidentă iar efortul depus va fi răsplătit corespunzător.
Lucrarea se adresează în primul rând studenţilor Facultăţii de Electronică şi
Calculatoare a Universităţii Hyperion, şi studenţilor Facultăţii de Fizică a
Universităţii Bucureşti. Ea poate fi însă utilă tuturor programatorilor care doresc să-şi
mărească performanţele prin utilizarea celui mai rapid limbaj de programare -
limbajul de asamblare.

4
5
Lucrarea de laborator nr. 1
Utilizarea macroasamblorului TASM şi a depanatorului TD

Etapele dezvoltării unui program în limbajul de asamblare sunt următoarele:


1. Editarea
2. Asamblarea
3. Linkeditarea
4. Rularea şi eventuala depanare

Programul în limbaj de asamblare este scris mai întâi cu un editor de text


oarecare, constituind aşa-numitul program sursă. El trebuie să respecte două
categorii de reguli:
 Reguli specifice setului de instrucţiuni ale procesorului pentru care este scris.
Aceste reguli cuprind scrierea corectă a mnemonicelor instrucţiunilor, a operanzilor,
diverse prefixe şi notaţii suplimentare, toate fiind precizate în documentaţia
referitoare la procesorul respectiv.
 Reguli specifice programului asamblor cu care se lucrează. Aceste reguli se
referă la declaraţii, etichete, directive de asamblare, pseudoinstrucţiuni, eventual
macroinstrucţiuni, etc. Ele sunt precizate în documentaţia aferentă mediului de
asamblare.
După scrierea programului sursă, el este incărcat în asamblor care îl transforma
în final în program obiect. În plus, din procesul de asamblare se pot obţine şi alte
fişiere, care permit vizualizarea programului, a simbolurilor folosite, etc.
Programul obiect este la rândul său preluat de linkeditor, fiind transformat într-
un fişier executabil - programul final.
Programul executabil obţinut este testat în diverse moduri, iar în caz de
funcţionare necorespunzătoare din cauze care nu sunt evidente, se încarcă într-un
program depanator (debugger). Acesta permite rularea pas cu pas a zonelor neclare
din funcţionarea programului, cu afişarea continuă a conţinutului registrelor şi
memoriei, permiţând astfel localizarea problemelor. După clarificarea lor, este
modificat corespunzător programul sursă, şi procesul se reia.

1.1 Utilizarea TASM şi TD în forma clasică (linie de comandă, DOS)

Implementarea firmei Borland pentru limbajul de asamblare cuprinde în principal


trei aplicaţii, care vor fi utilizate în ordinea menţionării lor:
 TASM.EXE- asamblorul (Turbo Assembler)
 TLINK.EXE - linkeditorul (Turbo Linker)
 TD - depanatorul de program (Turbo Debugger)
Evident, în prealabil trebuie scris (editat) programul sursă, cu ajutorul unui
editor (acesta nefiind inclus în pachetul de la Borland).
Într-o fereastra DOS din sistemul de operare Windows (obţinută în Windows
XP din meniul Start-> Programs->Accessories->Command Prompt), comanda de
scriere a programului sursă poate fi de exemplu cea de apelare a aplicaţiei Wordpad a
sistemului:

write

6
În cazul în care se începe un program nou, ce urmează apoi să fie salvat sub
un nume propriu (obligatoriu cu extensia .asm), sau

write cale\Nume_Sursă

în cazul în care fişierul sursă există deja şi urmează a fi editat.


Se poate folosi de asemenea aplicaţia NOTEPAD.EXE, având avantajul că
poate să afişeze în bara de stare (jos) numărul liniei pe care se află cursorul, lucru util
pentru identificarea liniei la care asamblorul găseşte o eroare. Pentru aceasta va trebui
bifată în meniul View opţiunea Status Bar.
După salvarea fişierului sursă el va fi chemat de asamblor cu comanda:

Tasm Nume_sursă, Nume_obiect, Nume_listing


unde:
 Nume_sursă este numele ales pentru fişierul sursă editat anterior;
 Nume_obiect este numele sub care va apare fişierul obiect ce va fi transformat
în fişier executabil;
 Nume_listing este numele unui fişier opţional care conţine o varianta cu
informaţii rezultate din asamblare a fişierului sursă (listing), util pentru o
analiza vizuală.
Această linie de comandă admite şi anumite opţiuni, vizibile dacă se dă
comanda Tasm fără parametri într-o fereastră DOS. De exemplu, comanda:

Tasm.exe/zi Nume_sursă, Nume_obiect, Nume_listing/l

va genera informaţie completă pentru depanare (/zi) şi fişier listing normal (/l).
În cazul în care nu există erori de sintaxa (sunt respectate cele două categorii
de reguli menţionate) se obţine un mesaj favorabil (ca în figura 1), iar fişierul obiect
poate fi prelucrat mai departe.

Figura 1.1 - Exemplu de asamblare fără erori

În cazul în care apar erori, se reia editarea fişierului sursă, corectându-se


erorile şi se face din nou asamblarea.
Dacă în caseta de asamblare există linia Error messages: None, se poate trece
la linkeditare, folosindu-se comanda:

Tlink Nume_obiect, Nume_exefile

unde Nume_obiect este numele folosit în comanda precedenta (de asamblarere)


pentru fişierul obiect, iar Nume_exefile este numele ce se alege pentru fişierul

7
executabil. Se pot folosi şi aici opţiuni de linkeditare, care pot fi văzute rulând
comanda Tlink fără parametri într-o fereastra DOS. De exemplu, comanda

Tlink /v Nume_obiect, Nume_exefile

va genera informaţii simbolice complete pentru depanare.


În continuare, se poate rula programul executabil obţinut pentru a fi testat
(într-o fereastra DOS) sau se poate încarca în depanator (de exemplu Turbo
Debugger) pentru a fi rulat pas cu pas. În acest caz, comanda va fi:

TD Nume_exefile

Deoarece aceasta suită de comenzi se va repeta de fiecare dată, este comod să


se creeze un fişier batch de exemplu “Asamblare.bat” cu următoarea structură:

write.exe %1
pause
\tasm\bin\tasm.exe /zi %1,object,listing/l
pause
\tasm\bin\tlink /v object,exefile
pause
\tasm\bin\TD exefile

Acest fişier automatizează comenzile de asamblare, şi va fi folosit pentru


punerea la punct a unui program sursă care a fost creat iniţial cu comanda Write şi
salvat cu un nume având obligatoriu extensia .asm . Prin dublu click pe acest fişier,
se va selecta cu opţiunea “Browse” calea catre fişierul “Asamblare.bat” şi se va bifa
caseta “Always use this program to open this file”. În continuare, un dublu click pe
un astfel de fişier va lansa automat secvenţa de comenzi necesară asamblării. La
finalul fiecărui ciclu de asamblare, se va deschide fereastra depanatorului Turbo
Debugger care în general arată ca în exemplul din figura 1.2

8
Figura 1.2 - Fereastra principală din TurboDebugger

Se observă existenţa mai multor zone în aceasta fereastră.

1. Zona principală, care cuprinde partea stânga superioară afişează codul


programului şi are următoarele câmpuri (de la stânga la dreapta):
 Adresa efectivă în hexazecimal
 Codul instrucţiunii în hexazecimal
 Mnemonicul instrucţiunii
 Operanzii, cu eventualele constante numerice reprezentate în hexazecimal

2. Zona de memorie de date, din partea stânga jos, care cuprinde câteva linii
având structura:
 Adresa efectivă a segmentului de date - AE
 Conţinutul exprimat în hexazecimal al memoriei la AE
 Conţinutul hexa al memoriei la AE+1, ş.a.m.d până la AE+7
 Echivalentul ASCII al celor 8 octeţi aflaţi la adresele respective
Se poate afişa o fereastră suplimentară pentru vizualizarea unei zone mai mari
de memorie cu comanda "Dump" din submeniul View. Aceasta va apare, în
general, aşa cum se vede în figură, în partea de jos a ecranului.

9
3. Zona de registre, aflată în dreapta ferestrei principale, care afişează în
hexazecimal pe 16 biţi conţinutul tuturor registrelor

4. Zona de flaguri, în extrema dreaptă, în care sunt afişate valorile


indicatorilor de condiţii după fiecare instrucţiune executată.

5. În colţul din stânga jos este afişat conţinutul segmentului curent din stivă.

În fereastra principală se observă un cursor, reprezentat prin colorarea diferită


a unei linii (în figură, chiar prima linie) care poate fi folosit pentru a marca un punct
de oprire la o comanda de rulare a progranului. Cu opţiunea “Run to cursor” ( tasta
F4) din meniul “Run” se poate rula automat programul până la acest punct.
Poziţionarea cursorului este obligatorie dacă programul nu are un punct de oprire sau
ieşire (în caz contrar, se continuă automat cu interpretarea codurilor gasite în
memorie după ultima instrucţiune, iar sistemul se poate bloca). Terminarea se poate
face cu o instrucţiune de salt necondiţionat la ea insăşi, sau folosirea funcţiei 4Ch a
întreruperii 21h, cum se va arăta ulterior.
Ca alternativă, programul poate fi rulat instrucţiune cu instrucţiune, cu tasta
F7, urmărindu-se evoluţia registrelor, a memoriei şi a indicatorilor de condiţii după
fiecare pas.
Dacă asamblarea a decurs fără erori, în funcţie de setările TD, în fereastra
acestuia poate să apară chiar programul obiect care poate fi rulat de asemenea
instrucţiune cu instrucţiune (figura 1.3).

Figura 1.3 - Fişierul obiect în fereastra TD

Dacă se doreşte vizualizarea registrelor şi a memoriei, se poate selecta în


meniul “View” comanda “CPU”, sau alte ferestre. Eventual se poate bifa în meniul
“Option” ->”Display options” caseta “43/50 Lines” şi în “Option” ->”Save options”
caseta “Layout”.

1.2 Utilizarea TASM şi TD în forma integrata (fereastra Windows)

10
Se poate lucra mai comod folosind programul MIAD - Mediu Integrat de
Asamblare şi Depanare (© Universitatea Hyperion), care integreaza editorul,
asamblorul, linkeditorul şi depanatorul de la Borland într-o forma grafică.
La lansare apare fereastra de editare, în care se va scrie textul programului
sursă, ca în figura 1.4.
Există posibilitatea de a deschide un fişier cu extensia .asm din directoarea
C:\TASM\BIN, sau de a deschide un sablon care conţine elementele mininale care
trebuie să apară într-un program scris în assembler. După editare, fişierul se va salva
peste cel original, sau cu un nume nou, dar în care se va specifica obligatoriu
extensia .asm (alfel nu este recunoscut de asamblor).

Figura 1.4 -Mediul de asamblare

Urmează comanda de Asamblare +Link lansată din meniul Execuţie sau cu


butonul din bara de sub meniu, fiind generat un mesaj care arată condiţiile de
finalizare ale asamblării. Dacă au aparut erori, este afişată o fereastră cu fişierul
Listing, indicând tipul erorilor şi poziţia acestora, ca în figura 1.5. În caz că nu sunt
erori, listingul nu va fi afişat decât dacă este bifată opţiunea "Cu afişare listing" din
submeniul Execuţie.
Dacă există erori, se revine în fereastra iniţială, de editare, şi se corectează
acestea.
Se trece în continuare la rularea programului (etapă permisă numai dacă
asamblarea s-a facut fără erori). Se poate face rularea directă, cu comanda Run din
submeniul Execuţie sau cu butonul . Nu se recomandă însă aceasta comanda
decât atunci când programul nou creat este suficient de bine pus la punct pentru a nu
bloca sistemul. În fazele iniţiale ale dezvoltării programului se recomandă testarea şi
depanarea cu comanda Debug din submeniul Execuţie sau cu butonul . Aceasta

11
produce încărcarea programului în Turbo Debugger, apărând fereastra acestuia, ca în
figura 1.2

Figura 1.5 - Fiserul Listing cu specificarea erorilor

Dacă ordinea operaţiilor nu este respectată, programul dă mesaje care indică


etapele omise. Pe bara de jos a ferestrei principale este afişat numele fişierului curent
şi stadiul asamblării acestuia.

Lucrarea de laborator nr. 2


Instrucţiuni de transfer între registre

2.1 Elemente ale limbajului de asamblare

Programul sursă este format dintr-un număr de linii, care pot fi:

12
 Directive de asamblare
 Etichete şi declaraţii de simboluri
 Comentarii
 Linii de instrucţiuni
O linie de instrucţiune a programului sursă are următoarea structură:

{Etichetă:}_Mnemonic_{Prefix}_Operand1{,{Prefix}_Operand2}_{;Comentariu}

unde:
 Parantezele acolade indică un câmp opţional;
 Semnul _ indică un separator, care poate fi format din spaţii sau tab-uri; Între
Operand1 şi Operand2, separatorul este de regula o virgulă;
 Eticheta este un grup de caractere care începe cu o litera şi nu coincide cu un
cuvânt rezervat. Ea trebuie urmată de semnul “:” atunci când se află la
începutul liniei. Când este referita ca operand (de exemplu la o instrucţiune de
salt), ea nu mai este urmată de acest semn. Exemple: Eticheta1, Loop15, Salt,
Label, L22, etc.
 Mnemonicul este o prescurtare a descrierii instrucţiunii şi este conform cu
setul de instrucţiuni al procesorului;
 Operandul poate fi un nume de registru, o constantă numerică (date sau
adrese), sau o etichetă, conform descrierii instrucţiunii respective;
 Prefixele dau precizări suplimentare despre operanzi, conform descrierii
instrucţiunii respective;
 Comentariul este opţional şi trebuie precedat de semnul “;” . Tot ceea ce
urmează pe o linie după acest semn este ignorat de asmblor.

Toate programele care urmează a fi asamblate cu macroasamblorul TASM vor


avea o parte de preambul minimală, de forma:

.model small
.stack 100h
.code
start:
--------------
Primele trei liniii sunt directive de asamblare, care declară cantitatea de
memorie folosita, poziţia stivei, şi începutul segmentului de cod. A patra linie este
eticheta de intrare în program acesta încheindu-se cu declaratia END
eticheta_de_intrare.
Finalizarea se poate face cu o linie de bucla infinită şi cu directiva end, de
forma:

Bucla: jmp bucla


End start
Varianta normală de finalizare foloseşte întreruperea 21h şi se va prezenta
ulterior.

2.2 Notaţia hexazecimală:

În continuare se vor folosi următoarele notaţii pentru date (valori imediate,


precizate în instrucţiune):
13
-de 8 biţi - n:0..0FFh; notaţie echivalentă: imm8;
-de 16 biţi - nn:0..0FFFFh;notaţie echivalentă: imm16;
-de 32 biţi - nnnn:0..0FFFFFFFFh;notaţie echivalentă: imm32;
Pentru reprezentarea comodă a datelor, cuvintele în cod binar se împart în mai
multe grupuri de câte 4 biţi şi se asociază fiecărui astfel de grup un simbol (cele 10
cifre din sistemul zecimal plus primele 6 litere ale alfabetului), rezultând aşa-numita
reprezentare hexazecimală. Cu 4 biţi se pot realiza 2 4=16 combinaţii, conform
tabelului 2.1.
De exemplu, numărul binar:
1001010011001010
se va scrie:
1001.0100.1100.1010
adică 94CA în hexazecimal. Pentru a se evidenţia octeţii, se mai foloseşte şi scrierea
echivalentă 94.CA, unde 94 este octetul mai semnificativ iar CA octetul mai puţin
semnificativ.
În felul acesta se folosesc de până la 4 ori mai puţine cifre pentru
reprezentarea datelor. Un număr binar de 8 biţi (octet) se poate scrie cu 2 cifre
hexazecimale, un număr de 16 biţi (word) cu 4 cifre hexazecimale, etc.
Pentru a preciza ca un număr este reprezentat în hexazecimal (există astfel de
numere care nu conţin deloc litere) se foloseşte sufixul h ataşat în dreapta. De
exemplu numărul anterior se va scrie ca 94CAh.
Majoritatea asmbloarelor nu fac diferenţe între litere mari şi litere mici, deci
se pot folosi şi notaţii de genul: 94CAh , 94cAH sau 94caH.

Zecimal Binar Hexazecimal


0 0000 0
1 0001 1
2 0010 2
3 0011 3
4 0100 4
5 0101 5
6 0110 6
7 0111 7
8 1000 8
9 1001 9
10 1010 A
11 1011 B
12 1100 C
13 1101 D
14 1110 E
15 1111 F
Tabelul 2.1 - Reprezentarea hexazecimală

Mediul de asamblare consideră implicit constantele ca fiind zecimale.


Constantele hexazecimale trebuie să fie urmate de sufixul H, iar cele binare de
sufixul B (se pot folosi litere mari sau litere mici).
Dacă se intenţionează ca toate numerele din program să fie implicit
hexazecimale se poate introduce directiva .Radix 16, de regulă înaintea directivei

14
.Stack. Toate numerele folosite folosite în continuare sunt implicit hexazecimale.
Pentru specificarea numerelor zecimale se va folosi sufixul D.
Deoarece numerele hexazecimale cuprind şi litere, ele ar putea fi confundate
cu alte simboluri literale (etichete) folosite în program. De exemplu, numărul
hexazecimal ADCEH (în binar 1010.1101.1100.1110) ar putea fi o eticheta, o
variabila sau o constantă. Pentru a preciza că este vorba de un număr, dacă
numărul începe cu o litera se pune în stânga sa cifra 0. De exemplu, numărul
anterior se va scrie 0ADCEh, numărul 1011.1000.1001.0001 se va scrie 0B891h, etc.
Dacă numărul de biţi ai cuvântului binar nu este un multiplu de 4, el se va
completa în stânga cu 0 până devine multiplu de 4 şi apoi se face delimitarea cifrelor
hexazecimale. De exemplu numărul binar:
1011011001 se va scrie 0010.1101.1001= 2D9h sau 02D9h
Numerele folosite de diverşi algoritmi pot fi cu semn sau fără semn. Anumite
instrucţiuni aritmetice se comporta diferit pentru cele două categorii de numere, aşa
cum se va arata mai târziu. Pentru numerele cu semn se foloseşte următoarea
convenţie: primul bit din stânga al numarului (cel mai semnificativ) este bitul de
semn. El are valoarea 0 dacă numărul este pozitiv şi 1 dacă este negativ.
2.3 Registrele procesoarelor Intel x86

Microprocesorul convenţional din seria Intel x86 are următoarele registre


pentru lucrul curent:

Registrul Registrele de 8 biţi Utilizare preferenţială


de 16 biţi

AX AH AL Dedicat înmulţirilor şi împărţirilor,


etc.

BX BH BL Adresare (baza segmentului de date)

CX CH CL Contorizare

DX DH DL Utilizat în inmulţiri şi impartiri

DS Adresa segmentului de date

CS Adresa segmentului de cod

SS Adresa segmentului de stivă

ES Adresa extrasegment (transfer de


şiruri)

SI Adresa sursei în transferuri de şiruri

DI Adresa destinaţiei în transferuri de


şiruri

15
BP Adresare (baza segmentului de stivă)

SP Indicator de stivă

IP Numărator de program

F Registrul de flaguri (indicatori de


condiţii)
Registrele au fiecare câte 16 biţi, cele generale putând fi împărţite în câte două
registre de 8 biţi: cel care reţine octetul inferior, notat cu sufixul L şi cel care reţine
octetul superior, notat cu sufixul H.
Microprocesoarele de diverse tipuri au mai multe registre, cu mai mult de 16
biţi (cele din seriile I-386, I-486 şi Pentium ). Registrele de mai sus au de fapt la
aceste procesoare un număr de 32 de biţi, dar pot fi folosite ca registre de 16 biţi cu
notatiile de mai sus. În cazul în care se doreşte folosirea lor ca registre de 32 de biţi,
denumirea lor va fi precedată de litera E (de la "extended"), iar în preambulul
programului va trebui pusă directiva .386, pentru a preciza că este folosit un procesor
de la I-386 în sus.
Notaţiile folosite pentru registre în cele ce urmează sunt:
-de 8 biţi - r8: AL,AH,BL,BH,CL,CH,DL,DH;
-de 16 biţi - r16: AX,BX,CX,DX,SI,DI,BP,IP,F;
-de 32 biţi - r32: EAX,EBX,ECX,EDX,ESI,EDI,EBP,EIP,EF;
-registre de segment -rs: DS,ES,SS,CS.La procesoare de la I-386 în sus mai
există două registre suplimentare de segment, FS şi GS.

2.4. Instrucţiuni de transfer între registre

Mnemonic general: MOV dest,src


Acţiune: ‘dst’ ia valoarea ‘scr’
dst ← src

Operanzi: dst: r8,r16,r32,rs


src:r8,r16,r32,rs,n,nn,nnnn

Restricţii: nu sunt posibile transferuri de tip:


-MOV rs,rs (nu sunt posibile transferuri între registre de segment)
-MOV rs,nn (nu se poate scrie o constantă direct într-un registru de
segment)
-MOV cs,* (nu se poate transfera nimic în registrul de segment de cod)

Exemplul 2.1:

MOV AX, 33H ;Încarcă în AX constanta hexa 0033H


MOV DX, 1122H ;Încarcă în DX constanta hexa 1122H
MOV CL, AL ;Încarcă în CL conţinutul lui AL
MOV BL, DH ;Încarcă în BL conţinutul lui DH
MOV AH, DL ;Încarcă în AH conţinutul lui DL

16
Mod de lucru :
Toate constantele numerice specificate mai jos sunt hexazecimale, deci în
programul sursă vor fi urmate de sufixul h.
Rularea programelor se va face cu TD în modul pas cu pas (cu tasta F7) şi
după fiecare instrucţiune se va urmări în fereastra de afişare a registrelor modificarea
conţinutului acestora.
Se vor scrie şi testa următoarele programe:
P 2.1. Program de scriere în registrele AL, BL, CL şi DL a constantelor
99,AA, BB, respectiv CC.
P 2.2. Se va completa programul anterior pentru a transfera conţinutul
registrului AL în registrele BL, BH, CL, şi DH.
P 2.3. Program de scriere în registrele AX, BX, CX şi DX a constantelor
1122, 3344, 5566, respectiv 7788.
P 2.4. Se va completa programul anterior pentru a transfera conţinutul
registrului registrului BX în registrul DX, şi al registrului CX în AX.
P 2.5. Program care să transfere constanta 1234 în registrul DS şi constanta
5678 în registrul DX.
P 2.6. Să se scrie în registrele AL şi BL, constantele 99 şi AA şi se va face
apoi interschimbarea conţinutului acestora.

2.5. Instrucţiuni de interschimbare între registre

Mnemonic general:
XCHG dst,src

Acţiune: Se interschimba conţinuturile registrelor dest şi src.


dst ← src
src ← dst

Operanzi: dst,src:r8,r16,r32
Restrictii:Nu există instrucţiuni de tip:
-XCHG rs,rs
-XCHG cs,*

Mod de lucru :
P 2.7. Se vor încarca următoarele registre astfel:
AL cu 11
BL cu 22
CX cu 3344
DX cu 5566
după care se va interschimba conţinutul celor de 8 biţi şi conţinutul celor de 16 biţi.

P 2.8. Se vor încărca registrele AL, AH, BL şi BH constantele AA,BB,CC şi


DD şi apoi se va efectua permutarea circulară a conţinutului celor 4 registre. Se vor
folosi instrucţiuni de tip XCHG, şi după terminarea rulării programului registrele vor
trebui să aibă valorile: AL=BBh, AH=CCh, BL=DDh şi BH=AAh

2.6. Instrucţiuni de adunare şi scădere

17
Mnemonice generale:
-ADD dst,src - Adunare : dst=dst+src;
-ADC dst,src - Adunare cu transport (CF): dst=dst+src+CF
-SUB dst,src - Scădere: dst=dst – src;
-SBB dst,src - Scădere cu transport (“carry) sau împrumut (“borrow”):
dst=dst-src-CF;
În toate operaţiile aritmetice, se foloseşte implicit convenţia complementului
faţă de 2. Astfel, numerele pozitive au bitul cel mai semnificativ (MSB) 0, iar cele
negative au MSB 1. Numerele negative vor avea valoarea diferenţei între valoarea
lor absoluta şi 28n , unde n este numărul de octeţi folosiţi.
Exemple:
 25h=0010.0101 este un număr pozitiv, având echivalentul zecimal 37;
 0B3Ch= 0000.1011.0011.1100 este un număr pozitiv, cu echivalent zecimal
2876;
 0A7h=1010.0111 este un număr negativ (dacă este considerat de un octet), cu
valoare absoluta 167 şi valoare în complement faţă de 2 care se calculeaza
conform formulei 167-28 = -89;
 0CEACh = 1100.1110.1010.1100 este un număr negativ de doi octeţi, cu
valoare absoluta 52908 şi valoare în complement faţă de 2 care se calculeaza
conform formulei 52908-216 = -12628;
Se observă că un eventual 0 în faţa numărului scris în format hexazecimal nu
înseamna că acesta are semn pozitiv. Contează numai primul bit al octetului cel mai
semnificativ.
Aceste transformări se pot face cu utilitarul Calculator din Windows, având
opţiunea View - > Scientific.

Mod de lucru:
P 2.9. Se vor încarca registrele cu constantele: AX=1122, BX=3344,
CX=5566, DX=7788
şi se va efectua următoarea succesiune de operaţii:
AL+66
AL+BL
AL-CL
AL-22
AL+BL+CL+DL

P 2.10. Se vor încarca registrele cu constantele: AX=1122, BX=3344,


CX=5566, DX=7788
şi se va efectua următoarea succesiune de operaţii:
AX+6666
AX+BX
AX-CX
AX-22
AX+BX+CX+DX

P 2.11 Se vor încarca două numere de 32 de biţi în registre în felul următor:


- primul număr 11223344 în AX (octeţii superiori) şi BX (octeţii inferiori)
- al doilea număr 55667788 în CX (octeţii superiori) şi DX (octeţii inferiori)
În continuare se va efectua adunarea celor două numere. Rezultatul trebuie să fie
6688AACC

18
P 2.12 Acelaşi program ca la 2.11, numerele fiind 55667788 şi 99AABBCC.
Rezulatul trebuie să fie EF113354.

P 2.13 Acelaşi program ca la 2.11 dar, numerele fiind 55667788 şi 11223344,


se va efectua scăderea lor. Rezultatul trebuie să fie 44444444.

P 2.14 Acelaşi program ca la 2.13, numerele fiind 22334455 şi 66778899.


Rezultatul trebuie să fie BBBBBBBC.

Lucrarea de laborator nr. 3


Transferuri de date şi operaţii aritmetice cu memoria

3.1 Componentele unei adrese logice

Pentru a modulariza blocurile de memorie folosite de diverse task-uri şi


pentru a nu trebui specificată pe tot parcursul unui program o adresa logica de 32 de
biţi, arhitectura procesoarelor Intel x86 foloseşte procedeul segmentării. Astfel,
spaţiul de memorie este împarţit în blocuri de maxim 64 KB în Modul Real (respectiv
1 MB sau 4 GB în Modul Protejat), blocuri numite segmente.
Aceasta permite ca în Modul Real specificarea unei adrese de memorie să se
facă prin numai 16 biţi, consideraţi ca fiind poziţia locaţiei respective de memorie
faţă de baza segmentului în care se află. Acesti 16 biţi formează adresa efectivă
sau deplasamentul (offset). Ne vom referi în continuare, dacă nu se va specifică altfel,
numai la Modul Real de funcţionare.

Segment n

. .
. .
. .
. .
. . Locaţia vizată

Segment 2

19
Adresa efectivă (AE)

Adresa logica (AL)


Segment 1 Adresa baza segment (ABS)

Figura 3.1 - Adresarea în cadrul unui segment

Blocul de management al memoriei din interiorul procesorului va forma


automat o adresa logică de memorie ca în figura 3.1, după următoarea formulă
generală:
AL = AS*16 +AE
unde:
AL este adresa logică (coincide cu adresa fizică, transmisă pe magistrala de
adrese, dacă nu se foloseşte paginarea).
AS este adresa de segment, conţinută în unul din următoarele registre:
-CS pentru segmente de coduri de instrucţiuni
-DS pentru segmente de date
-SS pentru segmente de stivă
-ES pentru extrasegmente
Ea nu coincide cu adresa bazei segmentului , acesta fiind obtinuta prin
deplasarea cu 4 biţi spre stanga a adresei de segment (inmulţire cu 16):

ABS=16*AS

Prin acest procedeu de scriere a dreselor de segment, ele vor avea numai 16
biţi, iar adresa bazei segmentului va avea 20 si se obtine automat in unitatea de
management a memoriei din interiorul microprocesorului.
AE este adresa efectivă , indicând poziţia în interiorul unui segment, adică
deplasamentul faţă de baza segmentului. Ea are 16 biţi,ceea ce înseamnă că un
segment are o lungime de maxim 64k (216 locaţii).

Convenţii :
Orice operand pus între paranteze drepte reprezintă o adresa de
memorie . De exemplu [3A21] reprezintă conţinutul locaţiei de memorie cu adresa
efectivă 3A21, iar [BX+DI] reprezintă conţinutul locaţiei de memorie a carei adresa
efectivă este dată de suma între registrele BX şi DI.
Este permisă şi scrierea RG[const] cau const[RG] unde RG este un registru
general iar const este un deplasament (număr sau etichetă ) care se adună la
conţinutul acestui registru. Acestă forma este echivalentă cu [RG+const], deci
scrierea de termeni alaturaţi are semnificaţie de sumare şi nu de înmulţire.

Exemplu 3.1:
MOV CL,BX[10h] ; Încarcă în CL conţinutul
;locaţiei de memorie a carei adresa efectivă este suma

20
;între conţinutul lui BX şi constanta 10h, iar adresa
de ;segment este conţinută în DS.

Instrucţiunea este echivalentă cu forma MOV CL, 10h[BX].


În mod normal, programatorul va specifică numai adresa efectivă, dar în
cazuri speciale se poate folosi totuşi şi adresa fizică, prin specificarea şi a adresei de
segment, cu sintaxa:

AF=AS:AE

Exemplul 3.2:

MOV AH,DS:[20h] ;Transferă în AH conţinutul


;locaţiei 20h din segmentul a cărui
;adresă este conţinută în registrul DS
MOV SS:[BX+10h], CL ;Transferă conţinutul lui CL
;în locaţia a carei adresa efectivă este
;dată de conţinutul lui BX adunat cu 10h,
;din segmentul a cărui adresă este
;conţinută în SS.

Modul de lucru:

P 3.1 Se va scrie şi se va testa un program care efectueaza următoarele:


 Încarcă constanta 22h în registrul AL
 Trimite această constantă în memorie la adresa BX[20] şi la adresa
DS:30

Indicaţii:
Ambele locaţii sunt plasate în segmentul de date şi se pot vizualiza în zona
Dump din fereastra inferioară a Turbo Debugger.

3.2 Componentele unei adrese efective

Este comod să se lucreze în mod normal cu adrese efective, adresa de segment


fiind incărcată de procesor în mod automat din registrul de segment implicit pentru
operaţia respectivă. Aceasta conduce însă la necesitatea cunoasterii registrelor
implicite pentru diversele adresări, registre care vor fi specificate în continuare.
AE se alcătuieşte după formula generală:

AE = (BX/BP)* + (SI/DI)* + (D8/D16)*


unde:
* indică un termen opţional (nu se admite o AE formată numai din ultimul
termen)
/ separă variantele unui termen
BX şi BP sunt registrele de tip bază
SI şi DI sunt registrele index ( sursă şi respectiv destinaţie)
D8 şi D16 reprezintă un deplasament exprimat pe 8, respectiv 16 biţi

Deci, adresa efectivă se exprima şi sub forma:


21
Adresa = Baza + Index + Deplasament,
unii dintre aceşti termeni fiind opţionali.
În funcţie de registrele generale folosite în formarea unei adrese, registrele de
segment implicite sunt cele din tabelul 3.1.

Registru general Registru de segment implicit


SP SS
BP SS
BX DS
SI DS
DI ES
BP+SI sau BP+DI SS
BX+SI sau BX+DI DS
IP CS

Tabelul 3.1- Registrele de segment implicite la formarea unei adrese

Trebuie să se ţină seama în permanenţă de regulile registrelor de segment


implicite deoarece asamblorul nu poate semnala erori în cazul utilizarii lor incorecte.
De exemplu, dacă se doreşte citirea unei valori din segmentul de date şi se foloseşte
registrul general BP în instrucţiunea:

MOV CH,[BP+10]

asamblorul consideră ca aceasta instrucţiune este corectă şi ca intenţia


programatorului a fost să citească din segmentul de stivă (vezi tabelul).
Programatorul ar fi trebuit să foloseasca unul din registrele BX sau SI dacă dorea
citirea din segmentul de date.
Observaţie: Asamblorul nu acceptă AE specificată numai ca o constantă
numerică, deoarece nu poate şti registrul de segment implicit. De aceea, se vor folosi
forme de sumare cu un registru (eventual adus la 0 în prealabil), sau adrese logice .
Exemplu: în loc de MOV AL, [3000] se va folosi MOV AL,[BX+3000], dacă
BX a fost facut 0 în prealabil. Unele asambloare dau însă doar o avertizare şi folosesc
segmentul de date, indiferent dacă aceasta a fost intenţia programatorului sau nu.

Modul de lucru:
În programele care urmează se va incerca, de câte ori este posibil, să se
folosească adrese efective, lăsând procesorul să încarce automat adresa de segment
din registrul implicit specificat în tabelul 3.1.
P 3.2. Se va scrie şi se va testa un program care efectuează următoarele:
 Încarcă constanta 22 în registrul AL;
 Trimite această constantă în memorie în segmentul de date la adresa
10 şi la adresa 30;
 Trimite această constantă în memorie în segmentul de stivă la adresa
120.
Indicaţii:
Primele două locaţii se pot vedea în fereastra Dump, iar ultima în fereastra
Stack din dreapta jos a Turbo Debugger.

22
Pentru a se specifică segmentul de stivă, se va folosi adresarea prin registrul
BP.

3.3 Transferuri pe 1 octet şi pe 2 octeţi

O locaţie de memorie are prin convenţie un octet, astfel că ea poate fi operand


numai pentru un registru de 8 biţi. În cazul în care se fac transferuri cu registre de 2
octeţi se utilizează următoarea convenţie ("little-endian"): la adresa specificată se
află octetul inferior al registrului dublu, iar la adresa imediat următoare octetul
superior.
Specificarea lungimii operandului (1 octet sau 2 octeţi) este sau implicită sau
declarată cu prefixele BYTE PTR repectiv WORD PTR .

Exemplul 3.3:
MOV AL, [BX+3000] transferă numai în AL octetul de la adresa 3000 din
segmentul de date. Nu este nevoie de prefix deoarece operandul AL este de 8 biţi şi
rezulta implicit un transfer de un octet.
MOV AX, [SI+3000] transferă în AL octetul de la adresa 3000 din segmentul
de date şi în AH octetul de la adresa 3001 din segmentul de date (întotdeauna în
octetul superior conţinutul locaţiei de memorie cu adresa mai mare). Nu este nevoie
de prefix deoarece operandul AX este de 16 biţi şi rezultă implicit un transfer de doi
octeţi.
ADD word ptr [BX+3000],59 adună la cuvântul (număr de 16 biţi) conţinut
în locaţiile 3001 şi 3000 din segmentul de date, numărul 59. Dacă nu s-ar specifică
lungimea "word ptr", s-ar face adunarea pe un singur octet între conţinutul locaţiei
3000 şi constanta 59.
ADD byte ptr [BP+3000],59 adună la octetul conţinut în locaţia 3000 din
segmentul de stivă, numărul 59, fără vreo influenta asupra locaţiei 3001. Dacă nu s-
ar specifica lungimea, operaţia s-ar efectua tot pe un octet, dar asamblorul ar afişa
totuşi o avertizare legată de lungimea operanzilor.

Modul de lucru :

Se vor scrie şi testa următoarele programe, folosindu-se pe cat posibil numai


adrese efective:
P 3.3. Program care încarcă în AX constanta 3344 şi o trimite în memorie la
adresa 20h. Se va observă în ce fel apar octeţii acestei constante în memorie.
P 3.4.Trimite în memorie la adresa 20 constanta 1122 şi la 30 constanta 44
P 3.5. Program care:
 încarcă constanta 33EE în AX
 o trimite în memorie la adresa 30
 încarcă constanta 22 în AL
 adună această constantă la numărul din locaţiile încarcate anterior cu
constanta 33EE.
Indicaţii:
Pentru a avea rezultatul adunării pe 16 biţi, va trebui folosit registrul AX,
după ce se încarcă AH cu 00.
În memorie, la adresa DS:30 vor apare octeţii 10.34, adică numărul 3410,
rezultatul adunării lui 33EE cu 22.

23
P 3.6. Program care trimite în memorie la adresa 10 din segmentul de date
suma constantelor 44 şi 122, fără să se specifice explicit registrul de segment.
Indicaţii:
Rezultatul, la adresa 10 trebuie să apară sub forma 66.01.
P 3.7. Acelasi program ca la punctul 3.6 dar se vor folosi adrese logice, fără a
implica alte registre generale (se presupune ca nu trebuie modificat conţinutul
acestora).
Indicaţii:
Va fi necesar să se specifice explicit registrul de segment.

3.4 Moduri de adresare

În funcţie de termenii folosiţi în formula generală a adresei efective, se


definesc următoarele moduri de adresare:

1. Adresare imediată la memorie:


Se specifică în adresa efectivă numai deplasamentul, care constituie chiar
adresa efectivă. Conform observaţiei de la paragraful 3.2, este necesar să se specifice
şi registrul de segment, deci se va scrie de fapt o adresa logică.

Exemplul 3.4:
MOV AX,DS:[54] ;Încarcă în AL conţinutul
locaţiei cu adresa efectivă 54 din segmentul de date, iar
în AH conţinutul locaţiei următoare
MOV ES:[3AC2],DL ;Încarcă în locaţia cu adresa
efectivă 3AC2 din extrasegment conţinutul registrului de
8 biţi DL

Adresa efectivă poate fi specificată şi printr-o etichetă (în paranteze drepte şi


cu specificarea unui segment sau a unui registru general) care a fost declarată
anterior. Declararea unei etichete se face cu una din variantele:
eticheta EQU număr
eticheta EQU şir
eticheta = număr
Dacă se foloseşte forma cu EQU, se admite pentru asignare şi un şir de
caractere, în schimb nu se mai poate face altă asignare ulterioară în program. Forma
cu = admite reasignări, dar nu permite asignarea cu şiruri.

Exemplul 3.5:
adresa1 equ 20h
adresa2 equ adresa1+2
adresa3=30h
.
.
.

24
mov AL,DS:[adresa1]; Încarcă în AL continutul
;locaţiei de memorie de la adresa 20h
;din cadrul segmentului de date
mov SI[adresa2],ch ;Încarcă CH în adresa 22h
;din cadrul segmentului de date
mov AH,[BP+adresa3];Încarcă în AH de la
;adresa 30h din cadrul segmentului de
;stivă
.
.
.

2. Adresarea directă

În caz că se utilizează numele unei locaţii declarate în cadrul segmentului de


date, nu mai sunt necesare parantezele drepte şi un alt registru. Adresa de segment
este conţinută implicit în DS, dacă nu se specifică altfel.
Aceasta formă este posibilă pentru segmentul de date, care poate fi declarat în
partea iniţială a programului, fără ca programatorul să se preocupe de plasarea sa
exactă în memorie. Se utilizează directive de rezervare a unor locaţii de memorie,
DB, DW, etc. care vor fi prezentate pe larg mai târziu. Adresa va fi calculată automat
de asamblor şi înlocuită în instrucţiune cu valoarea numerică corespunzătoare.

Exemplul 3.6:
.model small
.stack 100h
.DATA
locaţie db 33,44,55,66 ;Stabileşte adresa
;"locaţie" la începutul
;segmentului de date
.code
MOV AX,@dată ;Încarcă adresa segmentului de date
MOV DS,AX ;în registrul DS
MOV AL,locaţie+2 ;Încarcă în AL octetul de la a
;locaţia 02 din DS
MOV locaţie+1, byte ptr AL;Încarcă în locaţia 01
;conţinutul lui AL
.
.
.
Se observă că nu este necesară punerea operandului de adresa în paranteze,
prin eticheta declarată după directiva .DATA înţelegându-se implicit conţinutul unei
locaţii de memorie.
Observaţie: Instrucţiunile care urmează imediat după directiva .code din
exemplul de mai sus ( cele cu caractere bold) sunt necesare întotdeauna atunci când
se declară un segment de date. Asamblorul şi linkeditorul plasează acest segment
acolo unde au memorie liberă şi adresa acestui segment trebuie incărcată explicit în
registrul de segment de date, DS. Cum acest registru nu admite o încărcare directă cu
o constantă, această adresă, cunoscută de asamblor prin simbolul @dată se încarcă
întâi într-un registru general şi apoi se transferă în registrul DS. Se poate folosi şi

25
forma de referire la o variabilă sau constantă din segmentul de date (forma
nerecomandată totuşi în astfel de cazuri):

MOV AX, seg locaţie

Programul Turbo Debugger, dacă are implicit afişata o fereastra Dump, după
rularea instrucţiunii MOV DS,AX va afişa automat zona respectivă cu registrul de
segment ES. Pentru a afişa chiar segmentul de date, trebuie dată o noua comanda
Dump din submeniul View, atunci când fereastra CPU este activata (dacă nu este, se
da un click pe aceasta fereastra). În noua fereastra dump se vor observa datele
declarate.

3.Adresare indirectă la memorie prin registru.


Se specifică în instrucţiune registrul din care se va lua adresa efectivă. După
cum rezulta din formula, registrul este unul din următoarele: BX,BP,SI,DI.

Exemplul 3.7:
MOV AL, [BX] ;Încarcă în AL conţinutul
;locaţiei de memorie a carei adresa efectivă este
;conţinută în BX şi adresa de segment conţinută în
;registrul implicit DS.
MOV [BP],CX ;Încarcă conţinutul lui CL în
;locaţia de memorie a carei adresa efectivă este
;conţinută în BP şi adresa de segment conţinută în
;registrul implicit SS, iar conţinutul lui CH în
locaţia ;de memorie următoare.

Dacă nu se specifică în adresa şi un registru de segment, acesta va fi cel


implicit, specificat de tabelul 3.1

4.Adresare indirectă la memorie prin registru cu deplasare.


Adresa efectivă este dată de suma registrului şi deplasamentului specificate de
instrucţiune. Adresa de segment va fi dată de DS, cu excepţia cazului în care se
utilizeaza registrul BP, caz în care adresa de segment este dată de SS.

Exemplul 3.8:
MOV AL,[DI+31] ; Transferă în AL conţinutul locaţiei
a carei adresa este dată de conţinutul lui DI la care se
adună 31, iar adresa de segment este dată de DS.
MOV [BP+1226],CX; Transferă pe CL în locaţia a carei
adresa este dată de conţinutul lui BP la care se aduna
1226, iar adresa de segment este dată de SS, iar CH în
locaţia următoare.
Aceste instrucţiuni se mai pot scrie şi :
MOV AL,31[DI] respectiv
MOV 1226[BP],CX
Modul de adresare prin registru cu deplasare se recomandă pentru adresarea
elementelor şirurilor şi tabelelor. De exemplu, dacă s-a definit anterior constanta
numerică TAB ( de exemplu TAB EQU 2100) se poate adresa elementul de tabel cu
numărul conţinut în registrul SI printr-o instrucţiune de genul ADD BX, TAB[SI].

26
5.Adresare indirectă la memorie prin 2 registre.
Adresa efectivă este dată de suma a două registre specificate de instrucţiune
(una din cele 4 variante posibile conform expresiei generale).
Registrul de segment implicit este DS cu exceptia cazului când este
menţionat BP, în care caz segmentul este cel de stivă, cu adresa conţinută în SS.
Modul de adresare prin registru cu deplasare se recomandă pentru adresarea
elementelor şirurilor şi tabelelor. De exemplu, dacă s-a incărcat anterior constanta
numerică TAB într-un registru de baza ( de exemplu MOV BX,2100) se poate adresa
elementul de tabel cu numărul conţinut în registrul SI printr-o instrucţiune de genul
MOV CX,[BX+SI].

Exemplul 3.9:
MOV CL,[BP+SI] sau MOV CL,[BP][SI]
SBB DX,[BX+DI] sau SBB DX,[BX][DI]

6.Adresare indirectă la memorie prin 2 registre cu deplasare.


Adresa efectivă este dată de suma a două registre şi un deplasament, toate
elementele fiind specificate de instrucţiune.
Registrul de segment implicit este DS cu exceptia cazului când este menţionat BP, în
care caz segmentul este cel de stivă, cu adresa conţinută în SS.

Exemplul 3.10:
MOV CX,[BX+SI+2C]
SUB DX,[BP+SI+2455]

Modul de adresare prin 2 registre cu deplasare se recomandă pentru adresarea


elementelor matricilor. De exemplu, dacă s-a definit anterior constanta numerică
MAT ( de exemplu 2100) iar BP conţine numărul unei linii înmulţit cu numărul total
de coloane se poate adresa elementul din linia respectivă având indicele (numărul de
coloană) conţinut în registrul SI, printr-o instrucţiune de genul:

ADD BX,MAT[BP][SI];echivalentă cu ADD BX,[BP+SI+2100]

De exemplu, pentru o matrice cu 5 linii şi 6 coloane, care începe la adresa


20h, dacă se doreşte accesarea elememtului al treilea din linia a patra, vom scrie:

MAT=20h
MOV BX, 18
MOV SI,3
MOV CL, MAT[BX+SI]

Modul de lucru

P 3.8. Se va realiza un program care să execute prin adresări imediate


următoarele operaţii:
 În CH se va citi (transferă) de la adresa 10 din memoria de date
 În DX se va citi de la adresa 11
 Se va scrie la adresa 20 constanta 22

27
 Se va scrie la adresa 21 constanta 8877
 Se va scrie la adresa 30 conţinutul lui CH
 Se va scrie la adresa 31 conţinutul lui DX

P 3.9. Se va realiza un program care are următoarele date iniţiale: constantele


de un octet A=11 şi B=22 şi constantele de doi octeţi C=3344 şi D=5566.Se va
calcula in BX expresia (C+D)-(A+B).

P 3.10. Se vor încarca registrele în felul următor: AX=2233, CX= 99AA,


DL=10 BX=20. Suma dintre AX şi CX se va trimite în memorie la adresa formată din
suma între BX şi DL iar diferenta lor la adresa imediat următoare.
Indicaţii:
- AX trebuie salvat înainte de sumare;
-DL nu poate fi adunat direct cu BX şi nici nu poate fi folosit la formarea AE.
-În memorie, la adresa DS:0030 va apare şirul: DD.BB.89.88

P 3.11. Se vor încarca registrele în felul următor: AX=1122, BX= 3344,


CX=5566 şi DX=7788. Sa se facă permutarea ciculară a acestor registre (AX ia
valoarea lui BX, BX a lui CX, CX a lui DX iar DX a lui AX). Se vor folosi pentru
stocarea temporară în memorie a unui registru modul imediat, modul direct şi modul
indirect.
P 3.12. Folosind instruncţiunea de adunare a unui registru cu o constantă, se
vor încarcă 4 locaţii succesive de memorie începând de la 10, cu numere crescătoare
de un octet, începând cu 1.

P 3.13. Acelasi program ca la punctul 3.12, dar cu numere pe doi octeţi


începând cu 1000.

P 3.14. Acelasi program ca la punctul 3.12, dar cu numere pe un octet


multipli de 5.

P 3.15. Acelasi program ca la punctul 3.13, dar cu numere pe doi octeţi,


multipli de 201.

P 3.16. Se va completa ultima varianta de program pentru a se transferă


conţinutul zonei de memorie de la 10 la 15 începând de la adresa 30 .

28
Lucrarea de laborator nr. 4
Procedee de transfer cu memoria

Deoarece numărul registrelor de uz general este mic, de multe ori este necesar
ca anumite rezultate intermediare sau alte variabile să fie stocate în memorie. Pentru
efectuarea de trensferuri cu memoria sunt utilizabile mai multe soluţii.

4.1 Transferuri prin adresare la memorie.

În acest caz, adresa efectivă este specificată de program, folosind unul din
modurile de adresare prezentate anterior. Metoda va fi folosită atunci când se doreşte
cunoaşterea adresei de memorie respective, ea fiind impusă de algoritm. De exemplu,
dacă se doreşte scrierea în memoria ecran care începe la adresa A000h, adresa
efectivă unde se va scrie poate fi specificată explicit de program.

4.2 Transferuri prin stivă

Pentru salvarea în memorie şi readucerea din memorie a unor registre se pot


folosi instrucţiunile complementare PUSH rs şi POP rd.
Instrucţiunea PUSH rs:
Mnemonic: PUSH rs:
Efect:
Mai întâi, registrul SP este decrementat cu 2. Apoi, conţinutul registrului sursă
dublu rs este trimis în memorie (în stivă) la adresa specificată de registrul SP (stack
pointer).

SP← SP-2.
[SP] ← rsL
[SP+1] ← rsH

29
POP rd:
Efect:
Mai întâi, conţinutul registrului destinaţie dublu rd este incărcat din memorie
(din stivă) de la adresa specificată acum de registrul SP (stack pointer). Apoi,
registrul SP este incrementat cu 2.

rdL ←[SP]
rdH ←[SP+1]
SP← SP+2.

Lucrul cu stiva prin instrucţiunile PUSH şi POP este comod deoarece nu


necesită calculul sau specificarea adresei de memorie. Trebuie să se ţină cont însă de
ordinea în care au fost salvate registrele în stivă, astfel ca dacă dorim refacerea lor,
încărcarea trebuie facută în ordine inversă.

Exemplul 4.1:

.
.
.
PUSH AX ;Acum SP=SPiniţial-2.
;Salvează AX la [SPiniţial -2].
PUSH BX ;Salvează BX la [SPiniţial-4]
. ;Alte instrucţiuni
. ;pe parcursul carora SP=SPiniţial- 4
.
POP BX ;Readuce BX de la[SPiniţial-4].
;Acum SP=SPiniţial-2.
POP AX ;Readuce AX de la [SPiniţial-2].
;Acum SP=SPiniţial.
.
.
.

Uneori poate fi alterată în mod voit ordinea inversă, pentru a se folosi alt
registru destinaţie decât cel care a fost iniţial sursă:

Exemplul 4.2:
.
.
.
PUSH AX ;Salvează AX la [SP].Acum SP=SPiniţial-2
. ;Alte instrucţiuni
. ;pe parcursul carora SP=SPiniţial- 2
.
POP BX ;Acum SP=SPiniţial. Readuce în BX de la
;[SPiniţial], ceea ce a fost înainte în
;AX
.
.
.
30
Modul de lucru
P 4.1. Se vor încarca registrele în felul următor: AX=1122, BX= 3344,
CX=5566 şi DX=7788. Sa se facă permutarea ciculară a acestor registre (AX ia
valoarea lui BX, BX a lui CX, CX a lui DX iar DX a lui AX). Se vor folosi numai
instrucţiuni PUSH şi POP (se va observă evoluţia stivei şi a SP în partea din dreapta
mijoc a TD) .
Indicaţie:
Se va folosi un registru suplimentar pentru a memora temporar conţinutul
unuia dintre registrele specificate.

4.3 Transferul prin iniţializarea/rezervarea de locaţii de catre asamblor

În cazul în care nu este necesară o adresă anume de memorie, variabila putând


fi stocată acolo unde există loc liber, nu mai este necesară specificarea explicită a
adresi efective. Se va folosi o directivă de asamblare de tip DB pentru rezervarea unei
locaţii de 1 octet sau DW pentru rezervarea unei locaţii de 2 octeţi (vezi anexa 1 -
Directive de asamblare).
De regulă, se va defini mai întâi un segment de date, cu directiva:
.DATA
şi aici se pot plasa directive de tip DB sau DW.

Exemplul 4.3:

.Radix 16
.Model small
.Stack 100h
.DATA
variabila1 DB ?
variabila2 DB 3F
variabila3 DW ?
sir1 DB 10 DUP(1A)

.Code
start:
mov ax,@dată ;Încarcă adresa
;segmentului
mov ds,ax ;de date în DS
mov al,variabila2 ;Încarcă în AL constanta
;3Fh
add al, 55h ;Aduna cu 55h
mov varibila1,al ;Depune octetul din AL în
;memorie la adresa
;variabila1
mov ah,variabila2 ;Aduce şi în AH constanta
;3Fh
mov variabila3,ax ;Depune cuvântul din AX
;în memorie la adresa
;variabila3
term: jmp temp

31
end start

Referirea în program a locaţiei se face prin numele asignat în stânga


directivei. Se observă că dacă se doreşte iniţializarea locaţiei, se va specifică
constanta care trebuie să fie iniţial acolo, iar dacă nu, se va folosi simbolul "?".
Se pot iniţializa mai multe locaţii cu directiva DB sau DW, valorile respective
fiind separate prin virgule.

Exemplul 4.4:
numere1 DW 23A4h,0BC56h,96h ;Declară 4 numere
;de 2 octeţi
caractere DB 'F','2','7' ;Declară 3
;caractere de un octet
const1 DB 21,0A2h,'L' ;Declară 3 valori
;diverse

De asemenea, se pot iniţializa sau rezerva un număr de n locaţii cu formularea


n DUP(const) sau respectiv n DUP(?) ca în exemplul de mai sus pentru constanta
ŞIR.
Observaţie: Cum s-a aratat şi în lucrarea precedenta, instrucţiunile care
urmează imediat după directiva .code (cele cu caractere bold in exemplul 4.3), sunt
necesare întotdeauna atunci când se declară un segment de date. Asamblorul şi
linkeditorul plasează acest segment acolo unde au memorie libera şi adresa acestui
segment trebuie incărcată explicit în registrul de segment de date, DS.
După rularea instrucţiunii MOV DS,AX programul Turbo Debugger, dacă are
implicit afişata o fereastra Dump, va afişa automat zona respectivă cu registrul de
segment ES, aceasta zona nefiind cea de date. Pentru a afişa chiar segmentul de date,
trebuie dată o noua comanda Dump din submeniul View după rularea acestei
instrucţiuni atunci când fereastra CPU este activata (dacă nu este, se da un click pe
aceasta fereastra). În noua fereastra dump se vor observă datele declarate.

Modul de lucru

P 4.2. Se va rula programul din exemplul precedent şi se va observa evoluţia


registrelor şi a zonei de memorie de date.

P 4.3. Se vor declara în segmentul de date şirul de cuvintele 1122, 3344 şi


5566 şi se vor transfera în alte trei locaţii rezervate (în locaţii consecutive variabilelor
declarate iniţial).
Observaţii:
Se vor folosi directive DW, deci adresa locaţiei 3344 este sursă+2, etc. Pentru
locaţiile de destinaţie se poate folosi o directiva de tipul:
dest DW 3 DUP(?)

P 4.4. Se va declara în segmentul de date un şir de 10 numere crescătoare de


un octet, începând cu 1, şi se va inversa conţinutul primei locaţii cu ultima şi a celei
de a doua cu penultima.

32
4.4 Instrucţiunea de translatare a unei adrese, XLAT

Dacă în memorie este definit un şir sau o tabelă a cărei adresă este specificată
de BX , se poate face încărcarea în AL a valorii conţinute în locaţia de memorie
[BX+AL], adică a locaţiei cu indexul dat chiar de AL în acea tabelă.
Atenţie: Indexarea incepe de la 0.
Formatul instrucţiunii este:
XLAT
Acţiune:
AL ← [BX+AL]

Exemplul 4.5:

.
.
.
mov bx, 1200h
mov al,5
xlat ; În AL va apare conţinutul locaţiei de memorie
;1205h adică al locaţiei cu numărul 5 din tabelă, TABELA5
.
.
.

Modul de lucru

P 4.5. Se va scrie un program care să aducă în DL conţinutul locaţiei cu


indexul 5 dintr-o tabelă care începe la adresa 10 din segmentul de date şi în DH
conţinutul locaţiei cu indexul 8 din acea tabelă. Se va folosi instrucţiunea XLAT.

4.5 Instrucţiuni de transfer pentru registrul de flaguri

Verificarea/modificarea individuală sau în bloc a flagurilor se poate face prin


transferul între registrul AH şi registrul de flaguri folosind următoarele instrucţiuni:

LAHF
Acţiune: Încarcă flagurile din registrul de flaguri în AH.
AH7=SF (flagul de semn, 1 dacă este minus, 0 dacă este plus);
AH6=ZF (flagul de zero, 1 dacă este 0, 0 dacă nu este 0);
AH5=0;
AH4=AF (flagul de transport auxiliar de la cei 4 biţi inferiori ai unui rezultat);
AH3=0 ;
AH2=PF (flagul de paritate, 1 dacă este par, 0 dacă este impar);
AH1=IF (flagul de întreruperi, 1 dacă dacă întreruperile sunt activate, 0 dacă
nu);
AH0=CF (flagul de transport 1 dacă există transport de la rezultat);

SAHF
Acţiune: Salvează flagurile AH în registrul de flaguri.

33
SF=AH7 (flagul de semn, 1 dacă este minus, 0 dacă este plus);
ZF=AH6 (flagul de zero, 1 dacă este rezultatu 0, 0 dacă nu este 0);
AF= AH4 (flagul de transport auxiliar de la cei 4 biţi inferiori ai unui
rezultat);
PF=AH2 (flagul de paritate, 1 dacă este par, 0 dacă este impar);
IF= AH1 (flagul de întreruperi, 1 dacă dacă întreruperile sunt activate, 0 dacă
nu);
CF=AH0 (flagul de transport 1 dacă există transport de la rezultat);
Biţii AH5 şi AH3 trebuie să fie 0.

4.6 Încărcarea unei adrese logice din memorie

Dacă în memorie la adresa nn se află un pointer (ca o adresă logică de 32 de


biţi), ea poate fi adusă într-o pereche formată dintr-un registru de segment şi un
registru de 16 biţi, folosind instrucţiunile LGS/LSS/LDS/LES/LFS.

Sintaxa: LDS r16,RS:nn


LSS r16,RS:nn
etc.
Acţiune:
LDS r16,nn: R16L←[RS:nn], R16H←[RS:nn+1], DSL←[RS:nn+2], DSH←[RS:nn+3]
LSS r16,nn: R16L←[RS:nn], R16H←[RS:nn+1], SSL←[RS:nn+2], SSH← [RS:nn+3]
LES r16,nn: R16L←[RS:nn], R16H←[RS:nn+1], ESL←[RS:nn+2], DEH←[RS:nn+3]
LFS r16,nn: R16L←[RS:nn], R16H←[RS:nn+1], FSL←[RS:nn+2], FSH←[RS:nn+3]
LGS r16,nn: R16L←[RS:nn], R16H←[RS:nn+1], GSL←[RS:nn+2], GSH←[RS:nn+3]

unde r16 este un registru de 16 biţi de uz general, RS este un registru de segment


(DS,SS,ES,FS sau GS) iar nn este un număr de 16 biţi.
Observaţii:
 Instrucţiunile LSS, LGS, LFS nu apar la procesoare anterioare lui 80386 (nici
nu existau registrele de segment FS şi GS), de aceea, în cazul folosirii lor, în
partea iniţială a programului trebuie introdusă directiva .386.
 Cu specificarea directivei .386, se poate folosi în al doilea operand şi un
număr nnnn (de 32 de biţi).

Modul de lucru

P 4.6. Să se scrie un program care să aducă în perechea ES:AX conţinutul a


patru locaţii de memorie a caror adresă de început este dată de DS+10h. Se va folosi
instrucţiunea LES.

4.7 Încărcarea unei adrese efective

Atunci când trebuie specificată o adresă care a fost calculată de asamblor şi nu


este cunoscută numeric, se poate folosi instrucţiunea LEA (Load Effective Adress):
Sintaxa: LEA r16, m16
Acţiune: r16 ← m16

34
Exemplul 4.6:

.radix 16
.model small
.stack 100h
.DATA
sir1 db 13,14,15,1,2,3
sir2 db 16,17,18,19
.code
start: mov ax,@dată ;Adresa segmentului de date
mov ds,ax ;se încarcă în DS
lea di,sir2 ;În DI se va află offset-ul
;şirului notat "sir2"(în acest caz 06),
;în memoria de date
mov al,[di+2] ;Transferă din a treia locaţie
;a acestui şir în AL

Observaţii:
 Pentru transferurile care implică segmentul de date vor fi folosite ca registre
destinaţie la instrucţiunea LEA numai registrele BX, SI şi DI şi nu va fi folosit
BP.
 Instrucţiunea LEA rd, adresa_efectivă poate fi inlocuită în majoritatea
cazurilor cu instrucţiunea MOV rd,OFFSET adresa_efectivă, lăsând astfel
asamblorul să calculeze şi să încarce valoarea corectă a adresei efective în
registrul dorit. Sunt situaţii însă când instrucţiunea LEA este mai eficientă (de
exemplu la lucrul cu directive de grupare).

P 4.7. Să se scrie un program care să inverseze al treilea element al primului


şir declarat ca în exemplul 4.6 cu elementul al patrulea al celui de-al doilea şir. Se va
folosi instrucţiunea LEA.

Lucrarea de laborator nr. 5


Operaţii aritmetice

35
Există următoarele tipuri de operaţii efectuate de ALU:
 aritmetice;
 logice;
 deplasări şi rotaţii;

Toate acestea afectează corespunzător unul sau mai mulţi din următorii
indicatori de condiţii:
 CF (Carry Flag) - indicator de transport -reflectă transportul în exterior al bitului
cel mai semnificativ al rezultatului operaţiilor aritmetice.Acest indicator poate fi
folosit în cazul adunării sau scăderii numerelor pe mai mulţi octeţi, semnificind în
primul caz transport la adunare şi în al doilea caz împrumut la scădere. Indicatorul
CF nu este modificat de instrucţiuni de incrementare şi decrementare.
 PF (Parity Flag) -indicator de paritate - este poziţionat pe 1 dacă rezultatul are un
număr par de biţi 1.
 AF (Auxiliary Carry Flag) - indicator de transport auxiliar - este poziţionat în 1
dacă a fost transport de la nivelul inferior la nivelul superior al octetului
rezultatului (de la bitul 3 la bitul 4). Acest indicator se foloseşte în programele de
calcule în aritmetică zecimală.
 ZF (Zero Flag) - indicatorul de zero - este poziţionat în 1 dacă rezultatul operaţiei
a fost zero.
 SF (Sign) indicatorul de semn - este poziţionat în 1 dacă cel mai semnificativ bit
al rezultatului (MSB) este 1, adică dacă în reprezentarea numerelor în
complement faţă de 2 rezultatul este negativ.
 OF (Overflow Flag) - Indicator de depăşire aritmetică (a gamei de valori posibil
de reprezentat) - este poziţionat în 1 dacă dimensiunea rezultatului depăşeşte
capacitatea locaţiei de destinaţie şi a fost pierdut un bit (la valorile cu semn se
alterează semnul).

5.1 Reprezentarea în complement faţă de 2


Toate structurile algebrice presupun existenţa unui element simetric faţă de
operaţia de adunare, definit prin relatia:

număr+simetric =0

În notaţia zecimala obisnuita, avem de exemplu:

 1 are simetric pe –1 deoarece suma lor da 0


 2 are simetric pe –2 deoarece suma lor da 0
 etc.

În binar se poate face o notaţie fără a specifică separat semnul, dacă se


consideră cuvinte de o lungime fixa, L. Astfel, de exemplu dacă L=4, putem spune ca
1 are ca simetric numărul binar 1111=F, deoarece
1+F= 0001+1111=0000 plus un transport (care însă nu mai încape în numărul
de L=4 biţi).
Similar:
 0010 are ca simetric 1110 deoarece suma lor dă 0000. Deci E = -2
 0011 are ca simetric 1101 deoarece suma lor dă 0000. Deci D = -3
36
 0100 are ca simetric 1100 deoarece suma lor dă 0000. Deci C = -4
 0101 are ca simetric 1011 deoarece suma lor dă 0000. Deci B = -5
 etc.
Dacă L=8, putem spune ca 1 are ca simetric numărul binar 1111.1111=FF,
deoarece
1+FF= 0000.0001+1111.1111=0000.0000 plus un transport (care însă nu mai
incape în numărul de L=8 biţi).
Similar:
 0000.0010 are ca simetric 1111.1110 deoarece suma lor dă 0000.0000.
Deci FE = -2
 0000.0011 are ca simetric 1111.1101 deoarece suma lor dă 0000.0000.
Deci FD = -3
 0000.0100 are ca simetric 1111.1100 deoarece suma lor dă 0000.0000.
Deci FC = -4
 0000.0101 are ca simetric 1111.1011 deoarece suma lor dă 0000.0000.
Deci FB = -5
 etc.

Această reprezentare se numeşte reprezentarea în complement faţă de 2,


deoarece numărul simetric este egal cu cel iniţial scăzut din 2L.
Se poate arata că complementul faţă de 2 se obţine prin negarea biţilor
numărului şi adunarea unui 1.
În limbaj de asamblare, complementul faţă de 2 al unui număr (negativul
acelui număr) se obţine cu instrucţiunea NEG (vezi mai jos descrierea instrucţiunii).

5.2 Prezentarea instrucţiunilor aritmetice

ADD dst,src - Adunare


Acţiune: dst = dst + src;
Operanzi: dst: r8, r16, r32, m8, m16, m32
src: r8, r16, r32, m8, m16, m32, n, nn, nnnn

ADC dst,src - Adunare cu carry (transport)


Acţiune: dst = dst + src +CF;
Operanzi: dst: r8, r16, r32, m8, m16, m32
src: r8, r16, r32, m8, m16, m32, n, nn, nnnn

INC dst -Incrementare


Acţiune: dst = dst + 1
Operand: r8, r16, r32, m8, m16, m32

SUB dst,src - Scădere


Acţiune: dst = dst - src;
Operanzi: dst: r8, r16, r32, m8, m16, m32
src: r8, r16, r32, m8, m16, m32, n, nn, nnnn

Exemplul 5.1:
37
mov al,33h;Desc ăzutul
mov bl,44h;este mai mic decat scăzătorul
sub al,bl ;rezultatul în AL va fi negativ,0EFh
;şi va apare şi CARRY

SBB dst,src - Scădere cu borrow (împrumut)


Acţiune: dst = dst - src - CF;
Operanzi: dst: r8, r16, r32, m8, m16, m32
src: r8, r16, r32, m8, m16, m32, n, nn, nnnn

Exemplul 5.2:

mov al,33
mov bl,44
sub al,bl ;La această scădere apare împrumut
sbb cl,al ;Acesta e luat în consideraţie aici

DEC dst -Decrementare


Acţiune: dst = dst + 1
Operand: r8, r16, r32, m8, m16, m32
NEG dst -Negare aritmetica
Acţiune: dst = - dst ( se obţine complementul faţă de doi)
Operand: r8, r16, r32, m8, m16, m32
Descriere: Instrucţiunea NEG genereaza complementul faţă de 2 al
opernadului adică numărul respectiv cu semn schimbat. CF este setat automat, cu
excepţia cazului când Operandul este 0.

Exemplul 5.3:

mov al,0EFh;In complement fata de 2 este negativ


neg al ;Se schimba semnul si rezulta 11

NOT dst -Complementare faţă de 1.


Acţiune: dst ← 0FFh - dst ; pentru Operand de 8 biţi
dst ← 0FFFFh - dst ; pentru Operand de 16 biţi
dst ← 0FFFFFFFFh - dst ; pentru Operand de 32 biţi
Operand: r8, r16, r32, m8, m16, m32
Descriere: Instrucţiunea NOT inversează operandul; orice 1 devine 0 şi
viceversa. Nu sunt afectaţi indicatorii de condiţii.

CMP dst,src -Comparaţie aritmetică (prin scădere)


Acţiune: dst-src;fără generare rezultat - modifica doar indicatorii de
condiţii.
Operanzi: dst: r8, r16, r32, m8, m16, m32
src: r8, r16, r32, m8, m16, m32, n, nn, nnnn

MUL src - Înmulţirea fără semn lui AL, AX sau EAX cu un număr.

38
Acţiunea depinde de marimea Operandului src, luând următoarele
forme:

- src de 8 biţi: AX ← AL * src8; src: r8,m8


Dacă AH = 0 atunci CF ← 0; În celelalte cazuri CF ← 1 şi
OF ← CF

-src de 16 biţi: DX: AX ← AX * src16; src: r16,m16


Dacă DX = 0 atunci CF ← 0; În celelalte cazuri CF ← 1 şi
OF ← CF

- src de 32 biţi: EDX: EAX ← EAX * src32; src: r32,m32


Dacă EDX = 0 atunci CF ← 0; În celelalte cazuri CF ← 1 şi
OF ← CF

Exemplul 5.4:

mul bl ; Se inmulteste AL cu BL (8 biţi) iar


;rezultatul este in AX
mul cx ; Se inmulteste AX cu CX iar rezultatul
;este în DX (octeţii superiori) şi AX
;(ocţetii inferiori)

IMUL (dst,)src - Înmulţirea cu semn a lui AL, AX, EAX sau a altui registru
cu un număr.
Acţiunea depinde de Operandul destinaţie şi de mărimea Operandului src.
În cazul în care destinatia este acumulatorul AL,AX sau EAX se obţine
rezultatul complet, chiar dacă apare flagul Overflow, deoarece rezultatul va fi
memorat cu precizie dublă faţă de a operanzilor:

-src de 8 biţi: AX ← AL * src8; src: r8,m8


Dacă AH = 0 sau AH = FF atunci CF ← 0; În celelalte cazuri CF ← 1 şi
OF ← CF

- src de 16 biţi: DX: AX ← AX * src16; src: r16,m16


Dacă DX = 0 sau AH = FF atunci CF ← 0; În celelalte cazuri CF ← 1 şi
OF ← CF

- src de 32 biţi: EDX: EAX ← EAX * src32; src: r32,m32


Dacă EDX = 0 sau AH = FF atunci CF ← 0; În celelalte cazuri CF ← 1 şi
OF ← CF

Spre deosebire de înmulţirea numerelor fără semn (cu instrucţiunea MUL), în


cazul instrucţiunii IMUL este posibil ca deînmulţitul să fie şi alt registru în afară de
acumulator, iar sursa poate să fie o valoare numerică imediată. În acest caz însă, dacă
rezultatul are mai mulţi biţi decât registrul care conţine deînmulţitul, se pierd biţii
care depaşesc lărgimea acestuia. Acţiunea este următoarea:

- IMUL dst,src
dst ← dst * src; (dst= r16; src=r16/m16 /imm8/imm16)

39
Dacă DX = 0 sau AH = FF atunci CF ← 0; În celelalte cazuri CF ← 1 şi
OF ← CF
Dacă src este de tip imm8, acesta se extinde cu semn până la lungimea dst.

- IMUL dst,src
dst ← dst * src; (dst= r32; src=r32/m32 /imm8/imm32)
Dacă DX = 0 sau AH = FF atunci CF ← 0; În celelalte cazuri CF ← 1 şi
OF ← CF
Dacă src este de tip imm8, acesta se extinde cu semn până la lungimea dst

DIV src - Împărţirea fără semn a acumulatorului cu un registru sau locaţie


de memorie.
Acţiune: - dacă src este de 8 biţi:
AL ← AX/src8; (câtul împărţirii)
AL ← AX % src8 (restul împărţirii)
src: r8,m8.
- dacă src este de 16 biţi:
AX ← DX : AX/srcl6; (câtul împărţirii)
DX ← DX : AX % srcl6 (restul împărţirii)
src: r16,m16.
- dacă src este de 32 biţi:
EAX ← EDX : EAX/srcl6; (câtul împărţirii)
EDX ← EDX : EAX % srcl6 (restul împărţirii)
src: r32,m32.
Observaţii: Dacă rezultatul (catul) nu incape în registrul destinaţie AL, AX
respectiv EAX, sau impartitorul este 0, se genereaza Întrerupere 0 (DE - Divide
Error) şi se sare automat din program. De aceea trebuie facuta o evaluare prealabila a
domeniului de valori ale rezultatului şi trebuie folosit un registru destinaţie
corespunzător.
Dacă câtul este subunitar, el este ajustat la 0.
Indicatorii de condiţii sunt nedefiniţi.

Exemplul 5.5:

mov ax, 0F0h


mov cl,10
div cl; Se imparte AX la CL(8biţi). Câtul este in AL iar restul in AH

Exemplul 5.6:

mov ax, 0F0h


mov cl,5
div cl ; Se imparte AX la CL (8biţi). Câtul este mai
;mare decat decât FF si apare eroare
;(intreruperea 0).

Corect ar fi fost:
mov ax,0F0h
mov cl,5

40
mov dx,0 ; Se pregateste ca deimpartitul sa fie in
;perechea DX:AX
mov ch,0 ; Se pregateste ca impartitorul sa fie in CX
div cx ; Impartire pe 16 biţi, deci câtul va fi in
;AX iar restul in DX

IDIV src - Împărţirea cu semn a acumulatorului cu un registru sau locaţie de


memorie.
Acţiune: - dacă src este de 8 biţi:
AL ← AX/src8; (câtul împărţirii, cu semn)
AL ← AX % src8 (restul împărţirii,cu semn)
src: r8,m8.
- dacă src este de 16 biţi:
AX ← DX : AX/srcl6; (câtul împărţirii,cu semn)
DX ← DX : AX % srcl6 (restul împărţirii,cu semn)
src: r16,m16.
- dacă src este de 32 biţi:
EAX ← EDX : EAX/srcl6; (câtul împărţirii,cu semn)
EDX ← EDX : EAX % srcl6 (restul împărţirii,cu semn)
src: r32,m32.

Observaţie: Dacă rezultatul (câtul) nu încape în registrul destinaţie AL, AX


respectiv EAX, sau împărţitorul este 0, se generează Întreruperea 0 (DE - Divide
Error) şi se sare automat din program. De aceea trebuie facută o evaluare prealabilă a
domeniului de valori ale rezultatului şi trebuie folosit un registru destinaţie
corespunzător.
Dacă câtul este subunitar, el este ajustat la 0.
Semnul restului este acelaşi cu al împărţitorului.
Indicatorii de condiţii sunt nedefiniţi.

CBW - Conversie de la Byte (8 biţi) la Word (16 biţi) cu păstrare


semn. Acţiune: AL 7 = 0 => AH =0;
AL 7 = 1 => AH =0FF;

CWD - Conversie de la Word (16 biţi) la Dword (32 biţi) cu păstrare


semn. Acţiune: AX 15 = 0 => DX =0;
AL 15 = 1 => DX =0FFFF;

Modul de lucru

P 5.1 Să se scrie un program care să încarce constantele 11,10,33 şi 44 hexa în


AL, BX, CL, respectiv DL, constanta 99h în memorie la adresa indicată de BX, apoi
să adune conţinutul registrelor AL,CL şi DL ,să scadă rezultatul din memorie de la
adresa conţinută în BX şi să memoreze rezultatul final la adresa de memorie
următoare.
Indicaţii:
Când se transferă un număr de un octet cu memoria, el trebuie precedat de
prefixul “byte ptr”.

41
P 5.2 Acelaşi program ca la punctul 1, dar conţinutul registrelor va fi 1122,
10, 3344, 5566 iar în memorie [BX]=AABB.
Indicaţii:
Când se transferă un număr de doi octeţi cu memoria, şi octetul cel mai
semnificativ este 00 sau lipseşte, el trebuie precedat de prefixul “word ptr”. Dacă
octetul cel mai semnificativ este diferit de 00, prefixul respectiv poate fi omis, el
subinţelegându-se.
Constantele care încep cu o literă trebuie precedate de cifra 0. Dacă se şi
termină cu o literă trebuie urmate de sufixul H.
În final, în memorie începând de la adresa 10 trebuie să fie octeţii:
EF.10.EF.10.

P 5.3 Să se scrie un program care să încarce constantele 9, 19 şi 29 în AL, BL


respectiv CL Să se incrementeze conţinuturile acestor registre şi să se înmulţească
apoi între ele. Se va verifica rezultatul cu aplicaţia Calculator.

Indicaţii:
Atunci când deânmulţitul este (sau poate fi) de doi octeţi, înmulţirea trebuie
facuta cu un înmulţitor care ocupă un registru de 16 biţi, chiar dacă înmulţitorul este
de numai 8 biţi.
În final, în AX trebuie să fie rezultatul 2AA8.

P 5.4 Se vor încarca registrele în felul următor: BX=1122, DX=22 şi


CX=5566. Sa se înmulţească aceste registre între ele iar rezultatul să se trimită în
memorie la adresa 20h.
Indicaţii:
Algoritmul poate fi următorul:
11.22*55.66*22 = 05.B7.1D.8C*22 = 1D.8C*22+10000*05.B7*22 = C251.EC98
Conţinutul unora dintre registre va trebui salvat în memorie.

P 5.5 Sa se încarce în CX , BL şi DL numerele 6655, 44 respectiv 22 să se


împarta CX la BL , câtul fiind apoi înmulţit cu DL şi adunat cu restul.
Indicaţii:
 Conţinutul unora dintre registre va trebui salvat în memorie.
 Impărţirea va avea un rezultat mai mare de 8 biţi, deci trebuie ca deâmpărţitul
să fie format din DX şi AX. Pentru aceasta, DX va fi făcut 0 iar împărţitorul
va fi BX (cu BH=0).
 Adunarea finală trebuie făcută pe 4 octeţi, deci după ce se va face o prima
adunare pe 16 biţi pentru octeţii mai puţin semnificativi, se va anula un
registru şi se va aduna cu CARRY la cei 16 biţi mai semnificativi.

42
Lucrarea de laborator nr. 6
Operaţii logice, deplasări şi rotaţii

6.1. Operaţii logice

Operanzii în modul real sunt aceiaşi ca la operaţiile aritmetice obişnuite:


dst:r8,r16,r32,m8,m16,m32;
src:r8,r16,r32,m8,m16,m32,n,nn,nnnn.

NOT dst - Complementare faţă de 1 a fiecărui bit din Operandul


destinaţie, dstn .
Acţiune: dstn ←1-dstn .
Operanzi: dst.
Descriere: Instrucţiunea NOT inversează biţii Operandului; orice 1 devine
0 şi viceversa. S-a notat dstn bitul n al operandului destinaţie.

AND dst,src -SI logic pe bit.


Acţiune: dstn ←(srcn)SI (dstn).
Operanzi: dst,src.
Descriere: Un bit al rezultatului instrucţiunii AND este un 1 dacă ambii
biţi corespunzători ai operanzilor sunt 1; altminteri, bitul devine 0. S-a notat cu src n şi
dstn bitul n al operandului sursă, respectiv destinaţie. Rezultatul înlocuieşte primul
operand.

TEST dst,src -Testare (SI fără generare de rezultat).


Acţiune: (srcn)SI (dstn).
Operanzi: dst,src.
Descriere: Instrucţiunea TEST calculeaza “SI logic pe bit” între cei doi
operanzi. Un bit al rezultatului este 1 dacă ambii biţi corespunzători ai operanzilor
sunt 1; altminteri, bitul este 0. Rezultatul operaţiei este sters şi doar flagurile sunt
modificate. S-a notat cu srcn şi dstn bitul n al operandului sursă, respectiv destinaţie.

OR dst,src -SAU logic pe bit.


Acţiune: dstn ←(srcn)SAU (dstn).
Operanzi: dst,src.
Descriere: Instrucţiunea OR calculeaza SAU pe bit între cei doi operanzi
şi rezultatul este plasat în primul operand. Un bit al rezultatului este 0 dacă ambii biţi
corespunzători ai operanzilor sunt 0; altminteri, bitul este 1. Rezultatul înlocuieşte
primul operand.

XOR dst src -SAU EXCLUSIV logic pe bit.


Acţiune: dstn ←(srcn) XOR (dstn).
Operanzi: dst,src.
Descriere: Instrucţiunea XOR calculeaza SAU EXCLUSIV pe bit între cei
doi operanzi. Un bit al rezultatului este 1 dacă biţii corespunzători ai operanzilor sunt
43
diferiţi; bitul rezultatului este 0 dacă biţii corespunzători sunt identici. Rezultatul
înlocuieşte primul operand.

6.2. Deplasări şi rotaţii

SHL dst,[nr]-Deplasare logică spre stânga cu nr poziţii (numere fără semn).


Acţiune:
C MSB LSB
0

Operanzi: -dst;
-[nr]: 1, CL,imm8.
Descriere: Operandul src este înmulţit cu 2 de [nr] ori.
Exemple:
SHL al,1 -deplasează spre stânga AL cu 1 bit;
SHL al,cl -deplaseaza spre stânga AL cu un număr de biţi egal cu conţinutul
lui CL.

SHR dst,[nr]-Deplasare logică spre dreapta cu nr poziţii (numere fără


semn).
Acţiune:
MSB LSB C
0

Operanzi: -dst;
-[nr]: 1, CL,imm8.
Descriere: Operandul src este impartit cu 2 de [nr] ori.

SAL src,[nr]-Deplasare aritmetică spre stânga cu nr poziţii (numere cu


semn).

Acţiune:
C MSB LSB
0

Operanzi: -dst;
-[nr]: 1, CL,imm8.
Descriere: Operandul src cu semn este înmulţit cu 2 de [nr] ori.

SAR src,[nr]-Deplasare aritmetica spre dreapta cu nr pozitii (numere cu


semn)
Acţiune:
MSB LSB C

44
Operanzi: -dst.
-[nr]: 1, CL,imm8.
Descriere: Operandul src cu semn este împărţit cu 2 de [nr] ori.

ROL src,[nr]-Rotaţie prin Carry spre stânga cu [nr] poziţii


Acţiune:
C MSB LSB

Operanzi: -dst;
-[nr]: 1, CL,imm8.

ROR src,[nr]-Rotatie prin carry spre dreapta cu [nr] poziţii


Acţiune:
MSB LSB C

Operanzi: -dst;
-[nr]: 1, CL,imm8.

RCL src,[nr]-Rotatie cu carry spre stânga cu [nr] poziţii


Acţiune:
C MSB LSB

Operanzi: -dst;
-[nr]: 1, CL,imm8.

RCR src,[nr]-Rotatie cu carry spre dreapta cu [nr] pozitii


Acţiune:
MSB LSB C

Operanzi: -dst;
-[nr]: 1, CL,imm8.

Descriere: Fiecare instrucţiune de rotaţie deplasează biţii operandului de


registru sau memorie dat. Instrucţiunile de rotaţie spre stânga deplasează toti biţii
către poziţia cea mai semnificativă (catre MSB) ,exceptând bitul din poziţia cea mai
semnificativă, care este mutat în poziţia cea mai puţin semnificativa (LSB).
Instrucţiunile de rotaţie spre dreapta acţionează invers: biţii sunt deplasaţi către

45
poziţia cea mai puţin semnificativă iar bitul din poziţia cea mai puţin semnificativă
ajunge în poziţia cea mai semnificativă.
Pentru instrucţiunile RCL şi RCR, flagul CF este o parte a cantităţii rotite.
Instrucţiunea RCL deplasează flagul CF în bitul cel mai puţin semnificativ şi cel mai
semnificativ bit în flagul CF; instrucţiunea RCR deplaseaza flagul CF în bitul cel mai
semnificativ şi bitul cel mai puţin semnificativ în flagul CF. La instrucţiunile ROL şi
ROR, valoarea flagului CF nu este parte a rezultatului, dar flagul CF recepţionează o
copie a bitului care a fost deplasat de la un capăt la altul.
În modul real sau virtual 8086, rotaţia este repetata de un număr de ori indicat
de al doilea operand, care este unu sau conţinutul registrului CL.De la procesoare I-
386 în sus, operandul al doilea poate fi şi o constantă imediată.
Flagul OF este definit numai pentru forme cu o singura rotaţie ale
instrucţiunilor (al doilea operand este un 1). Este nedefinit în toate celelalte cazuri.
Pentru deplasări/rotiri spre stânga, bitul CF de după deplasare este “sau-exclusivat”
cu bitul rezultat de cel mai înalt ordin. Pentru deplasări/rotiri spre dreapta, cei doi biţi
cu cel mai înalt ordin ai rezultatului sunt “sau-exclusivaţi” spre a rezulta flagul OF.

Observaţie: Deşi microprocesoarele sub I-386 admit deplasarea numai cu un


bit sau cu numărul contiinut de CL, unele asambloare admit şi un operand numeric
mai mare de 1 ca al doilea operand. Astfel, în TASM sunt admise forme ca:

SHL BP,8
SHL DX,6
SHR AL,2
.
.
.
După asamblare şi linkeditare, în programul obiect apar însă în mod corect 8
instrucţiuni SHL BP,1 sau 6 instrucţiuni SHL DX,1 s.a.m.d.
Cu directiva .386 sunt admise direct şi deplasări cu imm8.

6.3. Operaţii aritmetice BCD (opţional, vezi Anexa 1)

AAA -Ajustare AL după adunare (BCD despachetat).

AAS -Ajustare AL după scădere (BCD despachetat).

DAA -Ajustare AL după adunare (BCD inpachetat).

DAS -Ajustare AL după scădere (BCD impachetat).

AAM -Ajustare AL după înmulţire.

AAD -Ajustare AL înainte de împărţire.

4.Modul de lucru

46
Iniţial, în partea de început a programelor următoare, registrele şi memoria
vor fi încărcate astfel: AX=1122h, Bx=10h, CX=3344h, DX=5566, [BX]=99AAh,
BP= 77h.

P 6.1 Să se scrie un program care să transforme în 0 biţii lui AX=0EEEEh cu


excepţia biţilor 0..3. Această operaţie va fi denumită în continuare “Mascare” a biţilor
4..15. Rezultatul mascării va fi memorat în DX iar AX va trebui să rămână la
valoarea iniţială.

P 6.2 Să se scrie un program care să transforme în 1 biţii lui AX=0EEEEh cu


excepţia biţior 4...7. Rezultatul acestei mascari va fi memorat în DX iar AX va trebui
să ramână la valoarea iniţială.

P 6.3 Să se scrie un program care să copieze biţii 2 şi 3 ai lui BL=0A6h în


aceleasi pozitii din CL=1Fh, lasind restul biţilor lui CL neschimbati.

P 6.4 Să se scrie un program care să încarce în 4 locaţii consecutive din


memorie, începând de la adresa 10h , cei 4 biţi inferiori ai lui DL=05 (bitul 0 în prima
locaţie, bitul 1 în a doua locaţie, ş.a.m.d.).

P 6.5 Să se scrie un program care să inverseze semioctetul superior al lui


BL=12h cu cel inferior al lui CH=56h, pastrând ordinea biţilor.

P 6.6 Să se scrie un program care să anuleze în CL=25h biţii care sunt identici
cu cei omologi din DH=55h.

P 6.7 Să se scrie un program care să seteze în CL=25h biţii care sunt identici
cu cei omologi din DH=55h.

P 6.8 Să se scrie un program care să înmulţească cu 320 conţinutul registrului


BP, folosind deplasări spre stânga. Această operaţie este necesară pentru calculul
adresei unui punct din memoria ecran în modul grafic 320 x 200 şi va fi folosit
frecvent în programele de afişare grafică. Rezultatul pentru BP=77h va trebui să fie
94C0h.
Indicaţii: Se va ţine seama că 320=256+64 adică 320 = 2 8 + 26 . Prin urmare,
se va face o copie a lui BP în alt registru apoi se vor deplasa spre stânga cele două
registre cu 8 respectiv cu 6 poziţii şi se vor aduna.

P 6.9 Se va scrie un program care să faca înmulţirea cu 640 a conţinutului


registrului BP folosind deplasări spre stânga. Aceasta operaţie este necesară pentru
calculul adresei unui punct din memoria ecran în modul grafic 640 x 480 şi se
foloseşte frecvent în programele de afişare grafica. Rezultatul pentru BP=33h va
trebui să fie 7F80h.

47
Lucrarea de laborator nr. 7
Instrucţiuni de salt

7.1 Instrucţiuni de salt necondiţionat

Mnemonic: JMP adr - salt necondiţionat


Acţiune : PC← adr
Salturile de acest tip pot fi absolute sau relative, cu adresa dată direct sau
conţinută într-un registru sau locaţie de memorie, în acelasi segment sau
intersegment, etc. Pentru lista completă a tipurilor de salt necondiţionat se poate
consulta Anexa 1 de la sfârşitul lucrării. Într-o primă instanţă se vor folosi numai
salturi simple, cu adresa specificată sub forma de etichetă, iar asamblorul şi
linkeditorul vor transpune automat argumentul saltului. În general numai în Modul
Protejat este nevoie de toate instrucţiunile prezentate în lista completă.

7.2 Instrucţiuni de salt condiţionat


Mnemonic: Jcc deplasament, unde cc reprezintă condiţia testată.
Acţiunea:
 Dacă condiţia este adevarata, PC←PC+deplasament (se execută saltul la noua
adresă).
 Dacă condiţia este falsă , PC←PC+n, unde n este numărul de octeţi ai
instrucţiunii de salt (aceasta este ignorată şi se continuă cu instrucţiunea
următoare).

Salturile condiţionate sunt salturi relative, deci adresa de salt este dată de
suma între conţinutul curent al PC şi deplasamentul specificat de instrucţiune.
Deplasamentul admis de unele asambloare este cu numai 8 biţi, astfel ca
operandul “adr” trebuie să difere de adresa curenta cu maxim +/- 128 octeţi.
Procesoarele de la I-386 în sus admit şi salturi relative cu depalasament pe 16
sau 32 de biţi, dar numai în interiorul aceluiaşi segment. Dacă se doreşte saltul în
afara segmentului, se va folosi instrucţiunea de salt relativ cu condiţia inversă şi după
ea o instrucţiune de salt necondiţionat intersegment.
În funcţie de indicatorii de condiţii testati de instrucţiunea de salt, există
următoarele tipuri de salturi condiţionate (cu variantele echivalente scrise în
paranteze).

JP adr (JPE adr) – Jump if Parity - salt condiţionat de paritate pară.


JNP adr (JPO adr) – Jump if Not Parity - salt condiţionat de paritate impară.

JO adr - Jump if Overflow- salt condiţionat de OF =1 - a fost depăşire.


JNO adr - Jump if Not Overflow- salt condiţionat de OF = 0 - nu a fost
depăşire .

JS adr – Jump if Sign bit- salt condiţionat de SF=1 - rezultatul a fost negativ.
JNS adr - Jump if No Sign bit - salt condiţionat de SF = 0 rezultatul a fost
pozitiv.

JE adr (JZ adr) – Jump if Equal (Jump if Zero flag) - salt condiţionat de
ZF=1 - egalitate la comparaţia anterioara.
48
JNE adr (JNZ adr) - Jump if Not Equal (Jump if No Zero flag) - salt
condiţionat de ZF=0 - inegalitate la comparaţia anterioară.

Pentru compararea numerelor cu semn (MSB dă semnul: 1 pentru negativ, 0


pentru pozitiv) se folosesc atributele Less şi Greater:

JL adr (JNGE adr) – Jump if Less (Jump if Not Greater or Equal) - salt
condiţionat de SF<>OF (SF xor OF = 1) - mai mic la comparaţia anterioară a unor
valori cu semn.
JLE adr (JNG adr) - Jump if Less or Equal (Jump if Not Greater) salt
condiţionat de ZF=1 sau SF<>OF - mai mic sau egal la comparăţia anterioară a
unor valori cu semn.

JG adr (JNLE adr) – Jump if Greater (Jump if Not Less or Equal) - salt
condiţionat de ZF=0 şi SF=OF - mai mare la comparaţia anterioară a unor valori cu
semn.
JGE adr (JNL adr) – Jump if Greater or Equal (Jump if Not Less) - salt
condiţionat de SF=OF - mai mare sau egal la comparaţia anterioară a unor valori cu
semn.

Pentru compararea numerelor fără semn se folosesc atributele Below şi


Above:

JB adr (JNAE adr , JC adr) – Jump if Below (Jump if Not Above or Equal) -
salt condiţionat de CF = 1 - mai mic la comparaţia anterioară a unor valori fără semn
sau transport la operaţia anterioară.
JBE adr (JNA adr) – Jump if Below or Equal (Jump if Not Above) - salt
condiţionat de CF=1 sau ZF=1 - mai mic sau egal la comparaţia anterioară a unor
valori fără semn.

JA adr (JNBE adr ) – Jump if Above ( Jump if Not Below or Equal) - salt
condiţionat de CF =ZF = 0 - mai mare la comparaţia anterioară a unor valori fără
semn.
JAE adr (JNB adr , JNC adr) – Jump if Above or Equal (Jump if Not
Below, Jump if Not Carry) - salt condiţionat de CF=0 - mai mare sau egal la
comparaţia anterioară a unor valori fără semn sau nu există transport la operaţia
anterioară.

JCXZ – (Jump if CX is Zero) - salt condiţionat de conţinutul lui CX = 0

7.3 Instrucţiuni de ciclare LOOP, LOOPcc

Pentru execuţia repetată a unui grup de instrucţiuni (ciclu) se pot folosi, în


afara instrucţiunilor de salt şi instrucţiunile specializate pentru ciclare LOOP şi
LOOPcc. Acestea folosesc implicit registrul contor CX, pe care îl decrementează
automat la fiecare execuţie şi, dacă acesta nu a ajuns la 0, execută saltul la adresa
specificată.

Mnemonic: LOOP rel8.

49
Acţiune: DEC CX; jump short if CX <> 0.
Se execută ciclul până când contorul CX ajunge la 0.

Mnemonic: LOOPE rel8 (ciclează atâta timp cât există egalitate).


Acţiune: DEC CX; jump short if count <> 0 and ZF=1.
Se execută ciclul până când contorul CX ajunge la 0, sau până când apare ZF (la o
comparaţie sau scădere cu operanzi egali).

Mnemonic: LOOPZ rel8 (ciclează atâta timp cât există egalitate).


Acţiune: DEC CX; jump short if count <> 0 and ZF=1.
Se execută ciclul până când contorul CX ajunge la 0, sau până când apare ZF (la o
comparaţie sau scădere cu operanzi egali).

Mnemonic: LOOPNE rel8 (ciclează atâta timp cât nu există egalitate).


Acţiune: DEC CX; jump short if count <> 0 and ZF=0.
Se execută ciclul până când contorul CX ajunge la 0, sau până când apare ZF (la o
comparaţie sau scădere cu operanzi diferiţi).

Mnemonic: LOOPNZ rel8 (ciclează atâta timp cât nu există egalitate).


Acţiune: DEC CX; jump short if count <> 0 and ZF=0.
Se execută ciclul până când contorul CX ajunge la 0, sau până când apare ZF (la o
comparaţie sau scădere cu operanzi diferiti).

Modul de lucru:

În continuare, dacă nu se specifică altfel, se va folosi pentru adresa efectivă


valoarea implicită 0.

P 7.1 Sa se încarce în primele 3 locaţii de memorie constantele 5566h, 3322h


şi 8899h şi să se ordoneze în ordine crescătoare conţinutul acestor locaţii din
memorie. Se va testa programul şi cu valorile 4444h, 6666h şi 2222h, respectiv
7777h, 3333h, 2222h.
P 7.2 Sa se încarce o zonă de memorie de 20h de octeţi cu constanta 33h.
P 7.3 Sa se încarce o zona de memorie de 20h de octeţi cu numere crescătoare
de un octet începând cu 5.
P 7.4 Sa se adune conţinutul celor 20 de locaţii de memorie încarcate de
programul anterior, iar rezultatul, pe 16 biţi, să se plaseze în memorie cu octetul cel
mai puţin semnificativ la adresa efectivă 21h, şi cel mai semnificativ la adresa 20h.
P 7.5 Să se încarce o zona de memorie de 20h de octeţi cu numere crescătoare
din 10h în 10h .
P 7.6 Să se încarce o zona de memorie de 20h de octeţi cu numere
descrescătoare din 10h în 10h începând cu 200h.
P 7.7 Să se gasească şi să se plaseze, la sfârşitul şirului, octetul maxim din
10h locaţii de memorie începând de la adresa 0.

50
Lucrarea de laborator nr. 8
Instrucţiuni de lucru cu şiruri

În multe aplicaţii este necesar să se transfere şiruri de date dintr-o zona de


memorie în alta. Desi acest lucru este posibil folosind instrucţiuni MOV şi adresări
adecvate la memorie, s-au prevazut şi instrucţiuni speciale în acest scop, care permit o
viteză superioară, fiind recomandate în majoritatea situaţiilor de acest gen.
Pentru aceste instrucţiuni s-au prevazut două registre index: SI şi DI - Source
Index, respectiv Destination Index. Aceste registre conţin adresele efective implicate
în transfer, şi se modifica automat, incrementandu-se sau decrementându-se, cu 1 , cu
2, sau cu 4, la fiecare instrucţiune de acest tip. Transferul se poate face pe 8 biţi, pe
16 biţi , sau pe 32 biţi (de la I-386 în sus - vezi Anexa 1). Sunt prezentate aici doar
transferuri pe 8 şi pe 16 biţi.
Şirul sursă are adresa efectivă conţinută în registrul index sursă SI şi se află în
segmentul de date (cu adresa de segment în DS).
Şirul destinaţie are adresa efectivă conţinută în registrul index destinaţie DI şi
se află în extrasegment (cu adresa de segment în ES).
Sensul parcurgerii şirurilor este dat de flagul DF - Direction Flag, fiind
crescător dacă DF=0 şi descrescător dacă DF=1.
La utilizarea repetată a unor astfel de instrucţiuni este recomandabilă folosirea
prefixului REP în loc de utilizarea unei bucle clasice.

8.1. Instrucţiunile LODSB, LODSW, STOSB, STOSW

Mnemonic: LODSB - Încarcă de la DS:SI în AL.


Acţiune: AL←[SI].
SI←SI +1 dacă DF=0, SI←SI-1 dacă DF=1.

Mnemonic: LODSW - Încarcă de la DS:SI în AX.


Acţiune: AL←[SI].
AH←[SI+1].
SI←SI +2 dacă DF=0, SI←SI-2 dacă DF=1.

Mnemonic: STOSB - Încarcă AL la ES:DI .


51
Acţiune: [SI]←AL.
SI←SI +1 dacă DF=0, SI←SI-1 dacă DF=1.

Mnemonic: STOSW - Încarcă AL la ES:DI.


Acţiune: [SI]←AL.
[SI+1]←AH.
SI←SI +2 dacă DF=0, SI←SI-2 dacă DF=1.

Pentru instrucţiunile de transfer LODSB şi LODSW, sursă este locaţia de


memorie cu adresa efectivă dată de registrul index sursă SI şi adresa de segment dată
de DS.
Pentru instrucţiunile de transfer STOSB şi STOSW, destinatia este locaţia de
memorie cu adresa efectivă dată de registrul index destinaţie DI şi adresa de segment
dată de ES.
În urma efectuării unei astfel de instrucţiuni, registrul index SI respectiv DI
se modifică în funcţie de starea flagului DF (de direcţie). Dacă DF este 0, registrul
index va fi incrementat cu 1 la LODSB şi STOSB şi cu 2 la LODSW şi STOSW.
Dacă DF este 1, registrul index va fi decrementat cu 1, respectiv cu 2.
Registrul general implicit este AL la transferul de un octet şi AX la transferul
de doi octeţi.

În exemplul următor se arată utilizarea unor astfel de instrucţiuni la copierea


unui bloc dintr-o zonă memorie în alta.

Exemplul 8.1:

.radix 16
.model small
.stack 100h
LungimeBloc equ 30
.DATA
BlocSursa db 40 dup(56)
BlocDest db 40 dup(?)

.code
start:
mov ax,seg BlocSursa ;Se putea folosi şi mov
;ax,@dată
mov ds,ax ;Segmentul sursă în DS
mov ax,seg BlocDest ;Necesar numai dacă
;blocurile sunt în
;segmente diferite
mov es,ax ;Segmentul destinaţie ES
cld ;direcţia în sensul
;creşterii adreselor
mov şi, offset BlocSursa ;AE a sursei în SI
mov di, offset BlocDest ;AE a destinaţiei în DI

52
mov cx, LungimeBloc ;Numărul de transferuri în CX
bucla:
lodsb ;Încarcă în AL un octet
stosb ;şi îl trimite la destinaţie
loop bucla ;Decrementează CX şi reia
;bucla până când CX devine 0
term:
jmp term
end start

Modul de lucru:

P 8.1 Sa se iniţializeze un bloc de 20h de cuvinte de forma 1122h în memorie


începând de la adresa 0 din segmentul de date şi să se copieze acest bloc într-o zona
începând de la adresa 60h din segmentul de date.
Observaţie: Reamintim ca după încărcarea lui DS, zona de memorie afişată în
fereastra DUMP va fi cea a segmentului ES. Pentru a vedea segmentul de date, se dă
comanda Dump din submeniul View, având activă fereastra CPU.

8.2 Instrucţiunile MOVSB şi MOVSW

Aceste instrucţiuni combină instrucţiunile LODSB şi STOSB, respectiv


LODSW şi STOSW, fără a afecta AL sau AX.

Mnemonic: MOVSB - Mută un octet de la adresa DS:SI la adresa ES:DI.


Acţiune: [DS]←[SI].
SI←SI +1 dacă DF=0, SI←SI-1 dacă DF=1.
DI←DI +1 dacă DF=0, DI←DI-1 dacă DF=1.

Mnemonic: MOVSW - Mută un cuvânt de la adresa DS:SI la adresa ES:DI


Acţiune: [DI]←[SI].
[DI+1]←[SI+1].
SI←SI +2 dacă DF=0, SI←SI-2 dacă DF=1.
DI←DI +2 dacă DF=0, DI←DI-2 dacă DF=1.

Exemplul 8.2:

În exemplul 8.1 se pot înlocui instrucţiunile LODSB şi LODSW cu MOVSB


ca în secvenţa:

.
.
.
bucla:
movsb ;Un octet din blocul sursă
;este trimis la destinaţie

53
loop bucla ;Decrementeaza CX şi sare la
;eticheta "Bucla" până când CX ajunge la 0

term:
jmp term
end start

Instrucţiunile MOVSB şi MOVSW admit prefix de repetare, REP. În felul


acesta instrucţiunea precedată de REP este executată de atâtea ori cât se află în
registrul CX (maxim 65536 ori).
Acealşi exemplu poate avea partea finală scrisă în felul următor:

Exemplul 8.3:
.
.
.
bucla:
REP movsb ;un număr de octeţi egal cu
;conţinutul registrului CX sunt citiţi
;din blocul sursă şi trimişi la destinaţie
term:
jmp term
end start

Modul de lucru
P 8.2 Sa se modifice programul de la punctul 6.1 pentru a folosi prefixul REP
şi instrucţiuni care să nu afecteze conţinutul lui AX .

8.3 Instrucţiunile pentru analiza conţinutului şirurilor, SCASB şi


SCASW

Mnemonic: SCASB - Compară conţinutul registrului AL cu conţinutul


locaţiei ES:DI şi poziţionează corespunzător flagurile.
Acţiune: AL - [ES:DI].

Mnemonic: SCASW - Compară conţinutul registrului AX cu conţinutul


locaţiei ES:DI şi ES:DI+1 şi poziţionează corespunzător flagurile.
Acţiune: AL - [ES:DI].
AH - [ES:DI+1].

Instrucţiunea SCASB compară octetul din locaţia de memorie cu adresa


ES:DI cu conţinutul lui AL şi poziţionează indicatorii de condiţii în funcţie de
rezultatul comparării. Registrul DI va fi incrementat cu 1.
Instrucţiunea SCASW compară cuvântul punctat de locaţia de memorie cu
adresa ES:DI (octetul inferior fiind la această adresă, iar cel superior la cea
următoare), cu conţinutul lui AX şi poziţionează indicatorii de condiţii în funcţie de
rezultatul comparării.Registrul DI va fi incrementat cu 2.
În conformitate cu regulile aritmeticii în complement faţă de 2 (numerele
negative au bitul cel mai semnificativ 1 iar scăderea cu rezultat negativ dă un
54
împrumut) , dacă numărul din memorie este mai mic decât cel din registru, indicatorii
C (transport la adunare şi împrumut la scădere) şi S (semn) se poziţionează în 1 .
Dacă numărul din memorie este mai mare decât cel din cu cel din registru, indicatorii
C şi S se poziţionează în 0. Dacă numărul din memorie este egal cu cel din registru,
se poziţionează în 1 indicatorul Z.

Exemplul 8.4
Programul prezentat în continuare efectuează următoarele:
- Declară un şir de 15 octeţi cu numere întregi crescătoare de la 1 la 5;
- Încarcă în AL constanta 04;
- Numără de câte ori apare această constantă în şir (compară pe rând
conţinutul lui AL cu fiecare din locaţiile şirului declarat şi incrementeaza BH de cate
ori este găsită constanta respectivă).

.radix 16
.model small
.stack 100h
.DATA
BlocSursa db 3 dup(1,2,3,4,5)
LB equ $-BlocSursa ;Asamblorul
;calculeaza lungimea blocului
.code
start:
mov ax,@dată
mov ds,ax
mov es,ax ;Încarcă în ES segmentul de
;date (pentru SCASB)
mov di, offset BlocSursa ;Încarcă în DI adresa
;şirului(Pentru SCASB)
mov cx, LB ;În CX lungimea şirului
mov al,4 ;Constanta de comparat
mov bh,0 ;Valoare iniţiala contor
bucla:
scasb ;Compară AL cu un octetul de
;la [ES:DI] din şir
jnz conti ;Daca nu e egalitate sare
inc bh ;Daca e 4, incrementeaza BH
conti:
loop bucla ;Reluare dacă nu s-a terminat

term:
jmp term
end start

Observaţii:
- Instrucţiunea MOV DS,AX nu este necesară decât pentru a putea vizualiza
în TD şirul declarat în memorie (când fereastra CPU este activată, cu View-> Dump).
Totuşi, dacă nu se introduce aceasta instrucţiune, prima instrucţiune din buclă va
trebui scrisa în forma MOV BL,ES:[DI]pentru a se citi din segmentul de date.

55
-Nici instrucţiunea de încărcare în BL a octetului ce se compara nu este în
mod normal necesară (dacă o folosim, s-ar putea face comparaţia fără SCASB). Aici
ea a fost introdusă în scop didactic, pentru a putea vizualiza în fiecare moment
termenii de comparat.
-Simbolul LB a fost introdus pentru a putea calcula automat lungimea
blocului. Simbolul $ în limbaj de asamblare desemnează adresa curentă.
-Dacă era cunoscută lungimea blocului, ea se putea declara explicit (de
exemplu LB equ 0F).

Modul de lucru
P 8.3 Se va rula pas cu pas programul din exemplul 6.3 şi se va observa la
fiecare comparaţie eventuala schimbare a indicatorilor de condiţii
P 8.4 Se va modifica programul de mai sus pentru a introduce un şir de cel
puţin 20 de caratere oarecare şi a contoriza în BH numărul de apariţii ale caracterului
'a'.
Indicaţie: Caracterele sau şirurile de caractere se scriu între apstroafe, de
exemplu: 'ghafs3yDGfa'.
P 8.5 Se va modifica programul de mai sus pentru a contoriza în BH numărul
de apariţii ale unui subşirului 'fa' în şirul 'ghfafasfasfahsyfhhhsaad'.

Indicaţii:
- În final, va trebui să avem BH=4;
- Se va folosi instrucţiunea de comparaţie SCASW, deci în AX va trebui
incărcat subşirul 'af', (caracterele s-au inversat conform convenţiei "little-endian"- v.
lucrarea de laborator 3);
- Instrucţiunea SCASW va incrementa DI cu 2, deci s-ar putea pierde subşirul
care începe de la o pozitie pară (caracterele 8 şi 9). Pentru a se cauta din unu în unu,
imediat înainte de ultima instrucţiune a buclei se va decrementa DI cu 1, pentru a se
compensa saltul de 2 al DI.

8.4. Instrucţiunile de comparare şiruri CMPSB şi CMPSW

Mnemonic: CMPSB - Compară conţinutul locaţiei DS:SI cu continutul


locaţiei ES:DI şi poziţioneaza corespunzător flagurile.
Acţiune: [DS:SI] - [ES:DI]
SI←SI +1 dacă DF=0, SI←SI-1 dacă DF=1
DI←DI +1 dacă DF=0, DI←DI-1 dacă DF=1

Mnemonic: CMPSW - Compară conţinutul locaţiilor DS:SI şi DS:SI+1


cu conţinutul locaţiilor ES:DI şi ES:DI+1 şi poziţionează corespunzător flagurile.
Acţiune: [DS:SI] - [ES:DI]
[DS:SI+1] - [ES:DI+1]
SI←SI +2 dacă DF=0, SI←SI-2 dacă DF=1
DI←DI +2 dacă DF=0, DI←DI-2 dacă DF=1

Pentru instrucţiunea de comparaţie CMPSB primul operand este locaţia de


memorie cu adresa efectivă dată de registrul index sursă SI şi adresa de segment dată
de DS iar al doilea operand este locaţia de memorie cu adresa efectivă dată de
registrul index destinaţie DI şi adresa de segment dată de ES.

56
Pentru instrucţiunea de comparaţie CMPSW primul operand este dat de
locaţiile de memorie cu adresele DS:SI (octetul inferior) şi DS:SI+1 (octetul superior)
iar al doilea operand este dat de locaţiile de memorie cu adresele ES:DI (octetul
inferior) şi ES:DI+1 (octetul superior).
În urma efectuării unei astfel de instrucţiuni, registrele index SI respectiv DI
se modifica în funcţie de starea flagului DF (de direcţie). Dacă DF este 0, registrele
index vor fi incrementate cu 1 la CMPSB şi cu 2 la CMPSW. Dacă DF este 1,
registrele index vor fi decrementate cu 1, respectiv cu 2.
În exemplul următor se arată utilizarea unor astfel de instrucţiuni la
compararea a două zone de memorie. Programul numară în BH cazurile de
coincidenţă a unui caracter dintr-un şir cu caracterul din aceeaşi poziţie din al doilea
şir.
Exemplul 8.5

.radix 16
.model small
.stack 100h
.DATA
Sir1 db 'ghfafasfasfahsyfhhhsaad'
LB equ $-Sir1 ;Lungimea este dată de şirul 1
Sir2 db 'ahgfasgfasjkhajhasdjgdd'
.code
start:
mov ax,@dată
mov ds,ax ;Încarcă în DS segmentul de date
mov es,ax ;Încarcă în ES segmentul de date
mov şi, offset Sir1;Încarcă în SI adresa şirului 1
mov di, offset Sir2;Încarcă în DI adresa şirului 2
mov cx,LB ;Contorul de comparaţii în CX

bucla:
mov dl,[si] ;Aduce în DL octetul din şirul 1
mov dh,[di] ;şi în DH octetul din şirul 2
;(instrucţiuni în scop didactic,
permit vizualizarea elementelor)
cmpsb ;Compară AL cu octetul respectiv
jnz b1 ;Dacă nu este egalitate, se sare
inc bh ;Dacă s-a gasit egalitate, se
;incrementează BH
b1: loop bucla ;Reluare dacă nu s-a terminat
;şirul 1
term:
jmp term
end start
Modul de lucru

P 8.6 Se va rula pas cu pas programul din exemplul 6.4 şi se va urmări cum se
modifica registrele şi indicatorii de condiţii la fiecare comparaţie.
P 8.7 Se va modifica programul anterior introducandu-se două şiruri de
caractere numerice: '6512631827961792' şi '7531790734264725'. În BH se va
contoriza de câte ori cifrele omoloage coincid, în DL de câte ori cifra din primul şir
57
este mai mică decât cea din al doilea şir, iar în DH de câte ori cifra din primul şir este
mai mare decât cea din al doilea şir.

8.5 Prefixele REPE, REPZ, REPNE şi REPNZ

Instrucţiunile de comparaţie SCASB, SCASW, CMPSB şi CMPSW pot fi


precedate de prefixele REPE ( echivalent cu REPZ) şi REPNE (echivalent cu
REPNZ) care cer procesorului să repete instrucţiunea pe care o preced până când CX
devine 0 (prin decrementare automata), sau până când este gasită relaţia de ordine
specificată de prefixul respectiv.
Astfel, pentru:
REPE şi REPZ - repetă atât timp cât termenii comparaţiei sunt egali (până
când apare o diferenţă);
REPNE şi REPNZ- repetă atâta timp cât termenii comparaţiei nu sunt egali
(până când apare o situaţie de egalitate).

Modul de lucru

Se vor folosi prefixe de repetare pentru următoarele programe:


P 8.8 Să se scrie un program care să indice în BH poziţia (numărul de ordine)
în şirul 'ABCDEFGHIJKL' al caracterului 'E'.
P 8.9 Să se scrie un program care să indice în BH numărul de ordine al
primelor elemente egale în şirurile: '123456789' şi '987654321'.
P 8.10 Să se scrie un program care să indice în BH numărul de ordine al
primelor elemente omoloage diferite din şirurile '112233445566' şi 112244335566'.

Lucrarea de laborator nr. 9


Funcţii sistem (INT 21h)

9.1 Utilizarea întreruperilor software

Anumite acţiuni standard pe care trebuie să le execute un program pot fi


realizate mai simplu folosind întreruperile software şi apelul funcţiilor sistem, BIOS
sau BDOS. Acestea sunt colecţii de rutine de largă utilitate existente în sistemul de
operare şi în firmware-ul computerului şi care pot fi apelate de orice program.
Cele mai utilizate rutine ale sistemului de operare sunt cele apelate prin
intermediul întreruperii 21H. Aceasta se realizează cu instrucţiunea INT 21H, după ce
în prealabil au fost încarcate unele registre cu parametrii specifici.
De exemplu, afişarea unui şir de caractere pe ecran se poate face ca în
programul următor:
58
Exemplul 9.1:

.radix 16
.model small
.stack 100h

.DATA
Sir1 db 'abcdefghij ABC...$'

.code
start:
mov ax,seg Sir1 ;Adresa segmentului de date
;unde se află şirul
mov ds,ax ;se încarcă în DS
mov dx, offset sir1 ;Se va apela funcţia sistem 09
;care necesita adresa efectivă
;a şirului în DX
mov ah,09 ;Codul funcţiei sistem în AH
int 21 ;Se cheamă întreruperea pentru
;funcţii sistem

;Ieşirea catre sistemul de operare


mov ah,4c ;se face cu funcţia 4C
;al carei cod se încarcă în AH
int 21 ;Se cheamă întreruperea pentru
;funcţii sistem
end start

Observaţii:
- Şirul de caractere trebuie să fie scris între semne apostrof şi, pentru funcţia
09, trebuie să se termine cu caracterul $ (după cum se va arăta mai jos).
- În locul instrucţiunii mov ax,seg Sir1 se putea folosi aici şi
instrucţiunea mov ax,@data. Dacă însă erau mai multe şiruri, în segmente
diferite, era necesară instrucţiunea din exemplu.

9.2 Funcţii sistem de intrare şi ieşire

Funcţiile sistem sunt apelate prin execuţia întreruperii 21H, cu anumite valori
în registre.

Dintre acestea, funcţiile de intrare de la tastatura sunt:

01H Intrare caracter de la keyboard.


06H Intrare/Ieşire caracter de la keyboard/display.
07H Intrare caracter nefiltrat de la keyboard fără ecou.

59
08H Intare caracter de la keyboard fără ecou.
0AH Intrare de la keyboard în buffer.
3FH Intrare de la dispozitiv sau din fişier.

Funcţiile de ieşire la display sunt:

02H Ieşire caracter la display.


09H Ieşire şir la display.
40H Scriere în dispozitiv de ieşire sau fişier.

În afara de acestea mai există şi funcţii de lucru cu fişierele şi cu discul, cu


memoria, etc prezentate în Anexa 3.
O funcţie larg folosită este funcţia 4Ch care permite ieşirea din program catre
sistemul de operare.

01H FUNCTION- Citire caracter de la keyboard cu ecou (afişare


automată pe ecran)
Registre:
AH = 01H

Ieşire în registre:
AL = Caracterul citit
În caz că este un caracter cu cod extins, în AL se va obţine 0 şi va fi necesar
să fie apelată funcţia din nou pentru a se obţine codul extins.

Exemplul 9.2:
.
.
;Aici se va citi un caracter de la keyboard
MOV AH,01H; Funcţia de citire a unui caracter
INT 21 H
.
.

07H FUNCTION- Citire caracter nefiltrat de la keyboard fără ecou


Registre:
AH = 07H

Ieşire în registre:
AL = Caracterul citit.
În caz că este un caracter cu cod extins, în AL se va obţine 0 şi va fi necesar
să fie apelată funcţia din nou pentru a se obţine codul extins.

Exemplul 9.3:
.
.
MOV AH,07H
INT 21 H
.

60
.
Observaţie: Funcţia 07h nu testează caracterul, şi nu sesizează de exemplu
Ctrl+C, astfel că la redirectarea spre un fişier nu este detectat caracterul de sfârşit de
fişier, şi se continuă scrierea în fişierul imediat următor. Pentru sesizarea Ctrl-C se
poate folosi în loc funcţia 08h, care face filtrarea şi este similara cu 07h în rest.

FUNCTION 0AH- Citire de la keyboard în buffer


Registre:
AH = 0AH.
DS:DX = Adresa zonei unde se vor memora caracterele şi în care structura
datelor va fi următoarea:
BYTE 0 = Numărul total de caractere care urmează să fie citite;
BYTE 1 = Numărul de caractere citite până la un moment dat.
De la BYTE 2 până la [BYTE 0] + 2 = caracterele citite
Caracterele vor fi memorate începând cu octetul al treilea al zonei specificate.
Terminarea introducerii se face automat când s-a citit un număr de caractere egal cu
cel specificat în primul octet (moment în care difuzorul va genera un beep) sau când
se apasă tasta ENTER.

3FH FUNCTION – Citire din dispozitiv sau fişier


Registre:
AH = 3FH;
BX = Numărul asignat dispozitivului;
CX = Numărul de octeţi care trebuie citit;
DS:DX = Adresa zonei în care se va face memorarea.

Ieşiri în registre:
CF = 0 nu au fost erori iar AX = numărul de octeţi cititi;
CF = 1 dacă au existat erori iar AX conţine codul erorii.

02H FUNCTION - Afişare caracter


Registre:
AH = 02H;
DL = Codul hexa al caracterului de afişat.

Exemplul 9.4:
;Afişează caracterul '1'
MOV AH, 02
MOV DL,31h ; Caracterul '1' are codul ASCII 31H
INT 21h

09H FUNCTION – Afişare şir de caractere


Registre:
AH = 09H;
DS:DX = Adresa de început a şirului de caractere.

Funcţia afişează caracterele unul cite unul până intilneste caracterul $ care
este interpretat ca sfârşit de şir.

61
În locul acestei funcţii se recomandă utilizarea funcţiei 40H.

40H FUNCTION – Scriere în dispozitiv sau fişier


Registre:
AH = 40H;
BX = Numărul dispozitivului ( 1 pentru display);
CX = Numărul de octeţi de scris;
DS:DX = Adresa de început a şirului de scris.

Ieşiri în registre:
CF = 0 dacă nu au fost erori;
AX = Numărul de octeţi scrişi;
CF = 1 dacă au apărut erori;
AX = codul de eroare.
4CH FUNCTION – Ieşire către sistemul de operare
Registre:
AH = 4CH;

Ieşiri în registre:
AL = codul de terminare;

Modul de lucru:

Se recomandă ca la programele următoare ieşirea sa se faca cu funcţia 4Ch, ca


în exemplul 9.1. Rularea se poate face direct, in care caz revenirea in Windows se
face cu Alt+Tab sau cu tasta "Windows" (cea dintre Ctrl si Alt).
Se poate face rularea si prin TD, eventual pas cu pas.

P 9.1 Se va scrie un program care afişează la ecran caracterele având codurile


ASCII cuprinse între 30h şi 80h.
Indicaţii: Se va folosi funcţia 02.

P 9.2 Se va scrie un program care să afişeze un şir de caractere la ecran.


Indicaţii: Şirurile de caractere se scriu între semne apostrof, iar în interiorul
unui şir apostroful se dubleaza (de exemplu într'adevăr se va scrie ca şir sub
forma 'într''adevăr'). Pentru folosirea funcţiei 09h şirul trebuie să se termine
cu caracterul $.

P 9.3 Program care să afişeze două şiruri de caractere pe două rânduri.


Indicaţii: Pentru a putea trece la un nou rând pe ecran, trebuie trimise către
acesta caracterele 0Dh (Carriage Return - aducere la începutul rândului) şi 0Ah (Line
Feed - avans cu un rând mai jos pe ecran).

P 9.4 Se va scrie un program care să citească de la tastatură caractere şi să le


afişeze cu ecou la ecran. Dacă se apasa tasta ENTER (care generează caracterul
Carriage Return -ODh), se va afişa mesajul 'Citire tastatura incheiata.' (mesajele sunt
fără diacritice).
Indicaţii: Se va folosi funcţia 01, care va afişa automat caracterul tastat;
programul îl va afişa din nou , de exemplu cu funcţia 02, astfel că fiecare caracter va
apărea pe ecran dublat - cu ecou.

62
P 9.5 Se va modifica programul precedent pentru afişare fără ecou.

P 9.6 Se va scrie un program care să citească de la tastatură caractere şi să le


afişeze cu majuscule la ecran. Se va testa varianta cu ecou şi cea fără ecou.
Indicaţii: Codul ASCII pentru majuscule se obţine scăzând 20h din codul
curent.

P 9.7 Se va scrie un program care să citeasca într-un buffer un şir de caractere


(cu funcţia 0Ah) şi să le afişeze (cu funcţia 09h) pe linia următoare atunci când se
apasă Enter.

P 9.8 Se va scrie un program care afişează pe ecran textul:

"Care din următoarele registre folosite la adresare indirectă, implică segmentul de


date?
1. BX
2. BP
3. SI
4. DI"

şi asteapta un caracter (1..4) de la tastatură. Dacă răspunsul este corect să se afişeze


textul: "Corect", iar dacă este greşit să afişeze textul: "Gresit!! Este BX sau SI!"

Lucrarea de laborator nr. 10


Afişarea în mod grafic

10.1 Utilizarea întreruperii 10h

Plăcile grafice au o zonă tampon în memoria RAM a cărei copie se regăseşte


în ecran. In modul grafic, această zonă începe in general la adresa 0A000H (vezi şi
Anexa 2 pentru diverse moduri grafice). Orice scriere în memorie în această zonă se
va reflecta asupra ecranului în funcţie de modul de lucru ales pentru placa grafică.
Stabilirea atributelor ecranului se poate face cu întreruperea INT 10 H, care
oferă mai multe servicii aflate în BIOS în funcţie de conţinutul lui AH. Menţionăm în
continuare unele dintre acestea, restul funcţiilor fiind prezentat în Anexa2 :

Funcţia 0: Stabilire mod de lucru


AH = 0;
AL = Identificator de mod.
Ex: Pentru AL = 10 H modul 640x480x 16 culori;
Pentru AL = 13 H modul 320x200x256 culori.

63
Următoarea secvenţă va trece ecranul în modul 13H:

Exemplul 10.1:
;Mod video 320x200
mov ah,0
mov al,13h
int 10h

Funcţia 06: Defilare ecran


AH=06h;
AL=Număr de rânduri cu care se face defilarea. Pentru AL=0 se face
ştergerea ecranului.
BH = Atributele liniilor inserate

Următoarea secvenţă va face stergerea ecranului:

Exemplul 10.2:
sterge: ;Sterge ecran
mov ah,06h
mov al,0
int 10h

Funcţia 0CH: Afisare punct


AH= 0CH;
AL= numărul culorii;
CX= coordonata x (x=0 în extrema stânga a ecranului);
DX= coordonata y (y=0 în extrema superioară a ecranului).

Observaţie: Funcţia 0CH este lentă şi nu se recomandă pentru imagini cu un


număr mare de puncte.
Următoarea secvenţa afişează un punct la coordonatele aflate în CX şi DX, cu
culoarea dată de AL:

Exemplul 10.3:

afiş: ;Afişează un punct la x=CX, y=DX şi


;culoare=AL
mov ah,0Ch ;funcţia 0Ch
int 10h ;cheamă funcţia bios

Următoarea secvenţă afişează o linie orizontală , la y = DX din puncte cu


culori crescătoare.

Exemplul 10.4:

linie:
mov ah,0Ch ;funcţia 0Ch
int 10h ;call bios service
inc bh ;Calculează culoarea pentru
;următorul punct

64
mov al,bh ;Copie într-un alt registru pt
;prelucrare
shr al,5 ;Se iau numai cei 3 biţi mai
;semnificativi din registrul de culoare
inc cx ;Calculează x pentru următorul punct
cmp cx,600 ;Se afişează o linie de 600 puncte
jne linie

Funcţia OBH : Stabilire paletă de culori


AH=0BH;
BH=modul (0 pentru chenar, 1 pentru imagine);
BL=Numărul paletei (În general între 0 şi 65).

Exemplul 10.5:
Următoarea secvenţă stabileste paleta 8 pentru elementele de imagine:

;Paleta
mov ah,0bh
mov bh,1
mov bl,8
int 10h

10.2 Scrierea directă în memoria de ecran

Utilizarea întreruperii 10h pentru afişarea în ecran este destul de lentă, şi de


aceea se recomandă scrierea directă în memoria de ecran. Aceasta începe la adresa
0A000H în modul grafic şi are dimensiuni dependente de rezoluţia modului grafic
ales.
Următoarea secvenţă introduce adresa zonei ecran în registrul extrasegment şi
scrie un dublu octet conţinut în CX la coordonatele date de DI:

Exemplul 10.6:
MOV AX, 0A000H
MOV ES, AX
MOV ES:[DI], CX

Dacă se doreşte calculul offset-ului (în exemplul de mai sus DI) în funcţie de
coordonatele dorite X şi Y conţinute de exemplu în AX respectiv BX se poate folosi
o secvenţă de felul următor:

Exemplul 10.7:
MOV DI, X ; DI = X
MOV DX, Y ; Se face o copie a lui Y în alt
;registru
; Instrucţiunile următoare fac înmulţirea cu 320
SHL BX, 8 ; Shift Y left 8
SHL DX, 6 ; Shift Y left 6
ADD DX, BX ; DX = Y SHL 8 + Y SHL 6
; Se aduna acum coordonata X
ADD DI, DX ; DI = Y x 320 + X
65
MOV AL, Culoare
MOV ES:[DI],CX; Afişează pixelii lui CX

Pentru afişarea unui segment cu AX=x1, BX=y, CX=x2, DL=culoare se poate face
transferul in memoria ecran a continutului registrului AL cu instrucţiunea STOSB ca
in exemplul urmator:

Exemplul 10.8:
PUSH DX ; DX salvat pentru a putea fi utilizat
;în calcule
SUB CX, AX ; CX = X2 - X1 Lungimea segmentului
MOV DI, AX ; DI = X1
MOV DX, BX ; DX = Y
SHL BX, 8 ; Shift Y left 8
SHL DX, 6 ; Shift Y left 6
ADD DX, BX ; DX = Y SHL 8 + Y SHL 6
ADD DI, DX ; DI = Y x 320 + X
POP DX ; Reface vechiul DX, care conţine
;culoarea (în DL)
MOV AL,DL ; Culoarea este pusă în AL
REP STOSB ; Repetă stocarea lui AL în CX locaţii
; consecutive de la adresa din DI

Mod de lucru:

Pentru testarea programelor care urmează, se poate folosi rularea cu TD,


ecranul putând fi văzut după rulare cu F9, eventual cu comanda User Screen din
submeniul View ( Alt+F5). Se recomandă ca programele să se încheie cu o buclă
infinită de tipul :
term: jmp term
deoarece ieşirea normală, cu INT 21h poate afecta informaţia afişata pe User Screen,
în funcţie de caracteristicile sistemului de operare folosit.
Dacă se foloseşte bucla infinită, ieşirea din ea se poate face cu tasta
WINDOWS aflată între tastele CTRL şi ALT, urmată de un click dreapta pe taskul
respectiv de pe TaskBar şi comanda Close. Este absolut necesară închiderea acestei
ferestre, deoarece altfel memoria rămâne încărcată şi la un moment dat poate să fie
depăşită. Oricum, anumite procese rămân încărcate şi dacă apare mesaj de depăşire a
memoriei, se va reporni sistemul.

P 10.1 Se va scrie un program care să afişeze un punct în ecran, la x=100 şi


y=50, culoarea =2, folosind INT 10H.
Indicaţie: Mai întâi va trebui să se stabileasca modul video 320x 200 ca în
exemplul 10.1

P 10.2 Se va scrie un program care să afişeze o linie în ecran la x1=50,


y1=50, lungimea=100, culoarea=2, folosind INT 10H.
Indicaţie: se va folosi un contor, CX, care va fi incrementat şi se va relua
bucla până când CX ajunge la valoarea x1+lungimea.

66
P 10.3 Se va modifica programul 10.2 pentru a afişa 50 de linii cu aceiaşi
parametri iniţiali, dar cu y crescător.
Indicaţie: Se va include bucla anterioară într-o nouă buclă care îl modifică pe
DX.

P 10.4 Se va modifica programul 10.3 pentru a afişa linii formate din puncte
cu culori crescătoare (linii verticale cu diverse culori).
Indicaţie: Se va incrementa AL în interiorul buclei care trasează o linie.

P 10.5 Se va modifica programul 10.3 pentru a afişa linii cu culori crescătoare


(linii orizontale de diferite culori).
Indicaţie: Se va incrementa AL în exteriorul buclei care trasează o linie.

P 10.6 Se va scrie un program care să afişeze un punct de coordonate x1=160,


y1=0 şi culoare=3, direct prin scriere în memoria ecran, în modul grafic 320 x 200.
Indicaţie: Dacă se pune x1 în DI şi culoarea în AL, se poate folosi
instrucţiunea STOSB. Evident, adresa memoriei ecran, 0A000h va trebui să fie în
prealabil scrisă în ES.

P 10.7 Se va completa programul pentru a afişa o linie orizontală din 200 de


puncte începând din colţul din stânga sus al ecranului (X1=0, Y1=0), cu culoarea 5.
Indicaţie: Se poate folosi programul anterior, punând în CX lungimea liniei şi
prefixul REPZ la instrucţiunea STOSB.

P 10.8 Se va modifica programul pentru a afişa o linie orizontală de 200 de


puncte la poziţia X1=100, Y1=0.
Indicaţii: Înainte de afişarea liniei, registrul DI care ţine adresa punctului va
fi incărcat cu X1.

P 10.9 Se va modifica programul pentru a afişa o linie orizontală de 200 de


puncte la poziţia X1=100, Y1=1.
Indicaţie: Înainte de afişarea liniei, registrul care reţine coordonata iniţială,
DI, va trebui adunat cu 320 (numărul de puncte dintr-o linie).

P 10.10 Se va modifica programul pentru a afişa o linie orizontală de 200 de


puncte la poziţia X1=100, Y1=50.
Indicaţie: Înainte de afişarea liniei, registrul care reţine coordonata iniţială,
DI, va trebui adunat cu Y1*320 (de Y1 ori numărul de puncte dintr-o linie).
Înmulţirea se va face prin deplasări spre stânga, ca în lucrarea de laborator nr. 6. O
parte dintr-o realizare posibilă a programului este prezentată in continuare:

Linieo:
mov di,x1 ;DI conţine X1
mov bp,y1 ;BP conţine Y1
mov cx,lung ;CX conţine numărul de puncte
mov al,culoarea;În AL este culoarea
mov dx,bp ;Se face înmulţirea
shl dx,6 ;lui BP (adică a lui Y1) cu 320
shl bp,8 ;Prin copiere în DX
add bp,dx ;deplasări la stânga şi adunare

67
add di,bp ;Deplasamentul obţinut se aduna la
;adresa iniţială
repz stosb ;Se face transferul şirului

P 10.11 Se va modifica programul pentru a afişa o linie verticală de 50 de


puncte la poziţia X1=100, Y1=50.
Indicaţii:
Trebuie ca fiecare nou punct să fie pus la o adresa cu 320 mai mare decât cel
precedent. Prin urmare, nu mai poate fi folosită instrucţiunea STOSB, ci trebuie în
locul ei o buclă de tipul:
lv1: add di,320 ;Noul punct este cu 320 mai
;departe în memoria de ecran
mov es:[di],al ;Pune punctul
loop lv1 ;Repetă de CX ori

P 10.12 Se va modifica programul de mai sus pentru a afişa o linie oblică spre
dreapta jos, cu x1=100, y1=50 şi lungimea 50 de puncte.
Indicaţie: Adresa unui nou punct se obţine prin sumare cu 321 (adică 320+1)
faţă de adresa celui anterior.

P 10.13 Se va modifica programul de mai sus pentru a afişa o linie oblică spre
stânga jos, cu x1=100, y1=50 şi lungimea 50 de puncte.
Indicaţie: Adresa unui nou punct se obţine prin sumare cu 319 (adică 320-1)
faţă de adresa celui anterior.

P 10.14 Se va modifica programul de la punctul P 10.11 pentru a afişa 100 de


linii verticale identice, cu x1 crescător. Se va obţine un dreptunghi plin.
Indicaţii:
Se va folosi un contor (de exemplu BX) care va fi conţine iniţial 100 şi va fi
scăzut la fiecare trasare a unei linii.
Pentru ca linia să înceapă de fiecare dată de la acelasi y1, registrul DI care
conţine adresa primului punct dintr-o linie va trebui salvat la începutul buclei de linie
(care îl va modifica), şi readus la sfârşitul buclei, când va fi incrementat cu 1 pentru
avansul pe x. După aceea se va decrementa contorul şi se va face saltul condiţionat.

68
Lucrarea de laborator nr. 11
Utilizarea de subrutine (proceduri)

11.1 Chemarea şi revenirea din subrutină

Atunci când anumite porţiuni dintr-un program apar de mai multe ori în
cuprinsul acestuia, este avantajos ca ele să fie scrise o singura dată, ca subrutine, şi
să fie apelate atunci când sunt necesare.
Subrutinele se mai numesc în limbaj de asamblare şi proceduri (ca şi în alte
limbaje de programare).
O subrutină începe cu o etichetă şi se termina cu instrucţiunea RET. Apelul
subrutinei se face cu instrucţiunea CALL având ca operand eticheta respectivă.
Utilizarea subrutinelor modularizează programele şi le face mai compacte,
mai uşor de inţeles şi de dezvoltat. Totuşi utilizarea lor ridică unele probleme, în
special cele legate de transmiterea parametrilor şi modificarea de către subrutine a
unora dintre registre.

Exemplul 11.1:

Vom relua un program din lucrarea precedentă, pentru a trasa două linii
orizontale în poziţii diferite: x1=100, y1=50 şi x1=100 şi y1=150.

.MODEL SMALL
.STACK 200H
.DATA

x1=100 ;Aici se declară parametrii liniilor


y1=50
lung1=200

69
culoarea1 =5

x2=100
y2=150
lung2=200
culoarea2 =3

.CODE
Start:

;Mod video 320x200


mov ah,0
mov al,13h
int 10h

MOV AX, 0A000H; Adresa segmentului ecran mod 13


MOV ES, AX ; în ES

;De aici se cheamă scrierea primei linii

mov di,x1 ;Parametrii primei linii


mov bp,y1
mov cx,lung1
mov al,culoarea1
call linieo ;Cheamă subrutina de linie

;De aici se cheamă scrierea celei de a două linii


mov di,x2 ;Parametrii celei de a două linii
mov bp,y2
mov cx,lung2
mov al,culoarea2
call linieo ;Cheamă subrutina de linie

oprire:
jmp oprire

;*********** Subrutine********************

Linieo:

;Subrutina de trasare a unei linii orizontale cu


;parametrii DI=x,BP=y,CX=lungimea şi AL= culoarea
;Modifica registrele: DX,BP,DI şi CX (în STOSB)
mov dx,bp
shl dx,8
shl bp,6
add dx,bp
add di,dx ;S-a stabilit adresa primului punct
repz stosb ;Aici se scriu punctele liniei
ret ;Reântoarcere în programul apelant

70
END Start
Instrucţiunile subrutinei şi apelurile catre ea au fost scrise cu caractere bold
pentru a se evidenţia procedeul. La începutul subrutinei s-au scris în comentarii
registrele care conţin parametrii necesari, precum şi registrele modificate în urma
execuţiei. Aceste precizări, desi par consumatoare de timp, sunt extrem de utile în
dezvoltarea programului.
Se observă că înainte de apelul subrutinei, registrele au fost încărcate
corespunzător, cu parametrii specifici punctului de apel. Instrucţiunile de iniţializare
au fost deci scoase din blocul de trasare a unei linii folosit în programul din lucrarea
precedenta, luând forme diferite pentru cele două apeluri.
Se observă de asemenea că blocul folosit anterior modifica pe AX şi implicit
pe AL, care în mod normal reţine culoarea, de aceea şi instrucţiunile de iniţializare a
lui ES au fost scoase din subrutina.

P 11.1 Să se ruleze pas cu pas programul din exemplul 11.1 şi să se observe


evoluţia registrelor şi a ecranului (cu ALT+F5). Trecerea peste instrucţiunile
repetitive REPZ STOSB se poate face punând cursorul pe linia imediat următoare şi
dand comanda "Go to cursor" (F4) . Programul se va salva, fiind necesar la punctul
11.3.

P 11.2 Să se dezvolte programul anterior pentru a trasa un dreptunghi cu


vârful din stânga sus la x1=100 şi y1=50, lunginea=100 , înălţimea =50 şi culoarea 5
pentru liniile orizontale şi 1 pentru cele verticale.
Indicaţii: Se va adăuga o subrutina de trasare a unei linii verticale şi se va apela
corespunzător de 2 ori. Programul se va salva, fiind necesar la punctul 11.6.
Pentru ca liniile verticale să nu se suprapună peste cea orizontală de sus (după
cum se poate observa), originea lor trebuie să inceapa cu 320 de puncte mai departe şi
lungimea să fie cu 1 mai mica. Deci înainte de chemarea subrutinei de trasare a
liniilor verticale, DI trebuie adunat cu 320 iar CX decrementat.

11.2 Salvarea şi refacerea registrelor afectate de subrutină

Corpul principal al subrutinelor modifică în general conţinutul unor registre.


Dacă subrutina este apelată în mod repetat, aceste modificări pot afecta modul de
execuţie. De aceea este necesar ca registrele care sunt folosite de subrutina, şi al căror
conţinut este necesar mai târziu, să fie salvate în stivă cu instrucţiuni PUSH şi să fie
refăcute înainte de ieşirea din subrutină cu instrucţiuni POP în ordine inversă,
conform principiului de funcţionare al stivei.
De exemplu, atunci când subrutina este apelată dintr-o bucla în care avem
contorul în SI, iar subrutina modifică registrele DI şi BX, se va proceda în felul
următor:

Exemplul 11.2:
.
.
.
mov di,50 ;Valoarea iniţială a lui DI
mov bx,30 ;Valoarea iniţială a lui BX
mov şi,20 ;Contorul de chemări subrutina

71
et1: call subrutina ;Cheamă subrutina
add di,5 ;Vechea valoare a lui DI se adună
;cu 5
sub bx,3 ;Vechea valoare a lui BX se scade
;cu 3
dec şi ;Decrementeaza contorul
jnz et1 ;Reia dacă contorul nu a ajuns la 0
.
. ;Alte instrucţiuni
.
subrutina: ;Subrutina va modifica pe DI şi BX
push di ;de aceea se salvează DI
push bx ;şi BX
. ;Urmează corpul subrutinei
.
.
inc di ;în care se modifica DI
dec bx ;şi alte registre
.
.
.
pop bx ;La sfârşit se reface întâi BX
pop di ;şi apoi DI (deci în ordine
;inversă)
ret

Se observă că valorile iniţiale din registrele DI şi BX sunt necesare şi în alte


părţi din programul apelant, dar ele vor fi modificate de subrutina. De aceea ele se vor
salva în stivă şi se vor reface apoi din stivă, după principiul ultimul intrat este primul
ieşit ("Last In First Out" - LIFO).
De multe ori, problema modificării registrelor este dificilă, de aceea se
recomandă scrierea în faza iniţială în preambulul subrutinei a registrelor afectate, ca
în exemplul 11.1. Dacă unele din ele conţin valori care vor mai fi necesare, ele se vor
salva şi se vor reface.
Desigur, salvarea se poate face şi imediat înainte de apelul subrutinei, iar
refacerea imediat după revenirea din subrutina, sau în alte puncte convenabil alese.

P 11.3 Să se dezvolte programul anterior pentru a afişa un dreptunghi plin cu


x1=100,y1=50,l=120,h=60 şi culoarea 5.
Indicaţii:
Se va apela în mod repetat, de h ori, subrutina de trasare a unei linii
orizontale. Contor poate fi de exemplu registrul BX, care nu este folosit în altă parte.
Deoarece subrutina modifică registrele CX, DI şi BP, acestea se vor salva în
stivă la începutul subrutinei şi se vor reface la sfârşitul ei, ca mai jos:

Exemplul 11.3:

linieo: ;Linie orizontală


push cx ;Salvează
push di ;registrele
72
push bp ;care se vor modifica

mov dx,bp ;Începe trasarea liniei


shl dx,8
shl bp,6
add dx,bp
add di,dx
repz stosb

pop bp ;Reface
pop di ;registrele
pop cx ;care s-au modificat
ret

P 11.4 Să se dezvolte programul anterior pentru a afişa 20 de dreptunghiuri


pline cu x1=20+8n ,y1=50+5n,l=20,h=60 şi culoarea n, unde n este numărul
dreptunghiului curent.
Indicaţii: Se va scrie şirul instrucţiunilor de afişare a unui dreptunghi ca o subrutină,
şi se va apela în mod repetat, de n ori, schimbând corespunzător parametrii. O
posibilitate de realizare a unui program similar este cea de mai jos:

P 11.5 Să se modifice programul anterior pentru a afişa 2000 de dreptunghiuri


pline cu parametri aleatori cititi din memorie începând de la adresa DS:500h în felul
următor: x1=[500h+n] ,y1=[500h+n+1],l=[500h+n+2],h=60 şi culoarea [500h+n+3],
unde n este numărul dreptunghiului curent.
Indicaţii: Bucla de afişare a dreptunghiurilor va citi din memorie parametrii fiecărui
dreptunghi, deci ei nu mai trebuiesc salvati în subrutina chemată. O posibilitate de
realizare a acestei bucle este cea de mai jos:

Exemplul 11.4:

mov bx,500h ;Începutul zonei de memorie


mov şi,2000 ;Numărul total de dreptunghiuri
dreptnou: ;Mai întâi parametrii primei linii
mov di,[bx] ;DI e aici maxim FFFFh=65535
sub di,65536-320;x1 e acum maxim 320
mov bp,[bx+1] ;BP e iniţial maxim 65535
sub bp,65536-200;y1 e acum maxim 200
mov cx,[bx+2] ;CX e iniţial maxim 65535
and cx,01fh ;Lungimea e acum maxim 32
mov al,[bx+3] ;AL (culoarea) e maxim 255
mov ah,h ;Dreptunghiurile au înălţimea h
call dreptunghi ;Afişează dreptunghiul
add bx,4 ;Indexul în memorie e crescut cu 4
dec şi ;Numărul de repetări scăzut cu 1
jnz dreptnou ;Dacă nu s-a ajuns la 0, repetă

P 11.6 Sa se combine programul anterior cu cel de la punctul 11.3 pentru ca


dreptunghiurile să fie încadrate de un chenar negru.
Indicaţii: Pentru parametrii daţi, se va trasa mai întâi un dreptunghi din patru
linii negre şi apoi unul colorat cu parametri : x1c =x1+1 (x stânga sus color),
73
y1c=y1+1, lc=l-2, hc=h-2. Deoarece parametrii primului dreptunghi sunt necesari şi
pentru al doilea, registrele care îi conţin se vor salva şi apoi reface.

Lucrarea de laborator nr. 12


Utilizarea macroinstrucţiunilor

12.1 Generalitati

La fel ca în cazul utilizării subrutinelor, atunci când într-un program se


foloseşte de mai multe ori un bloc de instrucţiuni, acesta poate fi scris o singură dată
sub forma unei macroinstrucţiuni (numită şi macrodefinitie) şi reutiliza apoi în
punctele în care este necesar.
Blocul conţinut de o macroinstrucţiune va fi automat inserat în programul
obiect în urma procesului de asamblare, ca şi cum ele ar fi fost scrise ca atare în
programul sursă. Acest proces se numeşte expandare a macroinstrucţiunii
(macroexpandare).
Rezultă ca utilizarea de macroinstrucţiuni nu economiseste spatiu în memoria
de program, în schimb uşurează munca programatorului. În plus, spre deosebire de
subrutine, macroinstrucţiunile admit parametri expliciţi, precum şi unele directive
specifice care cresc productivitatea dezvoltării programelor. Si din punct de vedere al
vitezei, macroinstrucţiunile sunt preferabile, deoarece elimină necesitatea salturilor
suplimentare introduse de subrutine. Aceste salturi penalizează puternic viteza
procesoarelor care au coadă de asteptare în care instrucţiunile se extrag anticipat în
ordine, coadă care trebuie golită integral la apariţia unui salt.
Totuşi, utilizarea macroinstrucţiunilor generează anumite dificultăţi, a caror
rezolvare va fi prezentată în cele ce urmează.

12.2 Declararea şi utilizarea macroinstrucţiunilor

Declararea unei macroinstrucţiuni se face în forma următoare:

Nume MACRO [parametri formali]


[REPT]
[IRP]
[IRPC]
corpul macroinstrucţiunii
ENDM

74
Termenii puşi în paranteze drepte sunt opţionali (pot să apară sau să nu apară
la o macroinstrucţiune).
Corpul macroinstrucţiunii conţine date, instrucţiuni, din care unele care se pot
referi la eventualii parametri, şi chiar alte apeluri de macroinstrucţiuni sau subrutine.
Unele asambloare cer ca eventualele comentarii din declararea
macroinstrucţiunii să fie precedate în mod obligatoriu de ";;" deoarece la expandare
din cele două caractere ";" va rămâne unul singur.
Macroinstrucţiunile se declară de regulă la începutul zonei de cod, înainte de
eticheta de intrare în programul principal (START: ).
Utilizarea unei macroinstrucţiuni în program se face prin scrierea numelui
acesteia urmat de lista de parametri actuali (cu valorile necesare in punctul respectiv).

Nume [parametri actuali]

Exemplul 12.1:
Fie programul de trasare a unei drepte orizontale cu parametrii x1,y1,
lungimea şi culoarea din lucrarea 10, punctul P10.10. Scriind şirul de instrucţiuni
care trasează linia ca o macroinstrucţiune, programul poate fi pus în următoarea
forma:

.MODEL SMALL
.STACK 200H
.DATA

x1=100 ;Aici se declară parametrii liniilor


y1=50
lung=200
culoarea=5

.CODE

;Aici se declara macroinstrucţiunea de trasare linie


Linieo macro
mov di,x1 ;DI conţine X1
mov bp,y1 ;BP conţine Y1
mov cx,lung ;CX conţine numărul de puncte
mov al,culoarea;În AL este culoarea
mov dx,bp ;Se face înmulţirea
shl dx,6 ;lui BP (adică a lui Y1) cu 320
shl bp,8 ;Prin copiere în DX
add bp,dx ;deplasări la stânga şi adunare
add di,bp ;Deplasamentul obţinut se adună la
;adresa iniţială
repz stosb ;Se face transferul şirului
endm

Start:

;Mod video 320x200


mov ah,0
mov al,13h
75
int 10h

MOV AX, 0A000H; Adresa segment ecran în modul 13


MOV ES, AX ;în ES
Linieo ;Aici s-a chemat macroinstrucţiunea

oprire:
jmp oprire

END Start

Având însă în vedere posibilităţile comode de transmitere a parametrilor catre


o macroinstrucţiune, mai corect ar fi ca să se scrie lista de parametri formali la
declarare şi de parametri actuali la utilizare. De exemplu, un programu care trasează
două linii ar lua forma următoare:

Exemplul 12.2:

.MODEL SMALL
.STACK 200H
.DATA
x1=50
y1=50
lung=100
culoarea=0Eh
.CODE

;Aici se declara macroinstrucţiunea de trasare linie


Linieo macro x1,y1,lung,culoarea; parametrii
;formali
mov di,x1 ;DI conţine X1
mov bp,y1 ;BP conţine Y1
mov cx,lung ;CX conţine numărul de puncte
mov al,culoarea;În AL este culoarea
mov dx,bp ;Se face înmulţirea
shl dx,6 ;lui BP (adică a lui Y1) cu 320
shl bp,8 ;Prin copiere în DX
add bp,dx ;deplasări la stânga şi adunare
add di,bp ;Deplasamentul obţinut se aduna la
;adresa iniţială
repz stosb ;Se face transferul şirului
endm

Start:

;Mod video 320x200


mov ah,0
mov al,13h
int 10h

MOV AX, 0A000H; Adresa segment ecran în modul 13

76
MOV ES, AX ;în ES

linieo 10,100,30,2 ;Parametrii actuali ai primei


;linii
linieo 20,120,30,1 ;Parametrii actuali ai altei
;linii

oprire:
jmp oprire

END Start

Observaţii: În programul precedent nu era de fapt necesară declararea iniţială


a unor valori pentru x1,y1, lung şi culoarea. Dacă aceasta declarare apare, ea nu are
nici un efect asupra macroinstrucţiunii, chiar dacă în declararea acesteia s-au folosit
aceleaşi simboluri. Dacă însă la utilizarea macroinstrucţiunii sunt puse aceste
simboluri, ele vor lua ca valori actuale cele declarate explicit (50,50,100 şi OEh).

Modul de lucru.

P 12.1 Să se scrie şi să se testeze programul din exemplul 12.2. Se va observa


mai întâi în fişierul de listare modul în care macroinstrucţiunea este expandată în cele
două puncte unde este apelată şi cum apar parametrii actuali. Apoi se vor modifica
parametrii actuali ai uneia dintre utilizări, folosind simbolurile declarate în partea de
date a programului, şi se va observa în fişierul de listare cum sunt înlocuite aceste
simboluri.
Se va mai declara în partea de date un alt set de simboluri,
x1=150,y1=60,lung=30,culoarea=8, care vor fi folosite pentru trasarea unei a treia
linii orizontale.

12.3 Utilizarea etichetelor locale cu directiva LOCAL

Dacă, la declararea unei macroinstrucţiuni, în corpul acesteia există etichete


catre care se fac salturi, la expandarea în mai multe locuri se vor genera mesaje de
eroare de tip "simbol deja utilizat în altă parte". Nu se va mai putea şti catre care din
simbolurile identice aparute în urma expandarii să se faca saltul.
Pentru a se evita această situaţie, dacă în declararea unei macroinstrucţiuni se
folosesc simboluri, se va folosi înainte de corpul macroinstrucţiunii directiva
LOCAL urmată de lista de simboluri.

Nume MACRO [parametri formali]


LOCAL simbol1,simbol2,…
corpul macroinstrucţiunii
ENDM

În urma expandării, simbolurile vor fi renumite automat de catre asamblor sub


forma ??0001, ??0002, până la ??9999 şi nu vor mai fi posibile erori.

Exemplul 12.3:

77
.MODEL SMALL
.STACK 200H
.DATA
x1=50
y1=50
lung=100
culoarea=0Eh
.CODE

Liniev macro x1,y1,lung,culoarea


local Lv1
mov di,x1 ;DI conţine X1
mov bp,y1 ;BP conţine Y1
mov cx,lung ;CX conţine numărul de puncte
mov al,culoarea;În AL este culoarea
mov dx,bp ;Se face înmulţirea
shl dx,6 ;lui BP (adică a lui Y1) cu 320
shl bp,8 ;Prin copiere în DX
add bp,dx ;deplasări la stânga şi adunare
add di,bp ;Deplasamentul obţinut se adună la
;adresa iniţială
Lv1: add di,320 ;Noul punct este cu 320 mai
;departe în memoria de ecran
mov es:[di],al ;Pune punctul
loop Lv1 ;Repetă de CX ori
endm

Start:

;Mod video 320x200


mov ah,0
mov al,13h
int 10h

MOV AX, 0A000H; Adresa segmentului ecran mod 13


MOV ES, AX ;în ES

liniev x1,y1,lung,culoarea
liniev 20,120,30,1

oprire:
jmp oprire

END Start

Se observă că în macroinstrucţiunea de trasare a unei linii verticale există o


bucla cu eticheta Lv1. Aceasta este declarată cu directiva LOCAL Lv1, astfel că dacă
este utilizată în mai multe locuri, la expandările respective simbolul va căpăta
automat denumiri diferite.

78
Modul de lucru

P 12.2 Se va relua programul de desenare a unui dreptunghi din lucrarea


precedentă (P 11.2) folosind macroinstrucţiuni.
P 12.3 Se va scrie un program care să traseze un triunghi dreptunghic isoscel
cu ipotenuza orizontală şi unul cu ipotenuza oblică folosind macroinstrucţiuni pentru
linii oblice , orizontale şi verticale.
P 12.4 Se va relua programul de afişare a unor dreptunghiuri aleatoare cu
parametri din memorie, prezentat în lucrarea precedenta (P 11.5) folosind
macroinstrucţiuni.

12.4 Alte facilităţi de macroasamblare

Există o serie de directive suplimentare de macroasamblare care permit un


formalism de nivel crescut al scrierii fişierului sursă, lăsând macroasamblorului
sarcina expandării la nivel de limbaj de asamblare obişnuit. Deşi aceste facilităţi sunt
foarte puternice, ele sunt destul de rar necesare, datorită posibilităţilor de integrare a
programelor scrise în limbaj de asamblare în programe scrise în limbaj de nivel înalt
sau mediu care pot prelua partea formală. Vom da în continuare, succint, numai
câteva exemple de astfel de facilităţi. Ele depind totuşi de implementare şi se
recomandă consultarea documentaţiei asamblorului de care se dispune pentru a vedea
forma sintactică şi toate opţiunile prezente.
Macrodefiniţia REPT este folosită atunci când corpul macroinstrucţiunii
respective trebuie transcris de mai multe ori. Forma sintactică obisnuită este
următoarea:

REPT expresie
Corpul macro care se va repeta
ENDM

Ca efect, instrucţiunile din corp se vor repeta de un număr de ori egal cu


valoarea expresiei.
Expresia poate fi un număr, un simbol care a fost asignat numeric anterior,
sau poate fi o structură mai complexa aritmetica sau logica.
În macroinstrucţiuni şi expresii se admit diversi operatori cum ar fi &
(substituire), <> (şir de caractere pentru texte), ! (şir de caractere), % (expresie),
precum şi structuri de tip IF…ELSE…ENDIF.
Alte definiţii utile în macroinstrucţiuni sunt IRP (repetare cu parametri) şi
IRPC (repetare cu parametru şir).
Macroinstrucţiunile pot fi imbricate (se poate chema o macroinstrucţiune din
corpul alteia) şi admit recursivitate - o macroinstrucţiune se poate chema pe ea insăşi
de atatea ori câte argumente se află în lista de apel. Ele pot fi de asemenea anulate pe
parcursul unui program pentru eliberarea memoriei "heap" (cu directiva PURGE) sau
redefinite. Este admisă de către unele asambloare chiar şi folosirea unui nume
rezervat pentru numirea unei macroinstrucţiuni, apărând însă un mesaj de avertizare.
Se recomandă ca alte elemente ale limbajului de asamblare să fie consultate în
documentaţia asamblorului cu care se lucrează, ele fiind utile atunci când se scriu
programe deosebit de lungi şi complexe exclusiv în limbaj de asamblare.
ANEXA 1

79
SETUL DE INSTRUCŢIUNI ALE MICROPROCESOARELOR
INTEL 80x86 ÎN MODUL REAL SAU VIRTUAL 8086.

A 1.1 Notaţii, convenţii


Notaţiile folosite în continuare sunt următoarele:

Operanzi:
- dst: operandul destinaţie (al cărui loc va fi ocupat de rezultatul instrucţiunii)
- src: operandul sursă (care va rămâne neschimbat în urma instrucţiunii)

Date numerice (imediate):


- de 8 biţi - n: 0..0FFh.Notaţie echivalentă: imm8;
- de 16 biţi - nn: 0..0FFFFh.Notatie echivalentă: imm16;
- de 32 biţi - nnnn:0..0FFFFFFFFh. Notaţie echivalentă: imm32;
-pentru salturi relative se folosesc notaţiile: rel8,rel16,rel32

Registre:
- de 8 biţi - r8: AL, AH, BL, BH, CL, CH, DL, DH;
- de 16 biţi - r16: AX, BX, CX, DX, SI, DI, SP, BP,F;
- de 32 biţi -r32: EAX,EBX,ECX,EDX,ESI,EDI,ESP,EBP,EF;
- registre de segment - rs: DS, ES, SS, CS.

Memoria:
- m8: Conţinutul unei locaţii de memorie adresabilă prin adresa efectivă ;
- m16: Conţinutul a două locaţii consecutive de memorie, formând un operand de 16
biţi (2 octeţi).Adresa efectivă indică octetul mai puţin semnificativ al operandului, iar
adresa efectivă +1 indică octetul mai semnificativ;
- m32: Conţinutul a patru locaţii consecutive de memorie, formând un operand de 32
biţi (4 octeţi) Adresa efectivă indică octetul mai puţin semnificativ al operandului, iar
adresa efectivă +3 indică octetul mai semnificativ.

Observaţie: Operanzii de 32 de biţi există numai pentru procesoare


începând cu Intel 80386. Dacă sunt folosiţi în programul sursă astfel de operanzi,
este obligatorie directiva .386 în preambulul programului.

A1.2. Instrucţiuni de transfer

A1.2.1. Transferuri cu memoria şi registrele:

MOV - copierea datelor


Mnemonic: MOV dst, src
Acţiune: "dst" ia valoarea "src".
dst ← src.
Operanzi: dst: r8, r 16, rs, m8, m 16;
src: r8, r16, rs, m8, m16, n, nn;
Restricţii: nu sunt posibile transferuri de tip:
80
- MOV rs, rs
- MOV rs, nn
- MOV cs,*
- MOV m, m.

MOVSX - transferă cu extensia de semn într-un format mai mare


Mnemonic: MOVSX dst,src.
Acţiune: dst← src.
Operandul sursă este transferat într-un registru cu dimensiune mai mare,
păstrând semnul prin transferul bitului de semn în poziţia cea mai semnificativă a
operandului destinaţie.
Operanzi: src: m8,r8 => dst:r16,r32;
src: m16,r16 => dst:r32.

MOVSZ - transferă cu completare cu zerouri într-un format mai mare


Mnemonic: MOVSZ dst,src.
Acţiune: dst← src.
Operandul sursă este transferat într-un registru cu dimensiune mai mare,
completând cu zerouri biţii suplimentari din operandului destinaţie.
Operanzi: src: m8,r8 => dst:r16,r32;
src: m16,r16 => dst:r32.

XCHG - interschimbare între registre sau între un registru şi memorie


Mnemonic: XCHG dst, src.
Acţiune: Se interschimbă conţinuturile dst şi src.
dst ← src;
src ← dst.
Operanzi: dst: r8, r16,r32;
src: r8, r16, m8, m16,m32.
Restricţii: Nu există instrucţiuni de tip:
- XCHG rs, rs
- XCHG cs, *.
Variantă: XCHG dst - interschimb cu acumulatorul implicit AL,AX sau
EAX (în funcţie de mărimea dst).

XLAT - translatare în AL cu baza BX


Acţiune: AL ← [BX +AL].
În registrul AL se încarcă conţinutul locaţiei de memorie a cărei adresă
efectivă este dată de suma dintre BX şi chiar AL.
Adresa de segment este data de DS.

LEA - calculul şi încărcarea adresei efective a unei variabile într-un registru


general
Acţiune: r ← AE(mem).
Mnemonic: LEA r, mem.
Operanzi: r: r16, r32;
mem: m16,m32.
Dacă mărimile operanzilor sunt diferite, se fac automat trunchieri la mărimea
operandului cel mai mic.

81
LGS/LSS/LDS/LES/LFS - Încarcă un pointer (ca o adresa logică de 32 de
biţi) din memorie, de la adresa nn, într-o pereche formată dintr-un registru de
segment şi un registru de 16 biţi.

Mnemonic: LDS r16,RS:nn;


LSS r16,RS:nn;
etc.
Acţiune:
LDS r16, nn: R16L←[RS:nn],R16H←[RS:nn+1],DSL←[RS:nn+2],DSH ← [RS:nn+3]
LSS r16, nn: R16L←[RS:nn],R16H←[RS:nn+1],SSL←[RS:nn+2], SSH ← [RS:nn+3]
LES r16, nn: R16L←[RS:nn],R16H←[RS:nn+1],ESL←[RS:nn+2],DEH ← [RS:nn+3]
LFS r16, nn: R16L←[RS:nn],R16H←[RS:nn+1],FSL←[RS:nn+2], FSH ← [RS:nn+3]
LGS r16, nn: R16L←[RS:nn],R16H←[RS:nn+1],GSL←[RS:nn+2],GSH← [RS:nn+3]

unde r16 este un registru de 16 biţi de uz general, RS este un registru de segment


(DS,SS,ES,FS sau GS) iar nn este un număr de 16 biţi.
Observaţie: Instrucţiunile LSS, LGS, LFS nu apar la procesoare anterioare lui
80386 (nici nu existau registrele de segment FS şi GS), de aceea, în cazul folosirii lor,
în partea initială a programului trebuie introdusă directiva .386.

LAHF - citirea indicatorilor de condiţii (octetul inferior al registrului F) în


AH
Acţiune: AH ← F
AH7=SF (flagul de semn, 1 dacă este minus, 0 dacă este plus);
AH6=ZF (flagul de zero, 1 dacă este 0, 0 dacă nu este 0);
AH5=0 ;
AH4=AF (flagul de transport auxiliar de la cei 4 biţi inferiori ai unui rezultat);
AH3=0 ;
AH2=PF (flagul de paritate, 1 dacă este par, 0 dacă este impar);
AH1=IF (flagul de intreruperi, 1 dacă dacă întreruperile sunt activate, 0 dacă
nu);
AH0=CF (flagul de transport 1 dacă exista transport de la rezultat);
Structura octetului inferior al registrului indicatorilor de condiţii F este:

S Z x A x P x C

SAHF - Salvare AH în registrul de flaguri.

Acţiune: F ← AH

SF=AH7 (flagul de semn, 1 dacă este minus, 0 dacă este plus);


ZF=AH6 (flagul de zero, 1 dacă este 0, 0 dacă nu este 0);
AF= AH4 (flagul de transport auxiliar de la cei 4 biţi inferiori ai unui
rezultat);
PF=AH2 (flagul de paritate, 1 dacă este par, 0 dacă este impar);
IF= AH1 (flagul de intreruperi, 1 dacă dacă întreruperile sunt activate, 0 dacă
nu);
CF=AH0 (flagul de transport 1 dacă exista transport de la rezultat);

82
Bitii AH5 şi AH3 trebuie să fie 0.

A1.2.2. Transferuri cu stiva

PUSH - salvarea datelor în stivă


Mnemonic: PUSH src.
Operand r16, r32, m16, m32.
Acţiune:
Pentru operand de 16 biţi:
SP ← SP-2;
[SP] ← src1 (octetul inferior al sursei);
[SP+ 1] ← src2 (octetul superior al sursei);
Pentru operand de 32 biţi:
SP ← SP-4;
[SP] ← src1 (octetul inferior al sursei);
[SP+ 1] ← src2;
[SP+2] ← src3;
[SP+ 3] ← src4 (octetul superior al sursei).
Descriere: Indicatorul de stivă este decrementat cu un număr egal cu numărul
de octeţi ai operandului, după care operandul este salvat în stivă începând de la adresa
conţinută acum în indicatorul de stivă.
Observaţie: Este permisă şi salvarea din memorie (2 sau 4 locaţii consecutive,
adresate cu unul din modurile de adresare ).

POP - aducerea datelor din stivă


Mnemonic: POP dst.
Acţiune:
Pentru operand de 16 biţi:
dst [SP];
dsth ← [SP+ 1];
SP ← SP+2.
Pentru operand de 32 biţi:
SP ← SP-4;
dst1← [SP] (octetul inferior al sursei);
dst2 ← [SP+ 1];
dst3 ← [SP+2];
dst4 ← [SP+3] (octetul superior al sursei).

Operand: r16 (cu excepţia lui CS),r32, m16,m32


Descriere: Registrul sau locaţiile de memorie specificate de operand se
încarcă cu conţinutul locaţiilor de stivă a căror adresa de start se află în indicatorul de
stivă. Apoi indicatorul de stivă este incrementat cu un număr egal cu numărul de
octeţi ai operandului.

Observaţie: Este permisă şi aducerea din stivă în locaţii de memorie (2 sau 4 locaţii
consecutive, adresate cu unul din modurile de adresare).

PUSHF,PUSHFD - salvarea registrului indicatorilor de condiţii în stivă,


respectiv a registrului extins al indicatorilor de conditii
Mnemonic : PUSHF

83
Acţiune: SP ← SP-2
[SP] ← F1 (octetul inferior al registrului F);
[SP+1] ← F2 (octetul superior al registrului F).
Mnemonic: PUSHFD
Acţiune: SP ← SP-4;
[SP] ← EF1 (octetul inferior al registrului EF);
[SP+1] ← EF2;
[SP+2] ← EF3;
[SP+3] ← EF4 (octetul superior al registrului EF).

POPF, POPFD - aducerea indicatorilor de condiţii din stivă , respectiv a


registrului extins al indicatorilor de conditii.
Mnemonic : POPF
Acţiune: F1 ← [SP] (octetul inferior al registrului F);
Fh ← [SP+1] (octetul superior al registrului F);
SP ← SP+2.
Mnemonic : POPFD
Acţiune: F1 ← [SP] (octetul inferior al registrului EF);
F2 ← [SP+1] ;
F3 ← [SP+2] ;
F4 ← [SP+3] (octetul superior al registrului EF);
SP ← SP+4.

PUSHA,PUSHAD- salvarea tuturor registrelor în stivă


Mnemonic : PUSHA
Acţiune: SP ← SP-16;
[SP] ← AX,CX,DX,BX,SP(valoarea initiala),BP,SI,DI.
Mnemonic : PUSHAD
Acţiune: SP ← SP-32;
[SP] ← EAX,ECX,EDX,EBX,ESP(valoarea initiala),EBP,ESI,EDI.

POPA,POPAD- readucerea tuturor registrelor din stivă


Mnemonic : POPA
Acţiune: [SP] ← AX,CX,DX,BX,SP(nu se modifică),BP,SI,DI;
SP ← SP+16.
Mnemonic : POPAD
Acţiune: [SP] ← EAX,ECX,EDX,EBX,ESP(nu se modifică), EBP,ESI,EDI;
SP ← SP+32.

A1.2.3. Transferuri cu porturile

IN - citire din portul n sau a cărui adresa este în DX


Mnemonic: IN dst, src.
Acţiune: AL ← [port]8 sau
AX ← [port]16 sau

84
EAX ← [port]32 .
AL ← port[DX]8 sau
AX ← port[DX]16 sau
EAX ← port[DX]32 .
Operanzi: port: n,[DX].
Observaţii: Se poate face citire pe 8 biţi (în AL, dintr-un port de 8 biţi), pe 16
biţi (în AX, dintr-un port de 16 biţi) sau pe 32 biţi (în EAX, dintr-un port de 32 biţi).
În cazul în care adresa portului este conţinutul lui DX, aceasta are 16 biţi, deci
sunt posibile 65536 porturi. Dacă adresa este un număr n, aceasta are numai 8 biţi,
deci sunt posibile 256 de porturi.

OUT - scriere în portul n sau a cărui adresa este în DX


Mnemonic: OUT dst, src
Acţiune: [port]8 ← AL sau
[port]16 ← AX sau
[port]32 ← EAX
port[DX]8 ← AL sau
port[DX]16 ← AX sau
port[DX]32 ← EAX

Operanzi: port: n,[DX]


Observaţii: Se poate face citire pe 8 biţi (în AL, dintr-un port de 8 biţi), pe 16
biţi (în AX, dintr-un port de 16 biţi) sau pe 32 biţi (în EAX, dintr-un port de 32 biţi).
În cazul în care adresa portului este conţinutul lui DX, aceasta are 16 biţi, deci
sunt posibile 65536 porturi. Dacă adresa este un număr n, aceasta are numai 8 biţi,
deci sunt posibile 256 de porturi.

A1.2.4. Instrucţiuni de transfer de şiruri

LODSB, LODSW, LODSD,STOSB, STOSW,STOSD

Mnemonic: LODSB - Încarcă un octet de la DS:SI în AL


Acţiune: AL← [SI];
SI← SI +1 dacă DF=0, SI← SI-1 dacă DF=1.

Mnemonic: LODSW - Încarcă un cuvânt de la DS:SI în AX


Acţiune: AL← [SI];
AH← [SI+1];
SI← SI +2 dacă DF=0, SI← SI-2 dacă DF=1.

Mnemonic: LODSD - Încarcă un dublucuvant de la DS:SI în EAX


Acţiune: EAX0← [SI] (octetul inferior al EAX);
EAX1← [SI+1];
EAX1← [SI+2];
EAX1← [SI+3] (octetul superior al EAX);
SI← SI +4 dacă DF=0, SI← SI-4 dacă DF=1.

Mnemonic: STOSB - Încarcă AL la ES:DI

85
Acţiune: [DI]← AL
DI← DI +1 dacă DF=0, DI← DI-1 dacă DF=1

Mnemonic: STOSW - Încarcă AL la ES:DI


Acţiune: [DI]← AL;
[DI+1]← AH;
DI← DI +2 dacă DF=0, DI← DI-2 dacă DF=1.

Mnemonic: STOSD - Încarcă un dublucuvant din EAX la ES:DI


Acţiune: [DI]← EAX0 (octetul inferior al EAX);
[DI+1]← EAX1 ;
[DI+2]← EAX2 ;
[DI+3] ← EAX3 (octetul superior al EAX);
DI← DI +4 dacă DF=0, DI← DI-4 dacă DF=1.

Mnemonic: LODS dst,src - Mută un octet, doi octeţi sau 4 octeţi de la


adresa la adresa DS:SI în AL, AX sau EAX. Aceasta instrucţiune
este echivalenta cu LODSB,LODSW şi LODSD care nu au însă operanzi
expliciţi.

Mnemonic: STOS dst,src - Mută conţinutul lui AL, AX sau EAX în


memorie la adresa ES:DI. Aceasta instrucţiune este echivalentă cu
STOSB,STOSW şi STOSD care nu au însă operanzi expliciţi.

Pentru instrucţiunile de transfer LODSB, LODSW şi LODSW, sursa este


locaţia de memorie cu adresa efectiva data de registrul index sursa SI şi adresa de
segment dată de DS.
Pentru instrucţiunile de transfer STOSB, STOSW şi STOSD destinaţia este
locaţia de memorie cu adresa efectiva data de registrul index destinaţie DI şi adresa
de segment dată de ES.
In urma efectuării unei astfel de instrucţiuni, registrul index SI respectiv DI
se modifică în funcţie de starea flagului DF (de direcţie). Daca DF este 0, registrul
index va fi incrementat cu 1 la LODSB şi STOSB, cu 2 la LODSW şi STOSW şi cu 4
la LODSD şi STOSD . Daca DF este 1, registrul index va fi decrementat cu 1, 2,
respectiv cu 4.
Registrul general implicit este AL la transferul de un octet, AX la transferul
de doi octeţi şi EAX la transferul pe 4 octeţi.

MOVS,MOVSB, MOVSW,MOVSD

Aceste instrucţiuni combină instrucţiunile LODSB şi STOSB, respectiv


LODSW şi STOSW, fără a afecta AL sau AX. Segmentul destinaţie este întotdeauna
ES. Segmentul sursă implicit este DS, dar poate fi şi altul specificat în adresa sursă.

Mnemonic: MOVSB - Mută un octet de la adresa DS:SI la adresa ES:DI


Acţiune: [DS]← [SI];
SI← SI +1 dacă DF=0, SI← SI-1 dacă DF=1;
DI← DI +1 dacă DF=0, DI← DI-1 dacă DF=1.

86
Mnemonic: MOVSW - Mută un cuvânt de la adresa DS:SI la adresa ES:DI
Acţiune: [DI]← [SI];
[DI+1]← [SI+1];
SI← SI +2 dacă DF=0, SI← SI-2 dacă DF=1;
DI← DI +2 dacă DF=0, DI← DI-2 dacă DF=1.
Mnemonic: MOVSD - Mută un dublu-cuvant (32 de biţi) de la adresa
DS:SI la adresa ES:DI
Acţiune: [DI]← [SI];
[DI+1]← [SI+1];
[DI+2]← [SI+2];
[DI+3]← [SI+3];
SI← SI +4 dacă DF=0, SI← SI-4 dacă DF=1;
DI← DI +4 dacă DF=0, DI← DI-4 dacă DF=1.
Mnemonic: MOVS dst,src - Mută un octet, doi octeţi sau 4 octeţi de la
adresa SI la adresa ES:DI. Operanzii sunt simboluri de o anumită lungime,
declaraţi anterior în program. Această instrucţiune este echivalentă cu MOVSB,
MOVSW şi MOVSD care nu au însă operanzi expliciţi.

INS, INSB, INSW, INSD

Mnemonic: INSB - Încarcă în memorie la ES:DI conţinutul portului de 8


biţi a cărui adresă este în DX
Acţiune: [DI]←port[DX];
DI← DI +1 dacă DF=0, DI← DI-1 dacă DF=1.

Mnemonic: INSW - Încarcă în memorie la ES:DI conţinutul portului de 16


biţi a cărui adresă este în DX
Acţiune:[DI] ← port[DX]0 (octetul inferior al portului a cărui adresa e în
DX);
[DI+1]← port[DX]1(octetul superior al portului a cărui adresa e în
DX);
DI← DI +2 dacă DF=0, DI← DI-2 dacă DF=1.

Mnemonic: INSD - Încarcă în memorie la ES:DI conţinutul portului de 32


biţi a cărui adresă este în DX
Acţiune: [DI]← port[DX]0 (octetul inferior al portului a cărui adresa e
în DX);
[DI+1]←port[DX]1;
[DI+2]←port[DX]2;
[DI+3]← port[DX]3 (octetul superior al portului a cărui adresa
e în DX);
DI← DI +4 dacă DF=0, DI← DI-4 dacă DF=1.

Mnemonic: INS dst,src - Mută un octet, doi octeţi sau 4 octeţi din portul a
cărui adresa este conţinută în DX, într-un registru sau în memorie la adresa
ES:DI.Aceasta instrucţiune este echivalenta cu instrucţiunile INSB, INSW şi INSD
care nu au însă operanzi expliciţi.

87
OUTS, OUTSB, OUTSW, OUTSD

Mnemonic: OUTSB - Încarcă din memorie de la DS:SI în portul de 8 biţi


a cărui adresa este în DX
Acţiune: port[DX]← [SI];
SI← SI +1 dacă DF=0, SI← SI-1 dacă DF=1.
Mnemonic: OUTSW - Încarcă din memorie de la DS:SI în portul de 16
biţi a cărui adresă este în DX.

Acţiune: port[DX]0← [SI] (octetul inferior al portului a cărui adresa e în


DX);
port[DX]1← [SI+1] (octetul superior al portului a cărui adresa e în
DX);
SI← SI +2 dacă DF=0, SI← SI-2 dacă DF=1.

Mnemonic: INSD - Încarcă din memorie de la DS:SI în portul de 32 biţi a


cărui adresă este în DX
Acţiune: port[DX]0← [SI] (octetul inferior al portului a cărui adresa e în
DX);
port[DX]1← [SI+1] ;
port[DX]2← [SI+2] ;
port[DX]3← [SI+3] (octetul superior al portului a cărui adresa
e în DX);
SI← SI +4 dacă DF=0, SI← SI-4 dacă DF=1.

Mnemonic: OUTS dst,src - Mută un octet, doi octeţi sau 4 octeţi în portul
a cărui adresa este conţinută în DX, dintr-un registru sau din memorie de la adresa
DS:SI. Aceasta instrucţiune este echivalentă cu instrucţiunile OUTSB, OUTSW şi
OUTSD care nu au însă operanzi expliciţi.

Prefixul REP

Instrucţiunile de transfer de şiruri LODS, LODSx, STOS, STOSx, MOVS,


MOVSx, INS, INSx, OUTS, OUTSx (unde x este B,W sau D) pot fi precedate de
prefixul REP, care cere procesorului să repete instrucţiunea pe care o precede până
când CX devine 0 (prin decrementare automată). In cazul instrucţiunilor LODSx se
foloseste însă de regula prefixul LOOP, deoarece cu REP s-ar rescrie în mod inutil
registrul AL, AX sau EAX de CX ori.

A1.3. Instrucţiuni de calcul

Există următoarele tipuri de operaţii efectuate de ALU:

88
- aritmetice;
- aritmetice speciale;
- logice;
- deplasări;
- rotaţii.

Toate acestea afectează corespunzător unul sau mai mulţi din următorii
indicatori de condiţii:
- CF (Carry Flag) - indicator de transport - reflectă transportul în exterior al bitului
cel mai semnificativ al rezultatului operaţiilor aritmetice. Acest indicator poate fi
folosit în cazul adunării sau scăderii numerelor pe mai mulţi octeţi, semnificând în
primul caz transport la adunare şi în al doilea caz împrumut la scădere. Indicatorul CF
nu este modificat de instrucţiuni de incrementare şi decrementare.
- PF (Parity Flag) - indicator de paritate - este poziţionat pe 1 dacă rezultatul are un
număr par de biţi 1.
- AF (Auxiliary Carry Flag) - indicator de transport auxiliar - este poziţionat în 1 dacă
a fost transport de la nivelul inferior la nivelul superior al semioctetului rezultatului
(de la bitul 3 la bitul 4). Acest indicator se foloseşte în programele de calcule în
aritmetica zecimală.
- ZF (Zero Flag) - indicatorul de zero - este poziţionat în 1 dacă rezultatul
operaţiei a fost zero.
- SF (Sign Flag) indicatorul de semn - este poziţionat în 1 dacă cel mai semnificativ
bit al rezultatului (MSB) este 1, adică în reprezentarea numerelor în C2 (complement
faţă de 2) rezultatul este negativ.
- OF (Overflow Flag) - indicator de depăşire aritmetică (a gamei de valori posibil de
reprezentat) - este poziţionat în 1 dacă dimensiunea rezultatului depăşeşte capacitatea
locaţiei de destinaţie şi a fost pierdut un bit (la valorile cu semn se alterează semnul).

A1.3.1. Instrucţiuni aritmetice şi logice

Observaţii genera1e:
- Operanzi: dst: r8, r16, r32, m8, m16, m32
src: r8, r16, r32, m8, m16, m32, n, nn, nnnn
- Operaţiile sunt posibile pe 8, 16 sau 32 biţi (sursa şi destinaţia având mărimi
compatibile)
- Sursa şi destinaţia nu pot fi concomitent locaţii de memorie
- Adresarea imediată (specificarea valorii numerice a operandului) este
posibilă numai pentru sursă.
- Sunt posibile adunări, scăderi şi înmulţiri cu semn având operandul
destinaţie registru sau memorie pe 16 sau 32 de biţi, şi operandul sursa o valoare
imediată de 8 biţi. In acest caz, operandul de 8 biţi este extins la 16 sau 32 de biţi cu
păstrarea semnului (bitul cel mai semnificativ, cel de semn, este copiat din pozitia a
8-a în toţi biţii până la poziţia 16, respectiv 32). Aceasta posibilitate există şi pentru
operaţiile logice, cu excepţia instrucţiunii TEST.

ADC dst,src - Adunare cu carry (transport)


Acţiune: dst ← dst + src + CF;

ADD dst,src - Adunare

89
Acţiune: dst ← dst + src;

SUB dst,src - Scădere


Acţiune: dst ← dst - src;

SBB dst,src - Scădere cu "borrow" (împrumut)


Acţiune: dst ← dst - src - CF;
INC dst - Incrementare
Acţiune: dst ← dst + 1; Nu este afectat CF.

DEC dst - Decrementare


Acţiune: dst ← dst - 1; Nu este afectat CF.

NEG dst - Negare aritmetică


Acţiune: dst ← - dst (complementare faţă de doi)
Descriere: Se obţine operandul cu semn schimbat în complement faţă
de 2.
CF este setat automat, cu excepţia cazului când operandul este 0.

NOT dst - Complementare faţă de 1


Acţiune: dst ← 0FFh - dst ; pentru operand de 8 biţi
dst ← 0FFFFh - dst ; pentru operand de 16 biţi
dst ← 0FFFFFFFFh - dst ; pentru operand de 32 biţi
Descriere: Instrucţiunea NOT inversează operandul; orice 1 devine 0
şi viceversa.
Nu sunt afectaţi indicatorii de condiţii.

MUL src - Înmulţirea fără semn lui AL, AX sau EAX cu un numar.
Acţiunea depinde de mărimea operandului src, luând urmatoarele forme:

- src de 8 biţi: AX ← AL * src8; src: r8,m8;


Dacă AH = 0 atunci CF ← 0; În celelalte cazuri CF ← 1 şi
OF ← CF.

-src de 16 biţi: DX: AX ← AX * src16; src: r16,m16;


Dacă DX = 0 atunci CF ← 0; În celelalte cazuri CF ← 1 şi
OF ← CF.

- src de 32 biţi: EDX: EAX ← EAX * src32; src: r32,m32;


Dacă EDX = 0 atunci CF ← 0; În celelalte cazuri CF ← 1 şi
OF ← CF.

IMUL (dst,) src - Înmulţirea cu semn a lui AL,AX , EAX sau a altui registru
cu un număr.
Acţiunea depinde de operandul destinaţie şi de marimea operandului src.
In cazul în care destinaţia este acumulatorul AL,AX sau EAX se obţine
rezultatul complet, chiar dacă apare flagul Overflow, deoarece rezultatul va fi

90
memorat cu precizie dublă faţă de a operanzilor:

- src de 8 biţi: AX ← AL * src8; src: r8,m8;


Dacă AH = 0 sau AH = FF atunci CF ← 0; În celelalte cazuri CF ← 1
şi OF ← CF.

- src de 16 biţi: DX: AX ← AX * src16; src: r16,m16;


Dacă DX = 0 sau AH = FF atunci CF ← 0; În celelalte cazuri CF ← 1
şi OF ← CF.

- src de 32 biţi: EDX: EAX ← EAX * src32; src: r32,m32;


Dacă EDX = 0 sau AH = FF atunci CF ← 0; În celelalte cazuri CF ←
1 şi OF ← CF.

Spre deosebire de înmulţirea numerelor fără semn cu instrucţiunea MUL, în


cazul instrucţiunii IMUL este posibil ca deînmulţitul să fie şi alt registru în afară de
acumulator, iar sursa să fie o valoare numerică imediată. In acest caz însă, dacă
rezultatul are mai multi biţi decât registrul care conţine deînmulţitul, se pierd bitii
care depăşesc lărgimea acestuia.

Acţiunea este următoarea:

- cu dst de 16 biţi:
IMUL dst,src
dst ← dst * src; (dst= r16; src=r16/m16 /imm8/imm16);
Dacă DX = 0 sau AH = FF atunci CF ← 0; În celelalte cazuri CF ← 1
şi OF ← CF.
Dacă src este de tip imm8, acesta se extinde cu semn până la lungimea dst.

- cu dst de 32 biţi:
IMUL dst,src
dst ← dst * src; (dst= r32; src=r32/m32 /imm8/imm32);
Dacă DX = 0 sau AH = FF atunci CF ← 0; În celelalte cazuri CF ← 1
şi OF ← CF.
Dacă src este de tip imm8, acesta se extinde cu semn până la lungimea dst.

DIV src - Împărţirea fără semn a acumulatorului cu un registru sau locaţie de


memorie.
Acţiune: - dacă src este de 8 biţi:
AL ← AX/src8 (câtul împărţirii);
AL ← AX % src8 (restul împărţirii);
src: r8,m8.
- dacă src este de 16 biţi:
AX ← DX : AX/srcl6 (câtul împărţirii);
DX ← DX : AX % srcl6 (restul împărţirii);
src: r16,m16.
- dacă src este de 32 biţi:
EAX ← EDX : EAX/srcl6 (câtul împărţirii);
EDX ← EDX : EAX % srcl6 (restul împărţirii);
src: r32,m32.

91
Observaţii: Dacă rezultatul (câtul) nu încape în registrul destinaţie AL, AX
respectiv EAX, sau împărţitorul este 0, se generează Întrerupere 0 (DE - Divide
Error) şi se sare automat din program. De aceea trebuie făcuta o evaluare prealabilă a
domeniului de valori ale rezultatului şi trebuie folosit un registru destinaţie
corespunzător.
Dacă câtul este subunitar, el este ajustat la 0.
Indicatorii de condiţii sunt nedefiniţi.

IDIV src - Împărţirea cu semn a acumulatorului cu un registru sau locaţie de


memorie.
Acţiune: - dacă src este de 8 biţi:
AL ← AX/src8 (câtul împărţirii);
AL ← AX % src8 (restul împărţirii);
src: r8,m8.
- dacă src este de 16 biţi:
AX ← DX : AX/srcl6 (câtul împărţirii);
DX ← DX : AX % srcl6 (restul împărţirii);
src: r16,m16.
- dacă src este de 32 biţi:
EAX ← EDX : EAX/srcl6 (câtul împărţirii);
EDX ← EDX : EAX % srcl6 (restul împărţirii);
src: r32,m32.

Observaţie: Dacă rezultatul (câtul) nu încape în registrul destinaţie AL, AX


respectiv EAX, sau împărţitorul este 0, se generează întrerupere 0 (DE - Divide
Error) şi se sare automat din program. De aceea trebuie făcută o evaluare prealabilă a
domeniului de valori ale rezultatului şi trebuie folosit un registru destinaţie
corespunzător.
Dacă câtul este subunitar, el este ajustat la 0.
Semnul restului este acelaşi cu al împărţitorului.
Indicatorii de condiţii sunt nedefiniţi.

CBW - Conversie de la Byte (8 biţi) din AL la Word (16 biţi) în AX, cu


păstrare semn.
Acţiune: AL7 = 0 => AH ← 0;
AL7 = 1 => AH ← 0FFh.
Bitul cel mai semnificativ al lui AL este copiat în toţi biţii registrului AH.
Indicatorii de condiţii nu sunt afectaţi.

CWD - Conversie de la Word (16 biţi) din AX la Dword (32 biţi) în DX:AX,
cu păstrare semn.
Acţiune: AX15 = 0 => DX ← 0;
AL15 = 1 => DX ← 0FFFFh.
Bitul cel mai semnificativ al lui AX este copiat în toţi biţii registrului DX.
Indicatorii de condiţii nu sunt afectaţi.

92
CWDE - Conversie de la Word (16 biţi) la Dword (32 biţi) în EAX, cu
păstrare semn.

Acţiune:
EAX15 = 0 => EAX16 ..EAX31= 1 ;
EAX15 = 1 => EAX16 ..EAX31= 1 .
Bitul cel mai semnificativ al lui AX este copiat în toţi bitii jumătăţii
superioare a lui EAX.
Indicatorii de condiţii nu sunt afectaţi.

CDQ - Conversie de la Dword (32 biţi) în EAX la Qword (64 biţi) în


EDX:EAX, cu păstrare semn.
Acţiune:
EAX31 = 0 => EDX ← 0;
AL31 = 1 => EDX ← 0FFFFFFFFh.
Bitul cel mai semnificativ al lui EAX este copiat în toţi bitii registrului EDX.
Indicatorii de condiţii nu sunt afectaţi.

AND dst,src - SI logic pe bit


Acţiune: bn(dst) ← bn(dst) AND bn(src) ;
dst: r8,r16,r32,m8,m16,m32;
src: r8,r16,r32,m8,m16,m32,imm8,imm16,imm32.
Descriere: Fiecare bit al rezultatului instrucţiunii AND este un 1 dacă ambii
biţi corespunzători ai operanzilor sunt 1; altminteri, devine un 0.
Sursa şi destinaţia trebuie să fie de dimensiuni egale. Este posibil ca sursa să
fie o valoare imediată de 1 octet iar destinaţia să fie de 2 sau 4 octeţi, caz în care
numarul sursa va fi extins cu semn până la valoarea destinaţiei.
Nu se admite ca ambii operanzi să fie locatii de memorie.

OR dst,src - SAU logic pe bit


Acţiune: bn(dst) ← bn(dst) OR bn(src) ;
dst: r8,r16,r32,m8,m16,m32;
src: r8,r16,r32,m8,m16,m32,imm8,imm16,imm32;
Descriere: Instrucţiunea OR calculează SAU al celor doi operanzi şi rezultatul
este plasat în primul operand. Fiecare bit al rezultatului este 0 dacă ambii biţi
corespunzători ai operanzilor sunt 0; altminteri, fiecare bit este 1.
Sursa şi destinaţia trebuie să fie de dimensiuni egale. Este posibil ca sursa să
fie o valoare imediată de 1 octet iar destinaţia să fie de 2 sau 4 octeţi, caz în care
numarul sursa va fi extins cu semn până la valoarea destinaţiei.
Nu se admite ca ambii operanzi să fie locatii de memorie.

XOR dst,src - SAU EXCLUSIV logic pe bit


Acţiune: bn(dst) ← bn(dst) XOR bn(src) ;
dst: r8,r16,r32,m8,m16,m32;
src: r8,r16,r32,m8,m16,m32,imm8,imm16,imm32.
Descriere: Instrucţiunea XOR calculează SAU EXCLUSIV al celor doi ope-
ranzi. Fiecare bit al rezultatului este 1 dacă biţii corespunzători ai operanzilor sunt
diferiţi; fiecare bit este 0 dacă biţii corespunzători sunt identici. Rezultatul înlocuieşte

93
primul operand.
Sursa şi destinaţia trebuie să fie de dimensiuni egale. Este posibil ca sursa sa
fie o valoare imediată de 1 octet iar destinaţia să fie de 2 sau 4 octeţi, caz în care
numarul sursa va fi extins cu semn până la valoarea destinaţiei.
Nu se admite ca ambii operanzi să fie locatii de memorie.

CMP dst,src - Comparaţie aritmetică (prin scădere)


Acţiune: dst-src;
dst: r8,r16,r32,m8,m16,m32;
src: r8,r16,r32,m8,m16,m32,imm8,imm16,imm32.
Decriere: Se face diferenţa între dst şi src, fără generare rezultat - se modifică
doar indicatorii de condiţii.
Sursa şi destinaţia trebuie să fie de dimensiuni egale. Este posibil ca sursa sa
fie o valoare imediata de 1 octet iar destinaţia să fie de 2 sau 4 octeţi, caz în care
numarul sursă va fi extins cu semn până la valoarea destinaţiei.
Nu se admite ca ambii operanzi să fie locatii de memorie.

TEST dst,src - testare (SI fără generare de rezultat)


dst: r8,r16,r32,m8,m16,m32;
src: r8,r16,r32,m8,m16,m32,imm8,imm16,imm32.
Descriere: Instrucţiunea TEST calculează "SI logic pe bit" de cei doi operanzi.
Fiecare bit al rezultatului este 1, dacă ambii biţi corespunzători ai operanzilor sunt l;
altminteri, fiecare bit este 0. Rezultatul operaţiei este şters şi doar f1agurile sunt
modificate.
Sursa şi destinaţia trebuie să fie de dimensiuni egale.
Nu se admite ca ambii operanzi să fie locaţii de memorie.

SCAS,SCASB,SCASW,SCASD - Compară acumulatorul cu un sir

Mnemonic: SCAS dst


Descriere - Compară conţinutul registrului (E)AX cu conţinutul locaţiilor de
memorie (una, doua sau patru) care încep la adresa ES:[DI] şi poziţionează
corespunzator flagurile
dst: m8,m16,m32
Acţiune: AL - ES:[DI];
DI← DI+n dacă DF=0, DI← DI-n dacă DF=1 unde n=1/2/4 în
funcţie de dimensiunea operandului.

Mnemonic: SCASB - Compară conţinutul registrului AL cu conţinutul


locaţiei ES:DI şi poziţionează corespunzator flagurile
Acţiune: AL - ES:[DI];
DI← DI+1 dacă DF=0, DI← DI-1 dacă DF=1.

94
Mnemonic: SCASW - Compară conţinutul registrului AX cu conţinutul
locaţiilor ES:[DI] şi ES:[DI+1] şi poziţionează corespunzator flagurile
Acţiune: AL - ES:[DI];
AH - ES:[DI+1];
DI← DI+2 dacă DF=0, DI← DI-2 dacă DF=1.

Mnemonic: SCASD - Compară conţinutul registrului EAX cu conţinutul


locaţiilor ES:[DI], ES:[DI+1], ES:[DI+2] şi ES:[DI+3] şi poziţionează corespunzator
flagurile.
Acţiune: EAX1 - ES:[DI] - octetul cel mai puţin semnificativ al lui EAX;
EAX2 - ES:[DI+1] ;
EAX3 - ES:[DI+2] ;
EAX4 - ES:[DI+3] - octetul cel mai semnificativ al lui EAX;
DI← DI+4 dacă DF=0, DI← DI-4 dacă DF=1.

La aceste instrucţiuni operandul este întotdeauna în segmentul ES, şi nu este


posibilă schimbarea acestui segment.
Instrucţiunea SCASB compară octetul din locaţia de memorie cu adresa
ES:DI cu conţinutul lui AL şi poziţionează indicatorii de conditii în functie de
rezultatul comparării. Registrul DI va fi incrementat cu 1 dacă DF=0 şi decrementat
cu 1 dacă DF=1.
Instrucţiunea SCASW compară cuvântul punctat de locatia de memorie cu
adresa ES:DI (octetul inferior fiind la aceasta adresa, iar cel superior la cea
următoare), cu conţinutul lui AX şi poziţionează indicatorii de conditii în functie de
rezultatul comparării. Registrul DI va fi incrementat cu 2 dacă DF=0 şi decrementat
cu 2 dacă DF=1.
Instrucţiunea SCASD compară cuvântul punctat de locatia de memorie cu
adresa ES:DI (octetul inferior fiind la aceasta adresa, iar cel superior la cea de a treia
din cele care urmează), cu conţinutul lui EAX şi pozitioneaza indicatorii de conditii
în functie de rezultatul compararii. Registrul DI va fi incrementat cu 4 dacă DF=0 şi
decrementat cu 4 dacă DF=1.
In conformitate cu regulile aritmeticii în complement fata de 2 (numerele
negative au bitul cel mai semnificativ 1 iar scăderea cu rezultat negativ dă un
împrumut) , dacă numarul din memorie este mai mic decât cel din registru, indicatorii
C (transport la adunare şi împrumut la scadere) şi S (semn) se pozitioneaza în 1 .
Daca numarul din memorie este mai mare decât cel din cu cel din registru, indicatorii
C şi S se pozitioneaza în 0. Daca numarul din memorie este egal cu cel din registru,
se pozitioneaza în 1 indicatorul Z.

CMPS, CMPSB, CMPSW, CMPSD -compară două seturi de locaţii de


memorie

Mnemonic: CMPS dst,src - Compara conţinutul locatiilor (una, doua sau


patru) care incep la adresa DS:[SI] cu conţinutul aceluiaşi numar de locatii care încep
la adresa ES:[DI] şi poziţionează corespunzător flagurile.

dst,src: m8,m16,m32.

95
Acţiune: DS:[SI] - ES:[DI];
SI←SI +n dacă DF=0, SI←SI-n dacă DF=1;
DI←DI +n dacă DF=0, DI←DI-n dacă DF=1 unde n=1/2/4 în
funcţie de dimensiunea operanzilor.

Mnemonic: CMPSB - Compară conţinutul locaţiei DS:[SI] cu conţinutul


locaţiei ES:[DI] şi pozitionează corespunzător flagurile
Acţiune: DS:[SI] - ES:[DI];
SI←SI +1 dacă DF=0, SI←SI-1 dacă DF=1;
DI←DI +1 dacă DF=0, DI←DI-1 dacă DF=1.

Mnemonic: CMPSW - Compară conţinutul locatiilor DS:[SI] şi DS:[SI+1]


cu conţinutul locaţiilor ES:[DI] şi ES:[DI+1] şi poziţionează corespunzător flagurile

Acţiune: DS:[SI] - ES:[DI];


DS:[SI+1] - ES:[DI+1];
SI←SI +2 dacă DF=0, SI←SI-2 dacă DF=1;
DI←DI +2 dacă DF=0, DI←DI-2 dacă DF=1.

Mnemonic: CMPSD - Compară conţinutul a patru locaţii care încep la


adresa DS:[SI] cu conţinutul a patru locatii care încep la adresa ES:[DI] şi
pozitionează corespunzător flagurile
Acţiune: DS:[SI] - ES:[DI];
DS:[SI+1] - ES:[DI+1];
DS:[SI+2] - ES:[DI+2];
DS:[SI+3] - ES:[DI+3];
SI←SI +2 dacă DF=0, SI←SI-2 dacă DF=1;
DI←DI +2 dacă DF=0, DI←DI-2 dacă DF=1.

La aceste instrucţiuni operandul al doilea este întotdeauna în segmentul ES, şi


nu este posibila schimbarea acestui segment. Primul operand este implicit în
segmentul DS, dar se acest segment poate fi schimbat ( prin "segment override byte").
Pentru instrucţiunea de comparaţie CMPSB primul operand este locaţia de
memorie cu adresa efectivă dată de registrul index sursă SI şi adresa de segment dată
de DS iar al doilea operand este locaţia de memorie cu adresa efectivă data de
registrul index destinaţie DI şi adresa de segment data de ES.
Pentru instrucţiunea de comparatie CMPSW primul operand este dat de
locatiile de memorie cu adresele DS:[SI] (octetul inferior) şi DS:[SI+1] (octetul
superior) iar al doilea operand este dat de locatiile de memorie cu adresele ES:[DI]
(octetul inferior) şi ES:[DI+1] (octetul superior).
Pentru instrucţiunea de comparatie CMPSD primul operand este dat de patru
locatii de memorie care încep la adresa DS:[SI] (octetul inferior) şi se termină la DS:
[SI+1] (octetul superior), iar al doilea operand este dat de patru locatii de memorie
care încep la adresa ES:[DI] (octetul inferior) şi se termină la ES:[DI+1] (octetul
superior).
Pentru instrucţiunea de comparatie CMPS primul operand este dat de una
doua sau patru locatii de memorie care încep la adresa DS:[SI] (octetul inferior) şi se

96
termină iar al doilea operand este dat de patru locatii de memorie care încep la
adresa ES:[DI] (octetul inferior) şi se termină la ES:[DI+1] (octetul superior).
In urma efectuarii unei astfel de instrucţiuni, registrele index SI respectiv DI
se modifică în funcţie de starea flagului DF (de directie). Daca DF este 0, registrele
index vor fi incrementate cu 1 la CMPSB şi cu 2 la CMPSW. Daca DF este 1,
registrele index vor fi decrementate cu 1, respectiv cu 2.

A1.3.2. Ajustări zecimale pentru operaţii cu numere BCD

AAA - Ajustare în cod BCD despachetat a lui AL după adunare


Acţiune:
IF (AL AND OFH) > 9) OR (AF=1)
THEN
AL ← (AL + 6) AND OFH;
AH ← AH + 1;
AF ← 1;
CF ← 1;
ELSE
CF ← 0;
AF ← 0.
FI.
Descriere: Execuţia instrucţiunii AAA se face numai după instrucţiunea ADD
(sau ADC), care lasă rezultatul în registrul AL. Semiocteţii inferiori ai operanzilor
instrucţiunii de adunare trebuie să fie în intervalul 0...9. În acest caz, instrucţiunea
AAA ajustează registrul AX pentru a conţine rezultatul zecimal corect în format BCD
despachetat. Dacă adunarea a dus la un transport zecimal, registrul AH este
incrementat iar flagurile CF şi AF sunt setate. Dacă nu a fost transport zecimal,
flagurile CF şi AF sunt şterse iar AH rămâne neschimbat. În ambele cazuri, registrul
AL rămâne cu jumătatea superioară în 0 (BCD despachetat).
De exemplu, dacă AH=0 şi dacă AL=0Ah atunci AX devine 0100, dacă
AL=0Bh atunci AX devine 0101, dacă AL=0Ch atunci AX devine 0102, s.a.m.d.).
Dupa instrucţiunea AAA se poate obtine în AL rezultatul în cod ASCII
executând o instrucţiune OR AL,30h

AAS - Ajustare în cod BCD despachetat a lui AL după scădere


Acţiune:
IF (AL AND OFH) > 9) OR (AF=1)
THEN
AL ← AL - 6) AND OFH;
AH ← AH - 1;
AF ← 1;
CY ← 1;
ELSE
CF ← 0;
AF ← 0
FI.
Descriere: Execuţia instrucţiunii AAS se face numai după instrucţiunea SUB
(sau SBB), care lasă rezultatul în registrul AL. Semiocteţii inferiori ai operanzilor
instrucţiunii de scădere trebuie să fie în intervalul 0...9. În acest caz, instrucţiunea

97
AAS ajustează registrul AX pentru a conţine rezultatul zecimal corect în format BCD
despachetat Dacă scaderea a dus la un transport zecimal, registrul AH este
decrementat iar flagurile CF şi AF sunt setate. Dacă nu a fost transport zecimal,
flagurile CF şi AF sunt şterse iar AH rămâne neschimbat. În ambele cazuri, registrul
AL rămâne cu jumătatea superioară în 0 (BCD despachetat).
Dupa instrucţiunea AAA se poate obtine în AL rezultatul în cod ASCII
executând o instrucţiune OR AL,30h

DAA - Ajustare AL după adunare (BCD împachetat)


Acţiune:
IF (AL AND OFH) > 9) OR (AF=1)
THEN
AL ← AL + 6;
AF ← 1;
ELSE
AF ← 0;
FI
IF (AL> 9FH) OR (CF=1)
THEN
AL ← AL +60H;
CF ← 1;
ELSE
CF ← 0;
FI.
Descriere: Execuţia instrucţiunii DAA se face numai după instrucţiunea ADD
(sau ADC), care lasă un rezultat de doi digiţi BCD împachetat în registrul AL. Cei
doi operanzi ai instrucţiunii de adunare trebuiau să fi fost de asemenea în format
BCD împachetat pe câte doi digiţi. În acest caz, instrucţiunea DAA ajustează registrul
AL pentru a conţine cele două cifre BCD împachetat corecte ale rezultatului.

DAS - Ajustare AL după scadere (BCD împachetat)


Acţiune:
IF (AL AND OFH) > 9) OR (AF=1)
THEN
AL ← AL - 6;
AF ← 1;
ELSE
AF ← 0;
FI
IF (AL> 9FH) OR (CF=1)
THEN
AL ← AL -60H;
CF ← 1;
ELSE
CF ← 0;
FI.

Descriere: Execuţia instrucţiunii DAA se face numai după instrucţiunea SUB


(sau SBB), care lasă un rezultat de doi digiţi BCD împachetat în registrul AL. Cei doi

98
operanzi ai instrucţiunii de scadere trebuiau să fi fost de asemenea în format BCD
împachetat pe câte doi digiţi. În acest caz, instrucţiunea DAS ajustează registrul AL
pentru a conţine cele două cifre BCD împachetat corecte ale rezultatului.

AAM - Ajustare AL după înmulţire


Acţiune: AH ← AL/10;
AL ← AL modulo 10.

Descriere: Execuţia instrucţiunii AAM se face numai după instrucţiunea MUL


între două cifre BCD despachetate (fiecare ocupă câte un octet), care lasă rezultatul
în registrul AX. Deoarece rezultatul este mai mic de 100, el este conţinut integral în
registrul AL. Instrucţiunea AAM despachetează rezultatul din AL prin împărţire cu
10, lăsând câtul (cifra cea mai semnificativă) în AH, şi restul (cifra mai puţin
semnificativă) în registrul AL.

AAD - Ajustare AL înainte de împărţire;


Acţiune:
AL ← AH * 10 + AL;
AH ← 0.
Instrucţiunea AAD este folosită pentru a pregăti doua cifre în format BCD
despachetat (cifra mai putin semnificativa în AL şi cea mai semnificativa în AH)
pentru o împărţire care va genera un rezultat în format BCD despachetat. Aceasta se
realizează dând lui AL valoarea AL+(10*AH) şi lui AH valoarea 0. AX va deveni
egal deci cu echivalentul binar al numărului initial de doua cifre BCD despachetat.

A1.3.3. Deplasări şi rotaţii

SHL src,[nr]-Deplasare logică spre stânga cu nr poziţii (numere fără semn)


Acţiune:

C MSB LSB
0
Operanzi: -src:r8,r16,r32,m8,m16,m32;
-[nr]: 1, CL,imm8.
Descriere: Operandul src este înmulţit cu 2 de [nr] ori.

SHR src,[nr]-Deplasare logica spre dreapta cu nr poziţii (numere fără semn)


Acţiune:
MSB LSB C
0

99
Operanzi: -src:r8,r16,r32,m8,m16,m32;
-[nr]: 1, CL,imm8.
Descriere: Operandul src este împărţit cu 2 de [nr] ori.

SAL src,[nr]-Deplasare aritmetica spre stânga cu nr poziţii (numere cu


semn)
Acţiune:
C MSB LSB
0

Operanzi: -src:r8,r16,r32,m8,m16,m32;
-[nr]: 1, CL,imm8.
Descriere: Operandul src cu semn este înmulţit cu 2 de [nr] ori. Instrucţiunea
este echivalentă cu instrucţiunea SHL

SAR src,[nr]-Deplasare aritmetică spre dreapta cu nr poziţii (numere cu


semn)
Acţiune:
MSB LSB C

Operanzi: -src:r8,r16,r32,m8,m16,m32;
-[nr]: 1, CL,imm8.
Descriere: Operandul src cu semn este împărţit cu 2 de [nr] ori.

ROL src,[nr]-Rotaţie prin carry spre stânga cu [nr] poziţii


Acţiune:
C MSB LSB

Operanzi: -src:r8,r16,r32,m8,m16,m32;
-[nr]: 1, CL,imm8.

ROR src,[nr]-Rotaţie prin carry spre dreapta cu [nr] poziţii


Acţiune:
MSB LSB C

Operanzi: -src:r8,r16,r32,m8,m16,m32;
-[nr]: 1, CL,imm8.

RCL src,[nr]-Rotaţie cu carry spre stânga cu [nr] poziţii


Acţiune:
C MSB LSB

100
Operanzi: -src:r8,r16,r32,m8,m16,m32;
-[nr]: 1, CL,imm8.

RCR src,[nr]-Rotaţie cu carry spre dreapta cu [nr] poziţii


Acţiune:
MSB LSB C

Operanzi: -src:r8,r16,r32,m8,m16,m32;
-[nr]: 1, CL,imm8.
Descriere: Fiecare instrucţiune de rotaţie ROL şi ROR deplasează biţii
operandului src (registru sau locaţie de memorie). Instrucţiunile de rotaţie spre stânga
deplasează toţi biţii către poziţia cea mai semnificativă (către MSB), exceptând bitul
din poziţia cea mai semnificativă, care este mutat în poziţia cea mai puţin
semnificativă (LSB). Instrucţiunile de rotaţie spre dreapta acţionează invers: biţii sunt
deplasaţi către poziţia cea mai puţin semnificativă iar bitul din poziţia cea mai puţin
semnificativă ajunge în poziţia cea mai semnificativă.
Pentru instrucţiunile RCL şi RCR, flagul CF este o parte a cantităţii rotite.
Instrucţiunea RCL deplasează flagul CF în bitul cel mai puţin semnificativ şi cel mai
semnificativ bit în flagul CF; instrucţiune a RCR deplasează flagul CF în bitul cel mai
semnificativ şi bitul cel mai semnificativ în flagul CF. La instrucţiunile ROL şi ROR,
valoarea flagului CF nu este parte a rezultatului, dar flagul CF recepţionează o copie a
bitului care a fost deplasat de la un capăt la altul.
Rotaţia este repetată de un număr de ori indicat de al doilea operand, care este
1, o valoare imediata de 8 biţi, sau conţinutul registrului CL.
Numarul de deplasari maxim admis este de 31; dacă se specifică [n] mai mare,
se trunchiază automat la cei mai putin semnificativi 5 biţi.
Flagul OF este definit numai pentru forme cu o singură rotaţie ale in-
strucţiunilor (al doilea operand este un 1). Este nedefinit în toate celelalte cazuri.
Pentru deplasări/rotiri spre stânga, bitul CF de după deplasare este "sau-exclusivat"
cu bitul rezultat de cel mai înalt ordin, spre a rezulta flagul OF. Pentru deplasări/rotiri
spre dreapta, cei doi biţi cu cel mai înalt ordin ai rezultatului sunt "sau-exclusivaţi"
spre a rezulta flagul OF.

SHLD dst,src,[n] - deplasare stânga cu dublă precizie

C MSB dst LSB MSB src LSB

Operanzi: -src:r16,r32,m16,m32;
-[nr]: 1, CL,imm8.

Descriere: Conţinutul dst (registru sau locaţie de memorie) este deplasat spre
stânga de [n] ori împreună cu registrul src, ai cărui biţi pătrund în dst. Registrul src
rămâne neschimbat. Bitul CF ia valoarea ultimului bit care a fost deplasat din MSB al
dst.

101
Deoarece bitii care vor intra prin deplasare în dst sunt proveniţi de la un alt registru,
aceasta instrucţiune este utilă pentru deplasari cu dubla precizie (pe 64 de biţi)

SHRD dst,src,[n]- deplasare dreapta cu dubla precizie

MSB src LSB MSB dst LSB C

Operanzi: -src:r16,r32,m16,m32;
-[nr]: 1, CL,imm8.

Descriere: Conţinutul dst (registru sau locaţie de memorie) este deplasat spre
dreapta de [n] ori împreună cu registrul src, ai cărui biţi pătrund în dst. Registrul src
rămâne neschimbat. Bitul CF ia valoarea ultimului bit care a fost deplasat din MSB al
dst.
Deoarece bitii care vor intra prin deplasare în dst sunt proveniţi de la un alt
registru, aceasta instrucţiune este utilă pentru deplasări cu dublă precizie (pe 64 de
biţi).

A1.4 Instrucţiuni de lucru pe bit

CLC - ştergere flag transport (CF = 0)


STC - setare flag transport (CF = 1)
CMC - complementarea transport (CF = NOT CF)

CLD - stabilire direcţie crescătoare (DF = 0)


Dupa aceasta instrucţiune, la operatiile cu siruri registrele index vor fi
incrementate.
STD - stabilire direţie descrescătoare (DF 1)
Dupa aceasta instrucţiune, la operatiile cu siruri registrele index vor fi
decrementate.

STI - activare întreruperi (IF = 1)


CLI - dezactivare întreruperi (IF = 0)

BT - Testare bit (Copiere bit în CF)


Mnemonic: BT dst,src
dst: r16,r32,m16,m32;
src: r16,r32,imm8.
Acţiune: CF← Bit( Baza, index).
Descriere: Primul operand specifică baza iar al doilea indexul. Bitul cu
indexul dat de ala doilea operand din registrul sau locatia de memorie specificată de
primul operand este copiat în CF. Daca baza este un registru, indexul este ajustat
automat modulo 16 sau modulo 32 în functie de marimea registrului. Daca baza este
o locaţie de memorie, ea reprezintă adresa locaţiei de memorie care conţine bitul cu
index 0. Sunt posibile valori ale indexului între -2 31 şi 231-1 dacă al doilea operand
este un registru sau între 0 şi 31 dacă al doilea operand este o valoare imediata.

102
BTR - Testare bit şi resetare (Copiere bit în CF şi resetare)
Mnemonic: BT dst,src
dst: r16,r32,m16,m32;
src: r16,r32,imm8.

Acţiune: CF← Bit( Baza, index)


Bit( Baza, index)← 0.

Descriere: Primul operand specifică baza iar al doilea indexul. Bitul cu


indexul dat de al doilea operand din registrul sau locaţia de memorie specificată de
primul operand este copiat în CF, dupa care este resetat (adus la 0). Daca baza este un
registru, indexul este ajustat automat modulo 16 sau modulo 32 în functie de marimea
registrului. Daca baza este o locaţie de memorie, ea reprezintă adresa locaţiei de
memorie care conţine bitul cu index 0. Sunt posibile valori ale indexului între -2 31 şi
231-1 dacă al doilea operand este un registru sau între 0 şi 31 dacă al doilea operand
este o valoare imediată.

BTS - Testare bit şi setare (Copiere bit în CF şi setare)


Mnemonic: BT dst,src
dst: r16,r32,m16,m32;
src: r16,r32,imm8.

Acţiune: CF← Bit( Baza, index)


Bit( Baza, index)← 1.

Descriere: Primul operand specifică baza iar al doilea indexul. Bitul cu


indexul dat de ala doilea operand din registrul sau locatia de memorie specificată de
primul operand este copiat în CF, dupa care este setat (adus la 1). Daca baza este un
registru, indexul este ajustat automat modulo 16 sau modulo 32 în functie de marimea
registrului. Daca baza este o locaţie de memorie, ea reprezintă adresa locaţiei de
memorie care conţine bitul cu index 0. Sunt posibile valori ale indexului între -2 31 şi
231-1 dacă al doilea operand este un registru sau între 0 şi 31 dacă al doilea operand
este o valoare imediata.

BTC - Testare bit şi complementare (Copiere bit în CF şi complementare)


Mnemonic: BT dst,src
dst: r16,r32,m16,m32;
src: r16,r32,imm8.
Acţiune: CF← Bit( Baza, index);
Bit( Baza, index)← NOT Bit( Baza, index).
Descriere: Primul operand specifică baza iar al doilea indexul. Bitul cu
indexul dat de ala doilea operand din registrul sau locatia de memorie specificată de
primul operand este copiat în CF, dupa care este complementat (ia valoarea opusă).
Daca baza este un registru, indexul este ajustat automat modulo 16 sau modulo 32 în
functie de marimea registrului. Daca baza este o locaţie de memorie, ea reprezintă
adresa locaţiei de memorie care conţine bitul cu index 0. Sunt posibile valori ale
indexului între -231 şi 231-1 dacă al doilea operand este un registru sau între 0 şi 31

103
dacă al doilea operand este o valoare imediată.

BSF - Scanare înainte a biţilor


Mnemonic: BSF dst,src
dst: r16,r32;
src: r16,r32,m16,m32.
Acţiune: dst←index(src,0).
Descriere: Bitii din src sunt testaţi pe rand incepând cu cel mai putin
semnificativ, şi dacă toti sunt 0 este sters flagul ZF. Daca vreunul este găsit în 1,
indexul sau incepând de la 0 este scris în dst.

BSF - Scanare înapoi a bitilor


Mnemonic: BSR dst,src
dst: r16,r32;
src: r16,r32,m16,m32.
Acţiune: dst←index(src,0).
Descriere: Bitii din src sunt testaţi pe rand începand cu cel mai semnificativ,
şi dacă toti sunt 0 este sters flagul ZF. Daca vreunul este găsit în 1, indexul sau
începand de la 0 este scris în dst.

SETcc - Setează octet dacă condiţia cc este indeplinită


Instrucţiunea are una din urmatoarele forme:

SETA r/m8 Setează octetul dacă este peste (CF=0 and ZF=0)
SETAE r/m8 Setează octetul dacă este peste sau egal (CF=0)
SETB r/m8 Setează octetul dacă este sub (CF=1)
SETBE r/m8 Setează octetul dacă este sub sau egal (CF=1 or (ZF=1)
SETC r/m8 Setează octetul dacă este transport (CF=1)
SETE r/m8 Setează octetul dacă este egal (ZF=1)
SETG r/m8 Setează octetul dacă este mai mare (ZF=0 or SF=OF)
SETGE r/m8 Setează octetul dacă este mai mare sau egal (SF=OF)
SETL r/m8 Setează octetul dacă este mai mic (SF←>OF)
SETLE r/m8 Setează octetul dacă este mai mic sau egal (ZF=1 şi SF←>OF)
SETNA r/m8 Setează octetul dacă nu este peste (CF=1)
SETNAE r/m8 Setează octetul dacă nu este peste sau egal (CF=1)
SETNB r/m8 Setează octetul dacă nu este sub (CF=0)
SETNBE r/m8 Setează octetul dacă nu este sub sau egal (CF=0 şi ZF=0)
SETNC r/m8 Setează octetul dacă nu este transport (CF=0)
SETNE r/m8 Setează octetul dacă nu este (ZF=0)
SETNG r/m8 Setează octetul dacă nu este mai mare (ZF=1 or SF←>OF)
SETNGE r/m8 Setează octetul dacă nu este mai mare sau egal (SF←>OF)
SETNL r/m8 Setează octetul dacă nu este mai mic (SF=OF)
SETNLE r/m8 Setează octetul dacă nu este mai mic sau egal (ZF=1 şi SF←>OF)
SETNO r/m8 Setează octetul dacă nu este overflow (OF=0)
SETNP r/m8 Setează octetul dacă nu este paritate (PF=0)
SETNS r/m8 Setează octetul dacă semnul este 0 (SF=0)
SETNZ r/m8 Setează octetul dacă nu este zero (ZF=0)
SETO r/m8 Setează octetul dacă este overflow (OF=1)
SETP r/m8 Setează octetul dacă este paritate (PF=1)
SETPE r/m8 Setează octetul dacă este paritate pară (PF=1)

104
SETPO r/m8 Setează octetul dacă este paritate impară (PF=0)
SETS r/m8 Setează octetul dacă semnul este 1 (SF=1)
SETZ r/m8 Setează octetul dacă este zero (ZF=1)

Descriere: Daca condiţia este îndeplinită, atunci operandul (registru de 8 biţi


sau locaţie de memorie) devine 1. Daca nu, acesta devine 0.

A1.5. Instrucţiuni de ramificare în program

JMP adr - salt necondiţionat

adr: r16,r32,m16,m32,rel8,rel16,rel32,ptr16:16,ptr16:32,m16:16,m16:32.

Descriere: Instrucţiunea JMP transfera controlul catre un alt punct în lanţul de


instrucţiuni fără a se memora adresa de revenire. Operandul adr (ţinta) specifică
adresa instrucţiunii la care se sare. Acest operand poate fi o valoare imediată, un
registru de uz general sau o locaţie de memorie.
Aceasta instrucţiune poate executa patru tipuri diferite de salturi:
 Salt apropiat (near) - Un salt catre o instrucţiune din segmentul de cod curent,
segment indicat de conţinutul curent al registrului CS), numit şi salt
intrasegment.
 Salt scurt (short) - Un salt apropiat la care deplasamntul este limitat intre -128
şi +127 fata de valoarea curenta a EIP

 Salt indepărtat (far) - UN salt catre o instrucţiune aflata intr-un segment


diferit de segmentul curent de cod, dar cu acelasi nivel de privilegii, numit şi
salt intersegment
 Task switch - Un salt catre o instrucţiune aflata intr-un alt task (posibil numai
în modul virtual protejat - v. [2] )

Salturile apropiate şi scurte. Cănd se execută un salt apropiat, procesorul


sare la adresa (din segmentul de cod curent) care este specificată de operandul ţintă.
Acesta specifică fie un deplasament absolut (faţă de baza segmentului de cod) fie un
deplasament relativ (o valoare cu semn faţă de valoarea curentă a număratorului de
program).Registrul CS nu se modifică la astfel de salturi.
Un deplasamet absolut este specificat indirect printr-un registru general sau o
locaţie de memorie (operandul este r16/m16 sau r32/m32).Un deplasament absolut se
încarcă direct în EIP. Marimea operandului determină şi conţinutul EIP; dacă acesta
este de 16 biţi, cei 16 biţi superiori din EIP sunt puşi în 0, rezultand un deplasament
care nu depaşeşte 16 biţi.
Un deplasament relativ este în general specificat în limbaj de asamblare
printr-o etichetă, dar la nivel de cod masină acesta este decodificat ca o valoare
imediată cu semn, de 8, 16 sau 32 de biţi. Aceasta valoare este adunată la valoarea din
EIP, adică la adresa instrucţiunii imediat urmatoare celei de salt.

Salturi îndepărtate în modul Real sau Virtual 8086. Când se execută un


salt îndepărtat în modul Real sau Virtual 8086, procesorul sare la un segment de cod
şi un deplasament specificat de operandul instrucţiunii. Acesta specifică o adresa

105
absolută departată, fie direct printr-un pointer (ptr16:16 sau ptr16:32) fie indirect
printr-o locaţie de memorie (m16:16 sau m16:32).
In varianta cu pointer, segmentul şi deplasamentul adresei la care se sare sunt
specificate de instrucţiune printr-o valoare imediata de 4 octeţi (operand de 16 biţi)
sau de 6 octeţi (operand de 32 de biţi).
In varianta indirectă, operandul specifică o locaţie de memorie care conţine 4
octeţi (operand de 16 biţi) sau 6 octeţi (operand de 32 de biţi).
Adresa îndepărtată este încărcată direct în registrele CS (primii doi octeţi) şi
EIP (uramătorii 2 sau 4 octeţi). Daca operandul este de 16 biţi, cei 16 biţi superiori
din EIP sunt pusi în 0, rezultand un deplasament care nu depaseste 16 biţi.

Jcc adr - Salt condiţionat

adr: rel8,rel16,rel32.

Descriere: Instrucţiunea Jcc transferă controlul catre un alt punct în lanţul de


instrucţiuni fără a se memora adresa de revenire, numai dacă este indeplinită condiţia
cc. Dacă aceasta condiţie nu este indeplinită, se conţinuă cu instrucţiunea imediat
urmatoare. Operandul adr (ţintă) specifică adresa instrucţiunii la care se sare. Acest
operand este un deplasament relativ. In general, în limbaj de asamblare,
deplasamentul relativ este specificat printr-o etichetă, dar la nivel de cod masină
acesta este decodificat ca o valoare imediata cu semn, de 8, 16 sau 32 de biţi. Aceasta
valoare este adunată la valoarea din EIP, adica la adresa instrucţiunii imediat
urmatoare celei de salt.
Aceasta instrucţiune poate executa două tipuri diferite de salturi:
 Salt apropiat (near) - Un salt catre o instrucţiune din segmentul de cod curent,
segment indicat de conţinutul curent al registrului CS), numit şi salt
intrasegment.
 Salt scurt (short) - Un salt apropiat la care deplasamntul este limitat între -128
şi +127 fata de valoarea curentă a EIP
În funcţie de rezultatul operaţiei aritmetice sau logice precedente (care
modifică anumiţi indicatori de conditii) pot exista următoarele forme de instrucţiuni
de salt conditionat:

JP adr (JPE adr) - salt condiţionat de paritate pară. (PF=1)


JNP adr (JPO adr) - salt condiţionat de paritate impară (PF=0)
JO adr - salt condiţionat de OF = 1 - a fost depăşire.
JNO adr - salt condiţionat de OF = 0 - nu a fost depăşire.
JS adr - salt condiţionat de SF = 1 - rezultatul a fost negativ.
JNS adr - salt condiţionat de SF = 0 - rezultatul a fost pozitiv.
JE adr (JZ adr) - salt condiţionat de ZF = 1 - egalitate la comparaţia anterioară.
JNE adr (JNZ adr) - salt condiţionat de ZF = 0 - inegalitate la comparaţia anterioară.

Salturi condiţionate de comparaţii ale unor numere cu semn:

JL adr (JNGE adr) - salt condiţionat de SF ≠ OF (SF xor OF = 1) - mai mic la


comparaţia anterioară a unor valori cu semn.
JLE adr (JNG adr) - salt condiţionat de ZF = 1 sau SF ≠ OF - mai mic sau egal la
comparaţi a anterioară a unor valori cu semn.

106
JG adr (JNLE adr) - sat condiţionat de ZF = 0 şi SF = OF - mai mare la comparaţia
anterioară a unor valori cu semn.
JGE adr (JNL adr) - salt condiţionat de SF = OF - mai mare sau egal la comparaţia
anterioară a unor valori cu semn.

Salturi condiţionate de comparaţii ale unor numere fara semn:

JB adr (JNAE adr, JC adr) - salt condiţionat de CF = 1 - mai mic la comparaţia


anterioară a unor valori cu fara semn sau transport la operaţia anterioară.
JBE adr (JNA adr) - salt condiţionat de CF = 1 sau ZF = 1 - mai mic sau egal la
comparaţia anterioară a unor valori fără semn.
JA adr (JNBE adr) – salt condiţionat de CF = ZF = 0 – mai mare la comparaţia
anterioara a unor valori fără semn.
JAE adr (JNB adr, JNC adr) – salt condiţionat de CF = 0 – mai mare sau egal la
comparaţia anterioară a unor valori fără semn sau nu există transport la operaţia
anterioară.

JCXZ – salt condiţionat de conţinutul lui CX = 0.Deplasament numai pe 8 biţi.


JECXZ – salt condiţionat de conţinutul lui ECX = 0.Deplasament numai pe 8 biţi.

LOOP, LOOPE,(LOOPZ),LOOPNE(LOOPNZ)

Mnemonic: LOOP, LOOPE,(LOOPZ),LOOPNE(LOOPNZ)

Descriere: Instrucţiunea LOOP decrementează contorul CX sau ECX fără să


schimbe flagurile. Apoi sunt testate condiţiile specificate de forma LOOP folosită.
Dacă condiţia este îndeplinită, se face un salt scurt (domeniul –128 până la +127) la
eticheta dată de operandul instrucţiunii LOOP. Acest lucru se repetă până când
contorul ajunge la 0 sau până când condiţia nu mai este îndeplinită. Daca atributul de
lungime al operandului este 16 biţi contorul va fi CX, iar dacă este de 32 de biţi
contorul va fi ECX .
Instrucţiunea LOOP permite controlul iteratiilor prin combinarea
decrementarii automate a indexului cu saltul conditionat. Se foloseste introducând în
registrul contor (CX sau ECX) numarul fără semn al iteratiilor şi punând
instrucţiunea LOOP la sfârsitul seriei de instrucţiuni care vor fi repetate. Operandul
instrucţiunii LOOP este eticheta de la inceputul secventei care se va repeta.

LOOP – Repetare de CX ori a secvenţei


Mnemonic : LOOP rel8.
Operand: n: număr cu semn pe 8 biţi.
Acţiune: CX ← CX - 1;
dacă CX ≠ 0 atunci IP ← IP + n.
Se repetă secvenţa de instrucţiuni de lungime n octeţi, marcată cu un capăt de
instrucţiunea LOOP până când CX = 0. Lungimea fiind dată de un număr cu semn,
poate fi cuprinsă între -128 şi +128 octeţi.

LOOPZ (sau LOOPE) – Repetare de CX ori a secvenţei, condiţionată de


ZF = 1
Mnemonic: LOOPZ rel8.
107
Operand: n: număr cu semn pe 8 biţi.
Acţiune: CX ← CX – 1;
dacă ZF =1 şi CX ≠ 0 atunci IP ← IP + n.
Se repetă secvenţa de instrucţiuni de lungime n octeţi, marcată cu un capăt de
instrucţiunea LOOP până când CX = 0, dar numai cât timp ZF =1. Orice resetare a
fanionului ZF duce la ieşirea forţată din ciclu. Lungimea fiind dată de un număr cu
semn, poate fi cuprinsă între -128 şi +128 octeţi.

LOOPNZ (sau LOOPNE)–Repetare de CX ori a secvenţei, condiţionată de


ZF = 0.
Mnemonic: LOOPNZ rel8
Operand: n: număr cu semn pe 8 biţi.
Acţiune: CX ← CX -1;
dacă ZF = 0 şi CX ≠ 0 atunci IP ← IP + n.
Se repetă secvenţa de instrucţiuni de lungime n octeţi, marcată cu un capăt de
instrucţiunea LOOP până când CX = 0, dar numai cât timp ZF = 0. Orice resetare a
fanionului ZF duce la ieşirea forţată din ciclu. Lungimea fiind dată de un număr cu
semn, poate fi cuprinsă între -128 şi +128 octeţi.

CALL adr - apel de subrutină

Descriere: Instrucţiunea CALL conduce la execuţia subrutinei (procedurii) al


carei nume este specificat de operand. Când aceasta procedură s-a terminat (apare o
instrucţiune RET de reîntoarcere), execuţia programului continuă cu instrucţiunea
imediat următoare instrucţiunii CALL.

Acţiune: Există doua variante ale acestei instrucţiuni, a caror Acţiune este
urmatoarea:

CALL apropiat (near). Sunt acele apeluri de proceduri care au operandul de


tip r16, m16, r232, m32, rel16 şi rel32, care se execută în interiorul aceluiasi segment.
Prin urmare, schimbarea şi salvarea registrului de segment de cod nu este necesara.
Formele CALL rel16 şi CALL rel32 aduna un deplasament cu semn la
conţinutul lui EIP (adresa instrucţiunii care urmeaza lui CALL), pentru a determina
destinaţia. Marimea operandului determina şi conţinutul EIP; dacă acesta este de
numai 16 biţi, cei 16 biţi superiori din EIP sunt pusi în 0, rezultand un deplasament
care nu depaseste 16 biţi.
Formele CALL r16/m16 şi CALL r32/m32 specifică un registru sau o adresa
de memorie de unde se extrage deplasamentul absolut fata de baza segmentului
(adresa efectiva). Marimea operandului determina şi marimea deplasamentului extras.
Valoarea curenta a lui EIP (adresa instrucţiunii imediat urmatoare lui CALL)
este salvată în stivă înainte de incărcarea EIP cu noua adresă efectivă (deplasament
faţă de baza segmentului). Aceasta va fi readusă în EIP de instrucţiunea RET cu care
se termina subrutina.

CALL indepărtat (far). Formele CALL ptr16:16 şi CALL ptr 16:32 folosesc
un pointer de 4 sau 6 octeţi catre subrutina chemată. Formele CALL m16:16 şi CALL
m16:32 extrag pointerul respectiv din locatia de memorie specificata. In modul Real
sau Virtual 8086, pointerul da 16 biţi pentru registrul CS şi restul de 16 sau 32 de biţi

108
pentru registrul EIP. Instrucţiunile CALL indepărtat salvează în stiva şi registrul CS
şi registrul IP (sau EIP).

RET – reântoarcere din subrutină


Mnemonic: RET
RET n
Descriere: Instrucţiunea RET produce reîntoarcerea dintr-o subrutină prin
transferarea controlului la instrucţiunea a cărei adresa se află în stivă. Acestă adresa
este în mod normal plasată în stivă de o instrucţiune CALL, iar reîntoarcerea se face
la instrucţiunea imediat următoare acesteia.
Parametrul numeric opţional al instrucţiunii RET da numarul de octeţi din
stivă (dacă operandul e pe 16 biţi) sau de cuvinte (dacă operandul e pe 32 de biţi) care
să fie eliberaţi după ce este extrasă adresa de reîntoarcere.
Pentru o reîntoarcere intrasegment (apropiată), adresa extrasă din stivă este un
deplasament faţă de baza segmentului (adresa efectivă) care va fi încarca în IP.
Registrul CS ramâne neschimbat.
Pentru o reîntoarcere intersegment (îndepărtată), adresa extrasă din stivă este
un pointer. Mai întâi este extras deplasamentul şi încarcat în IP iar apoi adresa de
segment şi încarcata în CS.

INT – apelare întrerupere software


Mnemonic: INT n
INTO
Descriere: Instrucţiunea INT genereaza o chemare prin software a unei
subrutine de tratare a unei intreruperi. Operandul imediat, cuprins între 0 şi 255 da
indexul în tabela de intreruperi al subrutinei care este chemată. În modul Real, aceasta
tabelă cuprinde pointeri de căte 4 octeţi
Întreruperea condiţionată INTO este identică cu INT, dar operandul implicit
este 4, şi poate apare numai dacă flagul Overflow este setat.
Primele 32 de întreruperi sunt rezervate de Intel pentru utilizări speciale.
Unele dintre ele sunt folosite de excepţiile generate intern de procesor.
INT se comportă în principiu ca un CALL (far) dar înainte de a se salva în
stivă adresa de reintoarcere, se salvează şi registrul de flaguri. Subrutinele de tratare a
întreruperilor se încheie cu instrucţiunea IRET care aduce din stivă şi adresa de
reintoarcere şi conţinutul registrului de flaguri
Instrucţiunea INT este folosită frecvent pentru apelarea unor subrutine
standard din BIOS sau din sistemul de operare (vezi anexele 2 şi 3), care pot realiza
foarte eficient o serie de acţiuni de largă răspândire.

IRET – reîntoarcere din întrerupere

Descriere: In modul Real, instrucţiunea IRET extrage din stivă adresa de


reîntoarcere din subrutina de tratare a unei intreruperi, precum şi registrul de flaguri.
Aceasta are ca efect revenirea în program la instrucţiunea imediat urmatoare celei
care a precedat întreruperea, cu reactivarea întreruperilor (acceptarea unei cerei de
întrerupere sterge flagul de întreruperi). Ca alternativă, dacă s-ar folosi la sfârşitul
rutinei de întrerupere o instrucţiune de tip RET, aceasta ar trebui precedată de o
instrucţiune STI pentru reactivarea intreruperilor.

109
A1.6. Instrucţiuni speciale

HLT - oprirea oricărei activităţi a procesorului. Se poate ieşi numai cu


RESET sau întrerupere hard. Daca se iese din aceasta stare cu o intrerupere (inclusiv
NMI), programul conţinuă cu instrucţiunea imediat următoare instrucţiunii HLT.

NOP - Instrucţiune fără operaţie.

110
ANEXA 2

Lista serviciilor de ecran INT 10h

Întreruperea 10h pune la dispoziţia programatorului următoarele servicii


pentru lucrul cu ecranul :
 00h - Stabilire mod video;
 01h - Stabilire dimensiune cursor;
 02h - Stabilire poziţie cursor;
 03h - Citeşte cursor;
 04h - Citeşte poziţia creionului grafic;
 05h - Selectează pagina video;
 06h - Scroll în sus;
 07h - Scroll în jos;
 08h - Citeşte carcter şi atributul;
 09h - Scrie carcter şi atributul;
 0Ah -Scrie caracter numai la cursor;
 0Bh - Stabilire chenar şi paletă;
 0Ch - Scrie pixel;
 0Dh - Citeşte pixel;
 0Eh - Scrierea caracterului în modul Teletype (TTY);
 0Fh - Citeşte modul video curent;
 10h - Setarea regiştrilor paletei la EGA /VGA;
 11h - Generatorul de caractere EGA;
 12h - Funcţii speciale EGA;
 13h - Scrierea unui şir de caractere;
 14h - Utilizarea LCD;
 15h - Citeşte caracteristicile fizice ale adaptorului grafic.

Aceste servicii sunt prezentate detailat în continuare. Deşi oferă şi posibilităţi


de scriere pe ecran, nu este recomandată utilizarea acestora datorită vitezei reduse.
Variante mai performante sunt cele care folosesc INT 21h şi mai ales cele cu scriere
directă în memoria de ecran.

111
INT 10h, 00h (0) Stabilire mod video
Intrări: AH 00h;
AL Modul video.

Rezultate: Nici unul.


Registre modificate: AX, SP, BP, SI, DI.

------------------------------------------------------------------
Tabelul modurilor video
Adresa de
Mod Tip Rezoluţia Adaptor Culori memorie

00h Text 40 x 25 All but MDA 16 gray B8000


01h Text 40 x 25 All but MDA 16 fore/8 back B8000
02h Text 80 x 25 All but MDA 16 gray B8000
03h Text 80 x 25 All but MDA 16 fore/8 back B8000
04h Graphics 320 x 200 All but MDA 4 B8000
05h Graphics 320 x 200 All but MDA 4 gray B8000
06h Graphics 640 x 200 All but MDA 2 B8000
07h Text 80 x 25 MDA,EGA b/w B0000
08h Graphics 160 x 200 PCjr 16 B0000
09h Graphics 320 x 200 PCjr 16 B0000
0Ah Graphics 640 x 200 PCjr 4 B0000
0Bh Reserved (internal to EGA)
0Ch Reserved (internal to EGA)
0Dh Graphics 320 x 200 EGA 16 A0000
0Eh Graphics 640 x 200 EGA 16 A0000
0Fh Graphics 640 x 350 EGA b/w A0000
10h Graphics 640 x 350 EGA 16 A0000
------------------------------------------------------------------
Observaţii
Atunci cand modul video se schimbă, ecranul se şterge automat.
Totuşi, nu se recomandă folosirea acestui serviciu pentru ştergerea
ecranului deoarece este mai lent decât serviciile normale de
stergere a ecranului (serviciile 06h sau 07h).
Pentru a evita ştergerea ecranului se va chema întreruperea cu
bitul cel mai semnificativ din AL în 1.
În modul grafic, cursorul nu este afişat (el poate fi totuşi
citit).
Schimbarea modului video schimbă şi dimensiunea cursorului.
Se poate folosi serviciul 0Fh al întreruperii 10h pentru a
citi modul video curent.

Vezi şi : INT 10h, 06h INT 10h, 07h INT 10h, 0Fh.

INT 10h, 01h (1) - Stabilire dimensiune cursor


Ajustează dimensiunea cursorului prin stabilirea liniei de
început şi de sfârşit.

Intrări: AH 01h;
CH Linia de început a cursorului (0 - 31);

112
CL Linia de sfârşit a cursorului (0 - 31).

Rezultate: Nici unul.

Registre modificate: AX, SP, BP, SI, DI.

Valorile liniilor de început şi sfârşit ale cursorului (CH si CL)

Permise Implicite
Adaptor Început Sfârşit Început Sfârşit
CGA 0 7 6 7
MDA 0 13 11 12
7(12) Depinde de
EGA, VGA 0 13 6(11)
mod

Observaţii:
Numerotarea liniilor începe din partea superioară a blocului
unui caracter (0) şi creşte în jos. Dacă se specifică o linie de
sfârşit cu un număr mai mic decât al celei de început, cursorul va
apare format din două linii conform principiului: după ultima linie
a blocului de caracter urmează prima linie.
Punerea în 1 a biţilor 4 sau 5 din CL sau CH produce rezultate
dependente de placă grafică, şi de regulă se evită.
Există o singură dimensiune a cursorului la un moment dat
pentru toate paginile video
Clipirea cursorului nu poate fi dezactivată (este produsa de
hardware), dar se poate face cursorul invizibil. În acest scop se
poziţionează cursorul cu serviciul 02h în afara zonei vizibile a
ecranului (de exemplu pe linia 25).
Acest serviciu afectează doar modurile text; în modurile
grafice cursorul nu este afişat.
Pentru citirea dimensiunii cursorului se poate folosi
serviciul 03h.

Vezi şi: INT 10h, 03h INT 10h, 02h .

INT 10h, 02h (2) - Stabilire poziţie cursor


Setează poziţia cursorului (linie şi coloană) pentru o pagină
afişată specificată.

Intrări: AH 02h;
BH Numarul paginii afişate;
DH Linie;
DL Coloană.

Rezultate: Nici unul.

Registre modificate: AX, SP, BP, SI, DI.

------------------------------------------------------------------

Observaţii: Acest serviciu poate poziţiona cursorul pe pagina activă


afişată sau pe o pagină inactivă.

113
În modurile grafice, acest serviciu setează poziţia logică a
cursorului, chiar şi dacă cursorul în sine nu este afişat
(cursorul nu este afişat în nici unul din modurile grafice).
Pentru a face cursorul invizibil, acesta se poate poziţiona
la linia 25.
Colţul stânga sus al imaginii este DH = 0h, DL = 0h, iar
colţul dreapta este DH = 18h (24), DL = 27h (39) pentru ecran cu 40
de coloane, sau 4Fh (79) pentru ecran cu 80 de coloane.
A se vedea serviciul 05h pentru o listă de numere de pagină
valide pentru diferitele moduri de afişare. Deoarece servi
ciul nu verifica valoarea, pot apărea rezultate eronate dacă
se specifică un număr de pagină invalid. Numărul paginii
pentru modurile grafice este 0.

Vezi şi : INT 10h, 03h INT 10h, 05h.

INT 10h, 03h (3) Citeşte poziţia şi mărimea cursorului


Raportează poziţia (linia şi coloana) şi mărimea cursorului
pentru pagina afişată specificată.

Intrări: AH 03h;
BH Numărul paginii afişate.

Rezultate: CH Linia de start a cursorului;


CL Linia de sfârşit a cursorului;
DH Linie;
DL Coloană.

Registre modificate: AX, SP, BP, SI, DI.

Valorile liniilor de început şi sfârşit ale cursorului (CH si CL)

Permise Implicite
Adaptor Început Sfârşit Început Sfârşit
CGA 0 7 6 7
MDA 0 13 11 12
7(12) Depinde de
EGA, VGA 0 13 6(11)
mod

Observaţii: Acest serviciu poate raporta poziţia cursorului


în pagina activă, afişată, sau într-o pagină inactivă.
Deoarece există numai un cursor hardware, linia de start a
cursorului (CH) şi cea de sfârşit (CL) (şi deci mărimea cursorului)

114
vor avea aceeaşi valoare indiferent ce numar de pagină a fost
specificat.
În modurile grafice, acest serviciu raportează poziţia
logică a cursorului, chiar dacă cursorul nu este afişat.
Colţul din stânga sus al imaginii este DH = 0h, L = 0h, pe
când cel din dreapta jos este DH = 18h(24), DL = 27h (39) pentru
modul de 40 de coloane sau 4Fh (79) pentru modul de 80 de coloane.
A se vedea Serviciul 05h pentru o listă de numere de
pagină valide pentru diferite moduri de afişare.
Deoarece serviciul nu verifică valorile, pot să apară
rezultate eronate dacă se specifică un număr invalid.
Numărul paginii pentru modul grafic este 0.
Se foloseşte Serviciul 02h pentru a seta poziţia curentă
a cursorului.
Se foloseşte Serviciul 01h pentru a seta mărimea curentă a
cursorului.

Vezi şi: INT 10h, 01h INT 10h, 02h INT 10h, 05h.

INT 10h, 04h (4) Citeşte poziţia creionului optic


Raportează poziţia şi starea creionului optic.

Intrare: AH 04h.

Rezultate: AH Stare (0=neactivat, 1=activat);


BX Numărul coloanei unui pixel (0-639);
CH Numărul liniei unui pixel (0-199);
CX Numărul liniei pentru modurile 0Fh-10h(0-nnn);
DH Numărul liniei caracterului (0-24);
DL Numărul coloanei caracterului (0-39 sau 0-79).

Registre modificate: AX, SP, BP, SI, DI.

Observaţii: Poziţia este raportată sub două forme: poziţia


caracterului (linie în DH, coloana in DL), sau locaţia pixelului
(linia raster în CH, coloana/punct în BX).
Dacă rezultă AH este 0, creionul optic nu este suportat.
Coordonatele pixelului pentru poziţia creionului optic nu sunt
exacte. Coordonatele y sunt întotdeauna un multiplu de 2, pe când
coordonatele x sunt un multiplu de 4 pentru rezoluţia 320x200 şi
multiplu de 8 pentru rezoluţia de 640x200.

115
INT 10h, 05h (5) Setează pagina activă afişată
Setează pagina activă afişată.

Intrare: AH 05h;
AL Numărul paginii afişate.

Rezultate: Nici unul.

Registre modificate: AX, SP, BP, SI, DI.

------------------------------------------------------------------

Valorile valide de pagină (AL)

Mod video Pagini valide


00h 0-7
01h 0-7
02h 0-3
03h 0-3
04h 0
05h 0
06h 0
07h 0
08h 0
09h 0
0Ah 0
0Dh 0-7
0Eh 0-3
0Fh 0-1
10h 0-1
------------------------------------------------------------------
Observaţii: Conţinutul paginii afişate nu este distrus
când pagina curentă este modificată. De fapt, se poate scrie pe o
pagina inactivă, apoi să se schimbe obţinând astfel modificări
rapide ale ecranului.
Folosiţi serviciul 0Fh pentru a determina pagina activă
curentă.

Vezi şi: INT 10h, 0Fh.

116
INT 10h, 06h (6) Derulează fereastra în sus
Derulează fereastra specificată, în sus, cu numărul de linii
specificat.

Intrare: AH 06h;
AL Numărul de linii de derulat (daca este
0, şterge întreaga fereastră);
BH Atributele display-ului pentru liniile
goale;
CH Numărul liniei din colţul stânga sus;
CL Numărul coloanei din colţul stânga sus;
DH Numărul liniei din colţul dreapta jos;
DL Numărul coloanei din colţul dreapta jos.

Rezultate: Nici unul.

Registre modificate: AX, SP, BP, SI, DI.

------------------------------------------------------------------
Liniile sunt inserate în partea de jos a ecranului, mutând toate
liniile în sus. Noile linii sunt scrise cu atributuele stabilite de
valoarea din BH.
Liniile care dispar din partea de sus a ferestrei se pierd.
Observaţii: Dacă numarul de linii de derulat este specificat ca
find 0, întreaga fereastră este umplută cu spaţii.
Folosiţi serviciul 07h pentru a derula fereastra în jos.
Acest serviciu afectează numai pagina activă curentă afişată.

Vezi şi: INT 10h, 07h.

INT 10h, 07h (7) Derulează fereastra în jos


Derulează fereastra specificată în jos cu un număr specificat de
linii.

Intrări: AH 07h;
AL Numărul de linii de derulat (dacă este 0,
şterge întreaga fereastră);
BH Afişează atributele pentru liniile libere;
CH Numărul liniei din colţul stânga sus;
CL Numărul coloanei din colţul stânga sus;

117
DH Numărul liniei din colţul dreapta jos;
DL Numărul coloanei colţul dreapta jos.

Rezultate: Nici unul.

Registre modificate: AX, SP, BP, SI, DI

Liniile sunt introduse în partea de sus, iar toate celelalte


linii se deplasează în jos. Noile linii sunt scrise cu caractere
blanc având atributele date de valoarea din BH. Liniile care dispar
în partea de jos a ferestrei se pierd.

Observaţii: Dacă numărul de linii de derulat este dat ca


fiind 0, întreaga fereastră este umplută cu spaţii.
Folosiţi serviciul 06h pentru a derula fereastra în sus.
Acest serviciu afectează numai pagina activă curentă.

Vezi şi: INT 10h, 06h

INT 10h, 08h (8) Citeşte caracterul (şi atributele) de la cursor


Raportează valoarea ASCII şi (în modul text) atributele
caracterului de la locaţia curentă a cursorului în pagina
specificată.

Intrare: AH 08h;
BH Afişează numărul paginii (numai în
modurile text).
Rezultate: AH Atributele caracterului (mod text);
AL Valoarea ASCII a caracterului.

Registre modificate: AX, SP, BP, SI, DI.

Observaţii: În modul grafic, pagina afişată nu mai trebuie


specificată.
Atributele şi caracterul curent pot fi obţinute pentru
orice pagină, chiar şi dacă pagina nu este cea activă, curentă.
Folosiţi Serviciul 09h pentru a scrie un caracter cu atribute
specifice.

118
Vezi şi: INT 10h, 09h

INT 10h, 09h (9) Scrie un caracter (şi atributele) la cursor


Afişează caracterul dat, cu atributul specificat, de un număr de
ori dat.

Intrare: AX 09h;
AL Valoarea ASCII a caracterului;
BH Afişează pagina (numai în modul text);
BL Atribute/Culoare;
CX De câte ori se scrie caracterul.

Rezultate: Nici unul.

Registre modificate: AX, SP, BP, SI, DI.

Observaţii: Afişarea începe la locaţia curentă a cursorului


pe pagina afişată, specificată, dar cursorul nu este mişcat.
În modul text, caracterele care se extind peste marginea
din dreapta ecranului sunt ataşate liniiei următoare; în modul
grafic, acest lucru nu se întamplă.
Acest serviciu afişează caracterele control ca pe nişte
caractere printabile, în loc de echivalentul acestora pentru
controlul cursorului. De exemplu, dacă AL este 13, atunci se va
afişa nota muzicală, în loc de Carriage Return.
În modurile grafice, dacă atributul (BL) este dat cu bitul cel
mai semnificativ în 1, se face un XOR între biţii de culoare ai
caracterului specificat şi biţii de culoare ai caracterului curent.
Se poate utiliza această opţiune pentru scrierea de caractere iar
apoi ştergerea acestora.

Vezi şi: INT 10h, 0Ah INT 10h, 0Eh INT 10h, 13h INT 10h, 08h.

119
INT 10h, 0Ah (10) Scrierea caracterului la cursor
Afişează caracterul specificat de un număr de ori dat.

Intrare: AH 0Ah;
AL Valoarea ASCII a caracterului;
BH Afişează numarul paginii (numai mod text);
CX Numărul de ori de scriere al caracterului.

Rezultă: Nici unul.

Registre modificate: AX, SP, BP, SI, DI.

Afişarea începe la locaţia curentă a cursorului pe pagina


afişată, specificată, dar cursorul nu este miscat.

Observaţii: Folosiţi Srviciul 09h pentru modul grafic,


deoarece permite să se schimbe culorile.
În modul text, caracterele care se întind peste marginea
dreaptă a ecranului sunt lipite liniiei urmatoare; în modul grafic
acest lucru nu se întamplă.
Acest serviciu afişează caracterele control ca pe nişte
caractere printabile, în loc de echivalentul acestora pentru
controlul cursorului. De exemplu, dacă AL este 13, atunci se va
afişa nota muzicală, în loc de Carriage Return.
Diferenţa dintre acest serviciu şi Serviciul 09h este ca,
acest serviciu nu acordă dreptul de a specifica octetul de atribute
Acest serviciu foloseşte atributul de la pozitia curenta a
cursorului pentru noul caracter.

Vezi şi: INT 10h, 09h INT 10h, 0Eh INT 10h, 13h.

120
INT 10h, 0Bh (11) Setează paleta de culori
Selectează paleta de culori pentru diferitele moduri de
afişare.

Intrare: AX 0Bh;
BH Id-ul Paletei de culori (0 sau 1, vezi
mai jos);
BL Valoarea culorii sau paletei, pentru a
fi utilizată cu ID-ul Culorii (0 -31).

Rezultate: Nici unul.

Registre midificate: AX, SP, BP, SI, DI.

Daca BH (ID-ul Paletei de Culori) este 0, atunci:


. Setează culoarea de fond pentru rezoluţia 320 x 200
. Setează culoarea chenarului pentru modurile text
. Setează culoarea frontală pentru rezoluţia de 640 x 200

BL conţine culoarea de utilizat. EGA-ul va seta culoarea de


fond pentru rezoluţia de 640 x 200.
Când se setează culorile chenarelor pentru modurile text,
culorile 16 -31 vor selecta setul de fond de intensitate mare.
Daca BH (ID-ul paletei de culori) este 1, atunci:
. Selectează paleta de culori pentru rezoluţia de 320 x
200

Valoarea în BL determină care combinaţie de paletă să fie


utilizată, după cum este definit mai jos:

------------------------------------------------------------------
Paleta 0 (BL = 0)

Valoare Pixel Culoare


0 Culoarea curentă de fond
1 Verde
2 Roşu
3 Maro
------------------------------------------------------------------
Paleta 1 (BL = 1)
Valoare Pixel Culoare
0 Culoarea curentă de fond
1 Cyan
2 Magenta
3 Alb
Vezi şi: INT 10h, 10h.

INT 10h, 0Ch (12) Scriere pixel


Scrie un punct pixel de culoare dată la coordonatele de ecran
specificate.

Intrare: AH 0Ch;

121
AL Culoare pixel;
CX Poziţia pe orizontală a pixelului;
DX Poziţia pe verticală a pixelului;
BH Afişează numarul paginii (modurile
grafice cu mai mult de o pagină).
Rezultate: Nici unul.

Registre modificate: AX, SP, BP, SI, DI.

------------------------------------------------------------------
Valori valide
Mode CX(Horizontal) DX(Vertical) AL(Pixel Color) BH(Page Number)
04h 0-319 0-199 0-3
05h 0-319 0-199 0-3
06h 0-639 0-199 0-1
0Dh 0-319 0-199 0-15 0-7
0Eh 0-639 0-199 0-15 0-3
0Fh 0-639 0-349 0-1 0-1
10h 0-639 0-349 0-15 0-1
------------------------------------------------------------------

Observaţii: Dacă culoarea pixelului (AL) este dată cu


bitul cel mai semnificativ în 1, se face un XOR între biţii de
culoare ai caracterului specificat şi biţii de culoare ai
caracterului curent. Se poate utiliza această opţiune pentru
scrierea de caractere iar apoi ştergerea acestora.

Vezi şi: INT 10h, 0Dh.

INT 10h, 0Dh (13) Citire pixel


Raportează culoarea pixelului la coordonatele de ecran
precizate.

Intrare: AH 0Dh
CX Poziţia pe orizontală a pixelului
DX Poziţia pe verticală a pixelului
BH Afişează numărul paginii (modurile
grafice cu mai mult de o pagină)

Rezultate: AL Culoarea pixelului

Registre modificate: AX, SP, BP, SI, DI

122
------------------------------------------------------------------
Valori valide

Mode CX(Horizontal) DX(Vertical) AL(Pixel Color) BH(Page Number)


04h 0-319 0-199 0-3
05h 0-319 0-199 0-3
06h 0-639 0-199 0-1
0Dh 0-319 0-199 0-15 0-7
0Eh 0-639 0-199 0-15 0-3
0Fh 0-639 0-349 0-1 0-1
10h 0-639 0-349 0-15 0-1
------------------------------------------------------------------
Observaţii: Pentru modurile 0Dh până la 10h, numarul
paginii este necesar să fie precizat în BH.

Vezi şi: INT 10h, 0Ch.

INT 10h, 0Eh (14) Scrierea caracterului în modul Teletype (TTY)


Scrie un caracter la locaţia curentă a cursorului şi îl
avansează.

Intrare: AH 0Eh;
AL Caracterul de scris;
BL Culoarea (numai modurile grafice);
BH Numarul paginii afişate (numai
modurile text).

Rezultat: Nici unul.

Observaţii: În modurile text, caracterul afişat are


atributele de afişare ale caracterului anterior, care ocupă acea
locaţie de ecran. În modurile grafice, este necesar să se precizeze
culoarea de front (în BL) de fiecare dată, când se utilizează acest
serviciu.
În modurile text, caracterele pot fi scrise să afişeze alte
pagini decât cea activă.
Acest serviciu răspunde la valorile ASCII ale caracterelor 07h
(bell), 08h (backspace), 0Ah (linefeed), şi 0Dh (carriage return).
Toate celelalte valori ASCIIau ca efect afişarea unui caracter,
mutând cursorul cu o poziţie.
Dacă cursorul se află la sfârşitul unei linii, este ataşat
urmatoarei linii. Dacă cursorul este la sfârşitul ultimei linii a

123
ecranului, ecranul este derulat în sus iar atributul de afişare
pentru întreaga nouă linie este luat de la ultimul caracter al
liniei anterioare.

Vezi şi: INT 10h, 09h INT 10h, 0Ah INT 10h, 13h.

INT 10h, 0Fh (15) Citeşte modul video curent


Raportează modul video curent, numărul poziţiilor caracterelor
per linie în acel mod video, şi pagina curentă afişată.

Intrare: AH 0Fh;

Rezultte: AL Mod video;


AH Număr de coloane de caractere per linie;
BH Numărul paginii active afişate.

Registre modificate: AX, SP, BP, SI, DI.

Observaţii: Vezi serviciul 00h pentru un tabel de moduri


video şi cum se setează modul video curent.

Vezi şi: INT 10h, 00h

124
INT 10h, 10h (16) Setarea regiştrelor paletei la EGA /VGA
Setează regiştrii de paleta şi contur la EGA/VGA.

Intrare: AH 10h;
AL Subserviciu:
0–Setează registrul paletei:
BL Registru paletă;
BH Valoarea de setat;
1–Setează registrul culorii de contur:
BH Valoarea de setat;
2–Setează regiştrii paletei şi conturului:
ES:DX Pointerul listei de culori.
3–Activează bitul intensificare/clipire:
BL 0 – Activează intensificare;
1 – Activează clipire.

Subservicii numai VGA: 7–BL = registrul culoare de luat în BH;


8–Rezultă valoarea conturului în BH;
9–Rezultă lista registrilor paletei şi
valoarea conturului:
ES:DX pointer către lista;
10h–Setează registrul culorii:
BX Registrul de setat;
CH,CL,DL verde/albastru/Rosu;
1Ah–Informaţie despre culoarea paginii:
BL Mod;
BH Pagină.

Regiştrii modificati: AX, SP, BP, SI, DI.

Sunt 16 regiştri de palete în modurile de afişare EGA/VGA şi


un registru de contur. Acest serviciu oferă utilizatorului control
asupra acestor regiştri.

Subserviciul 0 (Setarea Registrului Paletei)

Fiecare din cei 16 regiştrii de palete poate lua o valoare de


la 1 la 64.
Valoarea în BH are forma următoare:

Bit 7 – Rezervat
Bit 6 – Rezervat
Bit 5 - Roşu Secundar
Bit 4 - Verde Secundar
Bit 3 - Albastru Secundar

125
Bit 2 – Roşu
Bit 1 – Verde
Bit 0 – Albastru

Culorile secundare au intensitaţi de 1/3, pe când culorile


normale au o intensitate de 2/3. De exemplu, BH = 02h va produce
verde, BH = 10h va produce un verde pal, iar BH = 02h va produce un
verde intens.
Valorile implicite pentru regiştrii paletelor, care sunt
aceeaşi ca cei ai adaptorului grafic color (CGA), sunt definiţi mai
jos:

------------------------------------------------------------------
Registru de Valoare culoare Culoare
paleta
00h 00h Negru
01h 01h Albastru
02h 02h Verde
03h 03h Cian
04h 04h Roşu
05h 05h Mov
06h 14h Maro
07h 07h Alb
08h 38 Gri inchis
09h 39h Albastru deschis
0Ah 3Ah Verde deschis
0Bh 3Bh Cian deschis
0Ch 3Ch Roşu deschis
0Dh 3Dh Mov deschis
0Eh 3Eh Galben
0Fh 3Fh Alb intens
------------------------------------------------------------------

Subserviciul 1 (Setează registrul de contur)

Acest subserviciu setează culoarea conturului. Subserviciul


este suportat numai în moduri de 200 de linii.

Subserviciul 2 (Setează toti regiştrii paletelor şi de contur)

ES:DX indică o listă de 17 octeţi de culoare, în care primii


16 octeţi conţin in valori noi pentru cei 16 regiştri ai paletelor
şi ultimul octet conţine este noua valoare a registrului de contur.
În mod normal, bitul 7 al octetului de atribut este folosit
pentru a indica clipirea. Cu acest subserviciu, bitul 7 poate indica
clipirea (BL=1) sau intensitatea de fond (BL=0).

Subserviciul 3 (Comută bitul intensitate/clipire )

Numai VGA:

Subserviciul 7 (Citeşte valoarea registrilor de culoare)

Subserviciul 8 (Citeşte valoarea conturului)

126
Subserviciul 9 (Citeşte regiştrii de culoare)

Subserviciul 10h (Setează Regiştrii de culoare)

Subserviciul 12h (Modifică regiştrii de culoare)

Subserviciul 13h (Setează pagina)

Subserviciul 15h (Citeşte Registrul de culoare)

Subserviciul 17h (Încarcă Regiştrii de culoare în memorie)

Subserviciul 1Ah (Citeşte informaţia de culoare a paginii)

Vezi şi: INT 10h, 0Bh.

INT 10h, 11h (17) Generatorul de caractere EGA

Modifică fonturile din adaptorul grafic în fonturi predefinite


sau definite de utilizator în ambele moduri, text sau grafic.

Intrare: AH 11h;
AL Subserviciu:
00h –Încarcă fontul definit de utilizator (moduri text):
ES:BP Indicator către tabelul de fonturi;
CX Numarare caractere;
DX Offset-ul tabelei de caractere;
BL Blocul de fonturi de încarcat (0-3);
BH Octeţi per caracter;

01h – Încarcă fontul de 8 x14 puncte (setul monocrom):

127
BL Blocul de fonturi de încarcat (0-3);

02h – Încarcă fontul dublu-punct, 8 x 8 de caractere


(modurile text):
BL Blocul de fonturi de încarcat (0-3);

03h – Setează specificatorul de bloc (modurile text):


BL Biţii 3, 2: Selectează blocul (0-3) de
utilizat când bitul 3 al atributului este 1;
Biţii 1, 0: Selecteaza blocul (0-3) de
utilizat când bitul 3 al atributului este 0 ;

04h –Încarca fontul de 8 x 16 puncte (VGA):


BL Blocul de fonturi de încarcat;

10h – Încarcă fontul definit de utilizator (modurile


text):
ES:BP Indicator către tabelul de fonturi;
CX Numărul de caractere;
DX Offset-ul tabelei de caractere;
BL Blocul de fonturi de încarcat (0-3);
BH Octeţi per caracter.

11h – Încarcă fontul de 8 x 14 puncte (setul monocrom)


BL Blocul de fonturi de încarcat (0-3):

12h – Încarcă fontul 8 x 8 dublu-punct (modurile text)


BL Blocul de fonturi de încarcat (0-3);

20h – Încarcă fontul de 8 x 8 puncte definit de


utilizator (modurile grafice):
ES:BP Indicator către tabelul grafic al
utilizatorului pentru caracterele grafice 128-255.
INT 1Fh este setat către acest indicator.

21h – Încarca fontul de caractere definit de utilizator


(modurile grafice);
ES:BP Indicator către tabelul grafic pentru
caracterele grafice 0-255.INT 43h dă indicatorul.
CX Octeţi per caracter;
BL Numărul de linii:
00h – DL conţine numărul de linii;
01h – 14 (0Eh) linii;
02h – 25 (19h) linii;
03h – 43 (2Bh) linii.

22h – Încarcă fontul ROM de 8 x 14 puncte (modurile


grafice):
BL Numărul de linii (Acelaşi format ca
subserviciul 21h);

23h – Încarcă fontul ROM 8 x 8 dublu-punct (modurile


grafice):
BL Numărul de linii (Acelaşi format ca
subserviciul 21h);

24h –Încarcă fontul 8 x 16 de caractere:


BL Numărul de linii (Acelaşi format ca
Subserviciul 21h);

128
30h – Rezultă informaţii despre font:
BH Tipul de pointer care rezultă:
00h – Pointerul curent INT 1Fh;
01h – Pointerul curent INT 44h;
02h – Pointerul ROM 8 x 14 puncte ;
03h – Pointerul ROM 8 x 8 dublu-punct;
04h – Pointerul ROM 8 x 8 dublu-punct (sus);
05h – Pointerul ROM text alternativ 9 x 14;
06h - 8 x 16 (VGA);
07h - 9 x 16 (VGA).

Rezultate: (Numai Subserviciul 30h – Dă informaţii despre


font);
ES:BP Indicator către tabelul specificat
în BH;
CX Linii per caracter;
DL Linii.

Vezi şi: INT 10h, 12h.

INT 10h, 12h (18) Funcţii speciale EGA


Rezultă informaţii asupra EGA şi permite selectarea unei
rutine alternative EGA Print Screen.

Intrare: AH 12h;
BL Subserviciu:
10h – Rezultă informaţia EGA;
20h - Selectează rutina EGA Print Screen
alternativă.
Numai VGA:
30h - Setează numărul de linii 0-200, 0-350,
2-400. Se activează după schimbarea
modului;
31h - AX = 0/1 -> permite/interzice
încarcarea paletei odată cu noul mod;
32h - AL = 0/1 -> Video Pornit/Oprit;
33h - AL = 0/1 -> Însumarea scale de gri
Pornit/Oprit;
34h - AL=0/1 ->Scalarea cursorului cu fontul
pornit/oprit;
35h – Schimbă între placa video şi video de
pe placa de bază:
AL = 0 adaptor pornit, es:dx salvează
starea;
= 1 video de pe placa de bază
pornit;
= 2 video activ oprit, es:dx
salvează starea;
= 3 video inactiv pornit, es:dx
salvează starea;
36h – Porneşte/opreşte ecranul :
AL = 0/1 -> Ecran pornit/oprit.

Rezultate: (numai pentru Subserviciul 10h):


BH Modul rezultat:
00h Mod color (domeniu de adresare 3Dxh);
01h Mod monocrom (domeniu de adresare 3Bxh);

129
BL Memorie EGA
00h 64K;
01h 128K;
02h 192K;
03h 256K;
CH Biţii adaptorului;
CL Setările comutarii.

Vezi şi: INT 10h, 11h.

INT 10h, 13h (19) Scrierea unui şir de caractere


Scrie un şir de caractere cu atributele precizate pe orice
pagina afişată.

Intrare: AH 13h;
AL Subserviciul (0-3);
BH Afişează numărul paginii;
BL Atribute (Subseviciile 0 si 1);
CX Lungimea şirului;
DH Poziţia liniei unde urmează să fie
scris şirul;
DL Poziţia coloanei unde urmează să fie
scris şirul;
ES:BP Indicatorul către şirul de scris.

Rezultate: Nici unul.

Registre modificate: AX, SP, BP, SI, DI.

------------------------------------------------------------------

Observaţii:

Acest serviciu are 4 subservicii după cum urmează:

AL=00h: Aplică tuturor caracterelor atributele din BL;


nu modifică cursorul;
AL=01h: Aplică tuturor caracterelor atributele din BL;
modifică cursor;
AL=02h: Foloseşte atributele din sir; nu modifică
cursorul;
AL=03h: Foloseşte atributele din şir; modifică cursorul.

Vezi şi: INT 10h, 09h INT 10h, 0Ah INT 10h, 0Eh.

130
INT 10h, 14h (20) Utilizarea LCD
Permite utilizarea de fonturi definite de utilizator şi
schimbarea atributului de intensitate mare într-un alt atribut pe un
ecran LCD.

Intrare: AH 14h;
AL Subserviciu:
00h - Încarcă fontul precizat de utilizator:
ES:DI Indicator către primul tabel de fonturi;
CX Numărul de caractere de stocat (1 - 256);
DX Offset-ul caracterului în buffer-ul de
fonturi din RAM;
BL Blocul de fonturi de încarcat:
0 – Font principal (bloc 0);
1 – Font alternativ (bloc 1);
BH Octeţi per character (1 - 255);

01h - Încarcă blocul de fonturi implicit din ROM:


BL Blocul de fonturi de încărcat:
0 – Font principal (bloc 0);
1 – Font alternativ (bloc 1);

02h – Transformarea atributului de intensitate mare:


BL Schema de transformare:
0 - Ignoră atributul de intensitate mare;
1 – Transformă în video invers;
2 - Transformă în subliniat;
3 – Selectează font alternativ.
Rezultate: Nici unul.

Vezi şi: INT 10h, 15h.

INT 10h, 15h (21) Citeşte caracteristicile fizice ale adaptorului grafic
Rezultă tipul de adaptor video alternativ şi un tabel care
descrie caracteristicile ecranului curent.

Intrare: AH 15h.

Rezultă: AX Tipul de adaptor video alternativ:


00h – Nici un adaptor alternativ;

131
5140h – LCD;
5153h – Tipul CGA de afişare;
5151h – Tipul monocrom de afişare;
ES:DI Indicator către tabelul de 7 cuvinte al
adaptorului video curent (vezi mai jos).

Observaţii: Forma tabelului adaptorului video este


următoarea:
Cuvânt 1 –
Numărul modelului video;
Cuvânt 2 –
Pixeli pe metru pe varticală;
Cuvânt 3 –
Pixeli pe metru pe orizontală;
Cuvânt 4 –
Total pixeli pe verticală;
Cuvânt 5 –
Total pixeli pe orizontală;
Cuvânt 6 –
Înalţimea pixel în micrometrii
(direcţie verticală);
Cuvânt 7 – Laţimea pixel în micrometrii
(direcţie orizontală);

------------------------------------------------------------------
Tabelul adaptoarelor video compatibile PC
Cuvant Monocrom CGA LCD (CGA) LCD (Monocrom)

1 5151h 5153h 5140h 5140h


2 0 0498h 08E1h 0
3 0 0A15h 0987h 0
4 0 00C8h 00C8h 0
5 0 0280h 0280h 0
6 0 0352h 0172h 0
7 0 0184h 0172h 0

Vezi şi: INT 10h, 14h.

ANEXA 3

Lista funcţiilor sistemului de operare INT 21h

Funcţiile sistem reprezintă o colecţie de subrutine standard foarte


performante, care pot fi chemate de un program în limbaj de asamblare prin
intermediul întreruperii 21h. Diferenţierea între ele se face prin valoarea care se
încarcă în prealabil în registrul AH, conform tabelului de mai jos.

AH Descriere AH Descriere
01 Citeşte un caracter de la STDIN 02 Scrie un caracter la STDOUT
05 Scrie un caracter la imprimantă 06 Intrare/Ieşire Consolă
Citeşte direct un caracter de la STDIN Citeşte un caracter de la STDIN
07 08
fară ecou fără ecou

132
09 Scrie un şir la STDOUT 0A Intrare bufferată
0B Află starea STDIN 0C Goleşte bufferul de la STDIN
0D Reset disk 0E Selectează unitatea implicită
19 Află unitatea curentă implicită 25 Setează vectorul de întrerupere
2A Află data sistemului 2B Setează data sistemului
2C Află ora sistemului 2D Setează ora sistemului
2E Seteaza fanionul de verificare 30 Află versiunea DOS
35 Află vectorul de înterupere
36 Află spaţiul liber de pe disc 39 Crează un subdirector
3A Şterge un subdirector 3B Setează directorul de lucru
3C Crează un fişier 3D Deschide un fişier
3E Închide un fişier 3F Citeşte un fişier
40 Scrie un fişier 41 Şterge un fişier
42 Caută un fişier 43 Află/Setează atributele fişierelor
47 Află directorul curent 4C Iese din program
4D Află return code 54 Află fanionul de verificare
56 Redenumeşte fişierul 57 Află/Setează data fişierului
INT 21h, 01h CITEŞTE UN CARACTER DE LA INTRAREA
STANDARD, CU ECOU
Intrare: AH=01h.
Efect: AL = caracter citit.
Observaţii:
 ^C/^Break sunt testate;
 ^P comută starea fanionului intern DOS al ecoului la imprimantă;
 ^Z nu este interpretat, aşadar nu cauzează un EOF. Dacă intrarea este
redirecţionată, caracterul este trimis în ecou la ieşirea standard.
Vezi şi: AH=06h,AH=07h,AH=08h,AH=0Ah.

INT 21h, 02h –SCRIE UN CARACTER LA IEŞIREA STANDARD


Intrare:AH=02h;
DL = caracter de scris.

Efect: AL = ultimul caracter ieşit.


Observaţii:
 ^C/^Break sunt testate;

133
 ultimul caracter ieşit va fi caracterul din DL excepţie făcând DL=09h la
intrare, caz în care AL=20h deoarece tab-urile sunt înlocuite cu blank-uri;
 dacă intrarea standard este redirecţionată într-un fişier, nu se ţine cont de nici
o eroare (protecţie la scriere, mediu de stocare plin, etc.).
Vezi şi: AH=06h,AH=09h.

INT 21h, 05h – SCRIE UN CARACTER LA IMPRIMANTĂ


Intrare:AH=05h
DL = caracter de printat.

Observaţii:
 se testează imprimanta pentru ^C/^Break;
 STDPRN este de obicei primul port paralel, dar poate fi redirectat sub DOS
2+ ;
 Dacă imprimanta e ocupată, această funcţie va aştepta.
Vezi şi: INT 17/AH=00h.

INT 21h, 06h – IEŞIRE DIRECTĂ LA CONSOLĂ


Intrare: AH=06h;
DL = caracter (excepţie FFh).
Efect: AL = caracter ieşit.
Observaţii: nu testează ^C/^Break.
Vezi şi: AH=02h,AH=09h.

INT 21h, 06h – INTRARE DIRECTĂ DE LA CONSOLĂ


Intrare: AH = 06h;
DL = FFh.
Efect:
 ZF setat dacă nu există caracter disponibil şi AL = 00h;
 ZF şters dacă există caracter disponibil AL = caracter citit.
Observaţii:
 ^C/^Break nu sunt testate;
 dacă rezultatul returnat este 00h, utilizatorul a apăsat o tastă cu un cod de tastă
extins, care se va returna la următoarea apelare a acestei funcţii.

134
 Deşi returnarea lui AL=00h atunci când nici un caracter nu e disponibil nu
este documentată, unele programe se bazează pe acest comportament.
Vezi şi: AH=0Bh.

INT 21h, 07h – INTRAREA DIRECTĂ A UNUI CARACTER, FĂRĂ


ECOU
Intrare: AH=07h;
Efect: AL = caracter citit de la intrarea standard.
Observaţii: nu testează ^C/^Break.
Vezi şi: AH=01h,AH=06h,AH=08h,AH=0Ah.

INT 21h, 08h – INTRARE CARACTER FĂRĂ ECOU


Intrare: AH=08h;
Efect: AL = caracter citit de la intrarea standard.
Observaţii: ^C/^Break sunt testate.
Vezi şi: AH=01h,AH=06h,AH=07h,AH=0Ah,AH=64h.

INT 21h, 09h – SCRIE UN ŞIR LA IEŞIREA STANDARD


Intrare: AH=09h;
DS:DX -> şir terminat cu '$'.
Efect: AL = 24h.
Observaţii: ^C/^Break sunt testate.
Vezi şi: AH=02h,AH=06h"OUTPUT".

INT 21h, 0Ah – INTRARE BUFFERATĂ


Intrare: AH=0Ah;
DS:DX -> buffer (vezi mai jos).
Efect: buffer umplut cu informaţia introdusă de utilizator.
Observaţii:
 ^C/^Break sunt testate ;
 citeşte de la intrarea standard.
Vezi şi: AH=0Ch.

135
Formatul buffer-ului de intrare DOS:
Index Mărime Descriere
00 1 Numărul maxim de caractere ce pot intra în buffer
Numărul maxim de caractere de de la ultima intrare care pot fi
01 1
rechemate sau numărul de caractere din citirea actuală, fără CR
02 N Caracterul actual citit, incluzând CR-ul final

INT 21h, 0Bh – AFLĂ STAREA STDIN (Intrare standard)


Intrare: AH=0Bh;
Efect:
 AL = 00h dacă nu există caracter disponibil;
 AL = FFh dacă caracterul este disponibil.
Observaţii: ^C/^Break sunt testate.
Vezi şi: AH=06h"INTRARE".

INT 21h, 0Ch - GOLEŞTE BUFFERUL ŞI CITEŞTE DE LA


INTRAREA STANDARD
Intrare:
 AH=0Ch;
 AL = funcţiea de executat după golirea bufferului;
 celelalte registre corespunzătoare funcţiei de intrare.
Efect: corespunzător funcţiei de intrare specificate.
Observaţie: dacă AL nu are una dintre valorile 01h,06h,07h,08h, sau 0Ah, bufferul e
golit dar nu este aşteptată nici o intrare.
Vezi şi: AH=01h,AH=06h"INTRARE",AH=07h,AH=08h,AH=0Ah.

INT 21h, 0Dh - RESETAREA DISCULUI


Intrare: AH=0Dh;
Observaţii: Această funcţie scrie pe disc toate bufferele modificate, dar nu
actualizează informaţia directoarelor.
Vezi şi: AX=5D01h.

INT 21h, 0Eh – SELECTEAZĂ UNITATEA IMPLICITĂ

136
Intrare: AH=0Eh;
DL = noua unitate implicită (0=A:, 1=B:, etc).
Efect: AL = numărul unităţilor potenţial valide.
Observaţii: valoarea întoarsă reprezintă valoarea corespunzătoare ultimei unităţi
prezente.
Vezi şi: AH=19h,AH=3Bh,AH=DBh.

INT 21h, 19h - AFLĂ UNITATEA CURENTĂ IMPLICITĂ


Intrare: AH=19h;
Efect: AL = unitate (0=A:, 1=B:, etc).
Vezi şi: AH=0Eh,AH=47h,AH=BBh.

INT 21h, 25h - SETEAZĂ VECTORUL DE ÎNTRERUPERE


Intrare:
 AH=25h;
 AL = numărul întreruperii;
 DS:DX -> noua tratare a întreruperii.
Observaţii: această funcţie este de preferat modificării directe a tabelei vectorilor de
întrerupere.
Vezi şi: AX=2501h,AH=35h.

INT 21h, 2Ah – AFLĂ DATA SISTEMULUI


Intrare: AH=2Ah;
Efect: CX = an (1980-2099) DH = lună DL = zi AL = zi a săptămânii
(00h=Duminică).
Vezi şi: AH=2Bh"DOS",AH=2Ch,AH=E7h.

INT 21h, 2Bh – SETEAZĂ DATA SISTEMULUI


Intrare: AH=2Bh;
CX = an (1980-2099) DH = lună DL = zi.
Efect:
 AL = 00 operaţie reuşită;

137
 FFh dată invalidă, data sistemului neschimbată.
Observaţie: DOS 3.3+ setează deasemenea ceasul din CMOS;
Vezi şi: AH=2Ah,AH=2Dh.

INT 21h, 2Ch – AFLĂ ORA SISTEMULUI


Intrare: AH=2Ch;
Efect: CH = ora CL = minute DH = secunde DL = 1/100 secundă.
Observaţie: pe majoritatea sistemelor, rezoluţia ceasului sistem este de 5/100sec, aşa
că valoarea lui DL nu se incrementează cu 1 pe unele sisteme, acesta returnând
întotdeauna 00h.
Vezi şi: AH=2Ah,AH=2Dh,AH=E7h.

INT 21h, 2Dh – SETAREA OREI SISTEMULUI


Intrare: AH=2Dh;
CH = ora CL = minute DH = secunde DL = 1/100 secundă.
Efect:
 AL = 00h operaţiune reuşită;
 FFh dacă valoarea este invalidă, ora sistemului rămâne neschimbată.
Observaţie: De la DOS 3.3 in sus , funcţia setează si ceasul din CMOS.
Vezi şi: AH=2Bh"DOS",AH=2Ch.
INT 21h, 30h – AFLĂ VERSIUNEA DE DOS
Intrare: AH=30h;
AL = ce să întoarcă în BH (00h OEM număr, 01h localizarea sistemului de
operare).
Efect:
 AL = numărul superior al versiunii (00h dacă DOS 1.x);
 AH = numărul inferior al versiunii;
 BL:CX = seria utilizatorului pe 24-biti (majoritatea versiunilor nu folosesc
aceasta) dacă DOS <5 or AL=00h;
 BH =Număr furnizorului sistemului dacă DOS 5+ şi AL=01h;
 BH = Localizarea sistemului: 08h in ROM, 10h in XMA.
Observaţii:
 DOS 4.01 şi 4.02 se identifică ca versiune 4.00;

138
 MS-DOS 6.21 raporteaza versiunea ca 6.20; versiunea 6.22 returnează
valoarea corectă;
 Windows95+ returnează versiunea 7.00 ( MS-DOS-ul asociat).
Vezi şi: AX=3000h/BX=3000h,AX=3306h,AX=4452h.

INT 21h, 35h – AFLĂ VECTORUL DE ÎNTRERUPERE


Intrare: AH=35h;
AL = numărul întreruperii.
Efect: ES:BX -> tratarea întreruperii curente.
Vezi şi: AH=25h,AX=2503h.

INT 21h, 36h – AFLĂ SPAŢIUL LIBER DE PE DISC


Intrare: AH=36h;
DL = numărul unităţii (0=implicit, 1=A:, 2=B:,3=C:,etc).
Efect:
 AX = FFFFh dacă unitatea este invalidă;
 AX = sectoare per cluster BX = numărul de clustere libere CX = bytes per
sector DX = număr total de clusteri per unitate.
Observaţii:
 spaţiul liber pe unitate în bytes este AX * BX * CX ;
 spaţiul total pe unitate în bytes este AX * CX * DX;
 clusterii indisponibili sunt consideraţi a fi utilizaţi ;
 aceasta funcţie nu dă rezultate corecte pe unităţile CD-ROM; folosiţi în
schimb AX=4402h pentru CD-ROM.
Vezi şi: AH=1Bh,AH=1Ch,AX=4402h"CD-ROM".

INT 21h, 39h - CREEAZĂ UN DIRECTOR


Intrare: AH=39h;
DS:DX -> ASCIIZ numele căii.
Efect:
 CF şters dacă AX a fost şters;
 CF setat în caz de eroare AX = cod eroare (03h,05h).
Observaţii:
139
 Tooate directoarele din calea dată trebuie să existe, mai puţin ultimul;
 eşuează dacă directorul părinte este rădăcina şi este plin;
 DOS 2.x-3.3 permite crearea unui director suficient de îndepărtat în structura
arborescentă de directoare, dar nu din directorul curent dacă calea depăşeşte
64 de caractere.
Vezi şi: AH=3Ah,AH=3Bh,AH=6Dh.

INT 21h, 3Ah - ŞTERGE DIRECTORUL


Intrare: AH=3Ah;
DS:DX -> ASCIIZ calea directorului de şters.
Efect:
 CF şters dacă AX a fost şters;
 CF setat în caz de eroare AX = cod eroare (03h,05h,06h,10h).
Observaţii: directorul trebuie să fie gol (să conţină numai intrări '.' şi '..' ).
Vezi şi: AH=39h,AH=3Bh.

INT 21h, 3Bh - SCHIMBA DIRECTORUL CURENT


Intrare: AH=39h;
DS:DX -> ASCIIZ calea directorului ce va deveni curent (maxim 64 bytes)
Efect:
 CF şters dacă AX a fost şters
 CF setat în caz de eroare AX = cod eroare (03h)
Observaţii: dacă numele directorului include litera unei unităţi, unitatea curentă nu
este schimbată ci numai directorul curent pe unitatea respectivă.
Vezi şi: AH=47h,AH=71h,INT 2F/AX=1105h.

INT 21h, 3Ch – CREAZĂ SAU TRUNCHEAZĂ FIŞIERUL


Intrare:
 AX=3Ch
 CX = atribute fişier;
 DS:DX -> ASCIIZ nume fişier.
Efect:

140
 CF şters dacă a reuşit, AX = tratare fişier;
 CF setat în caz de eroare, AX = cod eroare (03h,04h,05h).
Observaţii: dacă un fişier cu numele dat există este trunchiat la dimensiunea zero.
Vezi şi: AH=16h,AH=3Dh,AH=5Ah,AH=5Bh.

INT 21h, 3Dh – DESCHIDE FIŞIERUL EXISTENT


Intrare:
AX=3Dh;
AL = modurile de acces şi partajare:
Bit 0..2: Modul de acces:
000 = numai citire;
001= numai scriere;
010 = citire/scriere.
Bit 3: rezervat;

Bit 4..6: Modul de partajare:


000 = modul compatibil;
001 = numai programul curent are acces;
010 = interzice scrierea (alte programe pot doar citi fişierul);
011 = interzice citirea (alte programe pot doar să scrie in fişier);
100 = permite totul (alte programe pot scrie şi citi fişierul).
Bit 7: Se moştenesc proprietăţile.

DS:DX -> ASCIIZ nume fişier.

Efect:
 CF şters dacă a reuşit, AX = tratare fişier;
 CF setat în caz de eroare AX = cod eroare (01h,02h,03h,04h,05h,0Ch,56h);
01h = nu exista software pentru partajare;
02h = fişierul nu este găsit;
03h = calea nu este gasita sau fişierul nu există;
04h = nu exista program de tratare a fisierului;
05h = accesul interzis;
0Ch = modul de acces specificat nu este permis.

Observaţii:
 Indicatorul fişierului este setat la începutul fişierului;
 Fişierele trunchiate moştenesc de la fişierul părinte din care au fost trunchiate;
restricţiile de acces şi partajare;
 fişierele pot fi deschise chiar dacă li se dau atribute hidden sau system.
Vezi şi: AH=0Fh,AH=3Ch,AX=4301h,AX=5D00h.

141
INT 21h, 3Eh – ÎNCHIDE FIŞIERUL
Intrare: AH=3Eh;
BX = tratare fişier
Efect:
 CF şters dacă a reuşit, AX şters;
 CF setat în caz de eroare, AX = cod eroare (06h).
Observaţie: odată ce fişierul a fost scris, etichetele cu timpul şi data creerii fişierului
sunt actualizate la valorile curente, iar intrarea în director este reactualizată.
Vezi şi: AH=10h,AH=3Ch,AH=3Dh.

INT 21h, 3Fh - CITEŞTE DIN FIŞIER SAU DISPOZITIV


Intrare:
 AH=3Fh;
 BX = nume fişier;
 CX = număr bytes de citit;
 DS:DX -> buffer de date.
Efect:
 CF şters dacă operaţiunea a reuşit - AX = număr de bytes citiţi (0 dacă EOF
apare înaintea chemării funcţiei);
 CF setat în caz de eroare AX = cod eroare (05h,06h).
Observaţii:
 datele sunt citite începând de la locaţia curentă din fişier, iar poziţia locaţiei
curente este reactualizată după o citire reuşită;
 rezultatul returnat în AX poate fi mai mic decât cel solicitat în CX dacă
survine o citire parţală;
 dacă se citeşte de la CON, citirea se opreşte la primul CR.
Vezi şi: AH=27h,AH=40h,AH=93h.

INT 21h, 40h - SCRIE ÎNTR-UN FIŞIER SAU DISPOZITIV


Intrare:
 AH=40h;
 BX = nume fişier;
 CX = număr bytes de scris;
 DS:DX -> date de scris.

Efect:

142
 CF şters dacă operaţiunea a reuşit -AX = număr de bytes scris la actuala
scriere;
 CF setat în caz de eroare - AX = cod eroare (05h,06h).

Observaţii:
 Dacă CX este zero, datele nu sunt scrise, iar fişierul este trunchiat sau extins
până la poziţia curentă;
 datele sunt scrise începând de la poziţia curentă, iar poziţia în fişier este
reactualizată după fiecare scriere reuşită;
 cauza uzuală pentru care se returnează AX < CX este lipsa de spaţiu liber pe
disc.
Vezi şi: AH=28h,AH=3Fh.

INT 21h, 41H - ŞTERGE FIŞIERUL


Intrare:
 AH=41h;
 DS:DX -> ASCIIZ nume fişier;
 CL = masca atributului fşierului de şters.
Efect:
 CF şters dacă operaţiunea a reuşit, AX şters;
 CF setat în caz de eroare, AX = cod eroare (02h,03h,05h).
Observaţii:
 (DOS 3.1+) caracterele de înlocuire sunt permise dacă sunt apelate via
AX=5D00h, caz în care specificaţiile fişierului trebuie să fie valide (cum sunt
citite cu funcţia AH=60h), şi numai fişierele a căror atribute se potrivesc cu
masca atributelor din CL sunt şterse;
 DOS nu şterge datele din fişier; pur şi simplu fişierul devine inaccesibil
deoarece lanţul de locaţii asociate fişierului este şters din FAT;
 ştergerea unui fişier deschis poate conduce la erori în sistemul de fişiere.
Vezi şi: AH=13h,AX=4301h,AX=4380h,AX=5D00h,AH=60h,AH=71h.

INT 21h, 42h - SETEAZĂ POZIŢIA CURENTĂ ÎN FIŞIER


Intrare:
 AH=42h;

143
 AL =originea deplasării: 00h începutul fişierului 01h poziţia curentă în fişier
02h sfârşitul fişierului;
 BX = nume fişier;
 CX:DX = deplasarea (CX octetul mai semnificativ, DX octetul mai puţin
semnificativ).
Efect:
 CF şters dacă operaţiunea a reuşit, DX:AX = noua poziţie în fişier în bytes de
la începutul fişierului ;
 CF setat în caz de eroare, AX = cod eroare (01h,06h).
Observaţii:
 Pentru originile 01h şi 02h, deplasarea este un numar cu semn, deci
indicatorul ar putea fi poziţionat înaintea începutului fişierului; nici o eroare
nu este semnalată în acest caz, dar încercările ulterioare de intrare/ieşire vor
produce erori;
 dacă noua poziţie este dincolo de sfârşitul fişierului, fişierul va fi extins la
următoarea scriere (vezi AH=40h).
Vezi şi: AH=24h.

INT 21h, 43 - AFLĂ ATRIBUTELE FIŞIERULUI


Intrare:
 AH=43h;
 AL = 00h;
 DS:DX -> Nume fişier (ASCIIZ).
Efect:
 CF şters dacă operaţiunea a reuşit, CX = atributele fişierului;
 CF setat în caz de eroare, AX = cod eroare (01h,02h,03h,05h).
Observaţie: Windows for Workgroups returnează cod eroare 05h (acces nepermis) în
locul codului de eroare 02h (fişierul nu a fost găsit) atunci când se încearcă aflarea
atributelor unui fişier inexistent.
Vezi şi: AX=4301h,AX=4310h,AX=7143h,AH=B6h.

INT 21h, 43 – SETEAZĂ ATRIBUTELE FIŞIERULUI


Intrare:
 AH=43h;
 AL = 01h;

144
 CX = noile atribute fişier;
 DS:DX -> Nume fişier (ASCIIZ).

Efect:
 CF şters dacă operaţiunea a reuşit, AX şters;
 CF setat în caz de eroare, AX = cod eroare (01h,02h,03h,05h).
Observaţii:
 nu va schimba eticheta de volum a directorului sau biţii atributelor;
directorului, dar va schimba alţi biţi ai atributelor din director;
 MS-DOS 4.01 raportează fişierul închis dacă acesta era deschis.
Vezi şi: AX=4300h,AX=4311h,AX=7143h,INT 2F/AX=110Eh.
Câmpul biţilor pentru atributele fişierelor:
Biţi 7 6 5 4 3 2 1 0
Descriere Partajabil - arhivă director eticheta volum sistem ascuns numai citire

INT 21h, 47h – AFLĂ DIRECTORUL CURENT


Intrare:
 AH=47h;
 DL = număr unitate (00h = implicit, 01h = A:, etc);
 DS:SI -> buffer de 64 bytes pentru numele căii (ASCIIZ ).
Efect:
 CF şters dacă operaţiunea a reuşit;
 CF setat în caz de eroare, AX = cod eroare (0Fh).
Observaţii:
 Calea returnată nu include unitatea sau primul backslash;
 Multe din produsele Microsoft Windows se bazează pe faptul că AX devine
0100h când operaţiunea a reuşit.
Vezi şi: AH=19h,AH=3Bh,AH=71h.

INT 21h, 4Ch – IEŞIRE CU COD DE FINALIZARE


Intrare:
 AH=4Ch;
 AL = cod finalizare.

145
Efect: nu se mai întoarce.
Observaţii: în afara cazului în care procesul este propriul său părinte, toate fişierele
sunt închise şi toată memoria aparţinînd procesului este eliberată.
Vezi şi: AH=00h,AH=26h,AH=4Bh,AH=4Dh.

INT 21h, 4Dh – AFLĂ CODUL RETURNAT (NIVELUL ERORII)


Intrare: AH=4Dh;
Efect:
 AH = tip terminare (00=normal, 01h control-C abandon, 02h=abandon eroare
critică, 03h termină şi rămâne resident);
 AL = codul returnat.
Observaţii:
 Locaţia în care sistemul DOS stochează codul returnat este ştearsă după ce a
fost citită de această funcţie, aşadar codul returnat poate fi aflat o singură dată;
 COMMAND.COM stochează codul returnat la ultima comandă externă, ca
nivel al erorii
Vezi şi: AH=4Bh,AH=4Ch,AH=8Ah.

INT 21h, 54h – AFLĂ STAREA FANIONULUI DE VERIFICARE


Intrare: AH=54h;
Efect:

 AL = fanion de verificare (00h=off, 01h=on, deci toate scrierile pe disc sunt


verificate după scriere).
Vezi şi: AH=2Eh.

INT 21h, 56h - REDENUMEŞTE FIŞIERUL


Intrare:
 AH=56h;
 DS:DX -> Numele existent al fişierului (ASCIIZ fără caractere speciale);
 ES:DI -> Noul nume al fişierului (ASCIIZ fără caractere speciale);
 CL = masca atributelor.
Efect:
 CF şters dacă operaţiunea a reuşit;
 CF setat în caz de eroare, AX= cod eroare (02h,03h,05h,11h).

146
Observaţii:
 Permite mutarea între directoare cu acelaşi volum logic;
 această funcţie nu setează atributul arhivă;
 fişierele deschise nu vor fi redenumite;
 (DOS 3.0+) permite redenumirea directoarelor.

INT 21h, 57h – AFLĂ DATA ULTIMEI SCRIERI ÎN FIŞIER


Intrare:
 AH=57h;
 AL = 00h (Află attributele);
 BX = nume fişier.

Efect:
 CF şters dacă operaţiunea a reuşit, CX = file's time DX = file's date;
 CF setat în caz de eroare, AX = cod eroare (01h,06h).
Vezi şi: AX=5701h.
Câmpul biţilor pentru ora creării fişierului:
Biţi 15-11 10-5 4-0
Descriere ora minutul secunda
Câmpul biţilor pentru data creării fişierului:
Biţi 15-9 8-5 4-0
Descriere anul (1980-) luna ziua

INT 21h, 57h – SETAREA DATEI ULTIMEI SCRIERI ÎN FIŞIER


Intrare:
 AH=57h;
 AL =01h (Setează atributele);
 BX = nume fişier;
 CX = noua oră;
 DX = noua dată.
Efect:
 CF şters dacă operaţiunea a reuşit;
 CF setat în caz de eroareAX = cod eroare (01h,06h).

147
Vezi şi: AX=5700h.

ANEXA 4

Rezolvările programelor

Programul 2.1
.model small
.stack 100h
.code

start: mov al,99h


mov bl,0AAh
mov cl,0BBh
mov dl,0CCh

; terminate program
term: jmp term

end start

Programul 2.2
.model small
.stack 100h
.code

start: mov al,22h


mov bl,al
mov bh,al
mov cl,al
mov dh,al

; terminate program
term: jmp term

end start

Programul 2.3

.model small

148
.stack 100h
.code
start: mov ax,1122h
mov bx,3344h
mov cx,5566h
mov dx,7788h

term: jmp term


end start

Programul 2.4

.model small
.stack 100h
.code
start: mov bx,1122h
mov cx,3344h
mov dx,bx
mov ax,cx

term: jmp term


end start

Programul 2.5

.model small
.stack 100h
.code
start: mov ax,1234h
mov ds,ax
mov dx,5678
term: jmp term
end start

Programul 2.6

.model small
.stack 100h
.code
start:
mov al,99h
mov bh,0AAh

mov ah,al

149
mov al,bh
mov bh,ah

term: jmp term


end start

Programul 2.7

.model small
.stack 100h
.code
start:
mov al,11h
mov bl,22h
mov cx,3344h
mov dx,5566h
xchg al,bl
xchg cx,dx

term: jmp term


end start

Programul 2.8

.model small
.stack 100h
.code
start: mov al,0AAh
mov ah,0BBh
mov bl,0CCh
mov bh,0DDh
xchg al,ah
xchg ah,bl
xchg bl,bh

term: jmp term


end start

Programul 2.9

.model small

150
.stack 100h
.code
start:
mov ax,1122h
mov bx,3344h
mov cx,5566h
mov dx,7788h
add al,66h
add al,bl
sub al,cl
sub al,22h
add al,bl ;Rezultatul este in AL
add al,cl ;si se aduna cu termenul al treilea
add al,dl ;si apoi cu al patrulea
; Se va observa ca la ultima adunare (EEh+88h) apare
carry
term: jmp term
end start

Programul 2.10

.model small
.stack 100h
.code
start:
mov ax,1122h
mov bx,3344h
mov cx,5566h
mov dx,7788h
add ax,6666h
add ax,bx
sub ax,cx
sub ax,22h
add ax,bx ;Rezultatul este in AL
add ax,cx ;si se aduna cu termenul al treilea
add ax,dx ;si apoi cu al patrulea
; Se va observa ca la ultima adunare (DDEEh+7788h) apare
carry
term: jmp term
end start

Programul 2.11

.model small
.stack 100h
.code
start: mov ax,1122h

151
mov bx,3344h
mov cx,5566h
mov dx,7788h
add bx,dx ;NU apare transport
adc ax,cx ;deci urmatoarea adunare NU necesita
;sa-l includa si pe acesta
;Corect este totusi sa se tina seama de aceasta
;eventualitate
term: jmp term
end start

Programul 2.12

.model small
.stack 100h
.code
start:
mov ax,5566h
mov bx,7788h
mov cx,99AAh
mov dx,0BBCCh
add bx,dx ;Apare transport
adc ax,cx ;deci urmatoarea adunare va trebui
;sa-l includa si pe acesta

term: jmp term


end start

Programul 2.13

.model small
.stack 100h
.code
start:
mov ax,5566h
mov bx,7788h
mov cx,1122h
mov dx,3344h
sub bx,dx ;Nu apare imprumut
sbb ax,cx ;totusi corect este ca urmatoarea
;scadere sa-l includa si pe
acesta

term: jmp term


end start

152
Programul 2.14

.model small
.stack 100h
.code
start:
mov ax,2233h
mov bx,4455h
mov cx,6677h
mov dx,8899h
sub bx,dx ;Apare imprumut
sbb ax,cx ;deci urmatoarea scadere va trebui
;sa-l includa si pe acesta

term: jmp term


end start

Programul 3.1

.model small
.stack 100

.code
start: mov al,22
MOV BX,0
MOV bx[20],al
MOV DS:[30],al

term: jmp term


end start

Programul 3.2

.model small
.stack 100h
.code
start: mov al,22h
MOV BX, 10h
MOV [bx],al
mov bx,30h
MOV [bx],al

153
mov bp,120h ;Pentru segmentul de stiva se
face
mov [bp],al ;adresarea prin intermediul BP

term: jmp term


end start

Programul 3.3
.model small
.stack 100h
.code
start: mov ax,3344h
MOV BX, 20h
MOV [bx],al

term: jmp term


end start

Programul 3.4

.model small
.stack 100

.code
start: MOV BX,0
MOV [bx+20h],1122h
MOV [BX+30h],byte ptr 44h

term: jmp term


end start

Programul 3.5

.radix 16
.model small
.stack 100

.code
start: mov ax,33EEh
MOV BX,0
MOV [bx+30h],ax
mov al,22h
mov ah,0
add [bx+30h],ax

154
term: jmp term
end start

Programul 3.6

.radix 16
.model small
.stack 100

.code
start: mov bx,0
mov word ptr [bx+10], 44; Specifica 2 octeti
add [bx+10],122 ;pentru a aduna pe 2 octeti

term: jmp term


end start

Programul 3.7

.radix 16
.model small
.stack 100

.code
start: mov al,44
mov word ptr ds:[30], al ; Nu s-a folosit nici
add ds:[30],122;un registru pt adresare
indirecta
;S-au folosit adresari imediate
term: jmp term
end start

Programul 3.8

.radix 16
.MODEL SMALL
.STACK 100H
.CODE
Start:

mov ch,ds:[10]

155
mov dx,ds:[11]
mov ds:[20],byte ptr 22
mov ds:[21],word ptr 8877
mov ds:[30],ch
mov ds:[31],dx
; S-au folosit adresari imediate (nerecomandat)
term:
jmp term

END Start

SAU:

.radix 16
.MODEL SMALL
.STACK 100H
adr equ 0
.CODE
Start:

mov ch,ds:[adr+10]
mov dx,ds:[adr+11]
mov ds:[adr+20],byte ptr 22
mov ds:[adr+21],word ptr 8877
mov ds:[adr+30],ch
mov ds:[adr+31],dx
;Avantajul este ca modificand valoarea adr se
;translateaza intreaga structura unde se doreste
term: jmp term

END Start

Programul 3.9

.radix 16
.MODEL SMALL
.STACK 100H
.data
dateo db 11,22 ;se declara 2 locatii de 1 octet
datec dw 4455,6677 ;se declara 2 locatii de 2
octeti

.code
Start:
mov ax,@data
mov ds,ax
mov al,dateo ; Desi nu apar paranteze drepte,dateo
add al,date0+1;simbolizeaza continutul unei locatii

156
mov bx,datec ;de memorie, iar datec continutul a
add bx,datec+2;doua locatii de memorie
mov ah,0
sub bx,ax
term:
jmp term

END Start

Programul 3.10

.radix 16
.MODEL SMALL
.STACK 100H
.data
adr1 dw ?

.CODE
Start:
mov ax,@data; Aceste 2 instructiuni nu sunt
;obligatorii pentru ca nu se declara
mov ds,ax ;date numerice initiale
mov ax,8899
mov cx,2211
mov dl,10
mov bx,20

mov adr1,ax ;Salveaza continutul initial al lui AX


add ax,cx
mov dh,0 ;Pentru adunarea cu BX a lui DX=0010
add bx,dx
mov [bx],ax
mov ax,adr1
sub ax,cx
mov [bx+2],ax; Primul rezultat a fost de 2 octeti

term:
jmp term

END Start

Programul 3.11

.radix 16
.MODEL SMALL
.STACK 100H
.data

157
adr1 dw ?

.CODE
Start:
mov ax,@data; Aceste 2 instructiuni nu sunt
;obligatorii pentru ca nu se
declara
mov ds,ax ;date numerice initiale
mov ax,1122
mov bx,3344
mov cx,5566
mov dx,7788
mov adr1,ax
;sau mov DS[0],ax
;sau mov [bx],ax ;se scrie in locatia [3344]
mov ax,bx
mov bx,cx
mov cx,dx
mov dx,adr1

term:
jmp term

END Start

Programul 3.12

.radix 16
.MODEL SMALL
.STACK 100H
.CODE
Start:
mov bx,10
mov al,1
mov [bx],al
inc al
inc bx
mov [bx],al
inc al
inc bx
mov [bx],al
inc al
inc bx
mov [bx],al

term: jmp term

END Start

158
Programul 3.13

.radix 16
.MODEL SMALL
.STACK 100H
.CODE
Start:
mov bx,10
mov ax,1000
mov [bx],ax
inc ax
inc bx ;AX ocupa 2 locatii consecutive
inc bx ;deci BX trebuie marit cu 2
mov [bx],ax
inc ax
inc bx
inc bx
mov [bx],ax
inc ax
inc bx
inc bx
mov [bx],ax

term: jmp term

END Start

Programul 3.14

.radix 16
.MODEL SMALL
.STACK 100H

.CODE
Start:

mov bx,10
mov al,5
mov [bx],al
add al,5
inc bx
mov [bx],al
add al,5
inc bx

159
mov [bx],al
add al,5
inc bx
mov [bx],al

term: jmp term

END Start

Programul 3.15

.radix 16
.MODEL SMALL
.STACK 100H
.CODE
Start:
mov bx,10
mov ax,201
mov [bx],ax
add ax,201
inc bx
inc bx
mov [bx],ax
add ax,201
inc bx
inc bx
mov [bx],ax
add ax,201
inc bx
inc bx
mov [bx],ax

term: jmp term

END Start

Programul 4.1

.MODEL SMALL
.STACK 100H
.CODE
Start:

mov ax,1122
mov bx,3344
mov cx,5566

160
mov dx,7788

push ax
push bx
push cx
push dx
pop cx ;La POP, stiva furnizeaza informatia
pop bx ;in ordine inversa fata de PUSH
pop ax ;dupa principiul "Last In-First Out"
pop dx

term: jmp term

END Start

Programul 4.3

.radix 16
.MODEL SMALL
.STACK 100H
.data
sursa dw 1122,3344,5566
dest dw 3 DUP(?)
.CODE
Start:
mov ax,@data
mov ds,ax
mov ax,sursa
mov dest,ax
mov ax,sursa+2 ; Fusesera ocupate 2 locatii
mov dest+2,ax ;deci s-a avansat cu 2 in memorie
mov ax,sursa+4
mov dest+4,ax

term: jmp term

END Start

Programul 4.4

.Radix 16
.Model small
.Stack 100h
.Data
sir DB 1,2,3,4,5,6,7,8,9,0a

.Code

161
start: mov ax,seg sir; Se putea folosi si MOV AS,@data
mov ds,ax
mov al,sir
mov ah,sir+9
mov sir+9,al
mov sir,ah
mov al,sir+1
mov ah,sir+8
mov sir+8,al
mov sir+1,ah

term: jmp term


end start

Programul 4.5

.radix 16
.model small
.stack 100h
.data
tabela1 db 13,14,15,16,1,2,3,4,5
.code
start: mov ax,@data ;Adresa segmentului de date
mov ds,ax ;se incarca in DS
mov bx,0
mov al,5
xlat
mov dl,al
;Indexarea incepe de la 0 deci elementul 5 are valoarea 2
mov al,8
xlat
mov dh,al
;Indexarea incepe de la 0 deci elementul 8 are valoarea 5
term: jmp term
end start

Programul 4.6

.radix 16
.model small
.stack 100h
.code
start:
les ax,ds:10
; Se va observa efectul asupra lui ES si AX in functie

162
;de datele existente initial in memorie incepand de la
;adresa 10h.

term: jmp term


end start

Programul 4.7

.radix 16
.model small
.stack 100h
.data
adresa1 db 13,14,15,1,2,3
adresa2 db 16,17,18,19
.code
start: mov ax,@data ;Adresa segmentului de date
mov ds,ax ;se incarca in DS
lea bx,adresa1 ;In DI se va afla offset-ul in
;memoria de date al sirului
;notat "adresa1" (in acest caz 06)
mov al,[bx+2] ;Transfera din a treia locatie a
;sirului in AL
lea bx,adresa2 ;Noua adresa efectiva
mov ah,[bx+3] ;de la care este luat 19h
mov [bx+3],al ;si la care este trimis 15h

lea bx,adresa1 ;Adresa efectiva unde trebuie


mov [bx+2],ah ;trimis 19h

term: jmp term


end start

Programul 5.1

.radix 16
.model small
.stack 100h
.code
start:
mov al,11
mov bx,10
mov cl,33
mov dl,44
mov [bx],byte ptr 99; Transfer pe 1 octet
add al,cl
adc al,dl;In cazul general, putea sa apara CY
sub [bx],al ;Rezultatul in memorie la [bx]

163
mov al,[bx]
mov [bx+1],al ;Se trimite la [bx+1]

term: jmp term


end start

Programul 5.2

.radix 16
.model small
.stack 100h
.code
start:
mov ax,1122
mov bx,10
mov cx,3344
mov dx,5566
mov [bx],0AABBh
add ax,cx
adc ax,dx; In cazul general, putea sa apara CY
sub [bx],ax
mov ax,[bx]
mov [bx+2],ax ;Rezultatul era pe 2 octeti

term: jmp term


end start

Programul 5.3

.radix 16
.model small
.stack 100h
.code
start:
mov al,9
mov bl,19
mov cl,29
inc al
inc bl
inc cl
mul bl
mov ch,0 ;Pregatim CX pentru inmultire cu rezultat
mul cx ;de 16 biti

term: jmp term


end start

164
Programul 5.4

.radix 16
.model small
.stack 100h
.data
rez dw 2 dup(?); 4 locatii pentru rezultat c251ec98
temp dw 2 dup(?); salvari temporare de registre
.code
start:
mov ax,@data
mov ds,ax
mov bx,1122
mov cx,5566
mov dx,22

mov temp,dx ;temp =22


mov ax,bx
mul cx ;Rezultat in DX:AX=05b71d8c
mov temp+2,dx;Stocheaza dx la temp+2=05b7
mov bx,temp ;Reface bx=22
mul bx ;Inmulteste ax=1D8C cu 22
mov rez+2,ax ;Stocheaza in ultimii 2 octeti ax
mov rez,dx ;si in primii 2 octeti dx
mov ax,temp+2;Pregateste 05B7
mul bx ;si inmulteste cu 22
add rez,ax ;aduna rezultatul la primii 2 octeti

term:
jmp term
end start

Programul 5.5

.radix 16
.model small
.stack 100h
.data
tempw dw ?; locatie temporara pentru 1 word
tempb db ?; locatie temporara pentru 1 byte
.code
start: mov ax,@data
mov ds,ax
mov cx,6655
mov bl,44
mov dl,22

165
mov tempb,dl; Impartirea se face cu 16 biti
mov dx,0 ;deci trebuie adus DX la 0
mov ax,cx ;formand cu AX deimpartitul
mov bh,0 ;pregateste cei 16 biti
div bx ;ai impartitorului
mov tempw,dx;tempw=restul
mov dl,tempb;reface DL
mul dl ;Si inmulteste cu catul
adc ax,tempw;iar rezultatul cu CY aduna la rest

term: jmp term


end start

Programul 6.1

.radix 16
.model small
.stack 100h
.code
start:
mov ax,0EEEEh
and ax,0F

term: jmp term


end start

Programul 6.2

.radix 16
.model small
.stack 100h
.code
start:
mov ax,0EEEEh
or ax,1111111100001111b

term: jmp term


end start

Programul 6.3

.radix 16
.model small
.stack 100h

166
.code
start:
mov bl,10100110b; Valoare initiala BL
mov cl,00011111b; Valoare initiala CL
and bl,00001100b; Separa bitii 2 si 3 din BL
and cl,11110011b; Bitii omologi din CL anulati
or cl,bl ; Combina rezultatele

term: jmp term


end start

Programul 6.4

.radix 16
.model small
.stack 100h
.code
start: mov dl,05 ;Valoarea initiala a lui DL
mov al,0 ;Pregateste AL pentru a prelua CARRY
mov bx,0 ;Pregateste pointerul in memorie
ror dl,1 ;Rotire dreapta. Bitul 0 in CARRY
adc al,0 ;Aduna cu CARRY. Rezulta AL=CARRY
mov [bx],al;Trimite in prima locatie
xor al,al ;Sterge AL pentru urmatorul CARRY

;procesul se repata pentru celelalte 3 locatii


ror dl,1
adc al,0
mov [bx+1],al
xor al,al

ror dl,1
adc al,0
mov [bx+2],al
xor al,al

ror dl,1
adc al,0
mov [bx+3],al

term: jmp term


end start

Programul 6.5

.radix 16
.model small
.stack 100h

167
.code
start:
mov bl,12 ;Valoarea initiala a lui BL
mov ch,56 ;Valoarea initiala a lui CH
mov al,bl ;Copii de lucru in
mov dh,ch ;AL si DH
and al,0Fh ;Ia semioctetul inferior din BL
and bl,0F0h;Ramine in BL doar octetul superior

and dh,0F0h;Ia semioctetul superior din CH


and ch,0Fh ;Ramine in CH doar octetul inferior

shr bx,4 ;Deplaseaza cu un semioctet dreapta


shl cx,4 ;Deplaseaza cu un semioctet stanga
or ch,al ;Combina semioctetii
or bl,dh
xchg bl,ch ;Inverseaza registrele

term: jmp term


end start

Programul 6.6

.radix 16
.model small
.stack 100h
.code
start:
mov cl,25
;Valoarea initiala a lui CL
mov dh,55
;Valoarea initiala a lui DH
mov al,cl
;Copie de lucru a lui CL
xor al,dh
;Daca 2 biti omologi sunt identici,
;XOR îi anuleaza, restul devin 1
and cl,al ;Sunt pusi in 0 in CL numai bitii
;care fusesera identici cu ai lui DH
term: jmp term
end start

Programul 6.7

.radix 16
.model small
.stack 100h
.code
start:

168
mov cl,25 ;Valoarea initiala a lui CL
mov dh,55 ;Valoarea initiala a lui DH
mov al,cl ;Copie de lucru a lui CL
xor al,dh ;Daca 2 biti omologi sunt identici,
XOR ;ii anuleaza, restul devin 1
not al ;Inverseaza bitii
or cl,al ;Sunt pusi in 1 in CL numai bitii
;care fusesera identici cu ai lui DH
term: jmp term
end start

Programul 6.8

.radix 16
.model small
.stack 100h
.code
start:
mov bp,77 ; Valoarea initiala in BP
mov dx,bp ;Copie de lucru in DX
shl dx,8 ;Inmulteste copia cu 256
shl bp,6 ;Inmulteste valoarea initiala cu 64
add bp,dx ;Aduna 256+64=320 ori valoarea initiala

term: jmp term


end start

Programul 6.9

.radix 16
.model small
.stack 100h
.code
start:
mov bp,33 ; Valoarea initiala in BP
mov dx,bp ;Copie de lucru in dx
shl dx,9 ;Inmulteste copia cu 512
shl bp,7 ;Inmulteste valoarea initiala cu 128
add bp,dx ;Aduna 512+128=640 ori valoarea initiala

term: jmp term


end start

169
Programul 7.1

.radix 16
.model small
.stack 100h
.data
adr1 dw 7777
adr2 dw 3333
adr3 dw 2222

.code
start: mov ax,@data
mov ds,ax
mov ax,adr1
mov bx,adr2
cmp ax,bx ;Compara numerele 1 si 2
jb comp2 ;Daca 1 e mai mic, treci la comparatia 2
mov adr1,bx;Daca 1 e mai mare se trimit in memorie
mov adr2,ax;In ordine inversa
comp2:
mov ax,adr2
mov bx,adr3
cmp ax,bx ;Compara numerele 2 si 3
jb comp3 ;Daca 2 e mai mic, treci la comparatia 3
mov adr2,bx;Daca 2 e mai mare se trimit in memorie
mov adr3,ax;In ordine inversa
comp3:
mov ax,adr1;Posibil ca in urma inversarii 2 cu 3
mov bx,adr2;in pozitia 2 sa fie acum un numar
cmp ax,bx ;mai mic si decat cel din pozitia 1
jb term ;Daca sunt in ordine, termina
mov adr1,bx;Daca nu, se face din nou
mov adr2,ax;inversarea in memorie

term: jmp term


end start

Programul 7.2

.radix 16
.model small
.stack 100h
.code
start:
mov bx,0
mov cx,20
reia: mov [bx],byte ptr 33
inc bx

170
dec cx
jnz reia

term: jmp term


end start

Programul 7.3

.radix 16
.model small
.stack 100h
.code
start:
mov bx,0
mov cx,20
mov al,5
reia: mov [bx],al
inc al
inc bx
dec cx
jnz reia

term: jmp term


end start

Programul 7.4

.radix 16
.model small
.stack 100h
.code
start:
mov bx,0
mov cx,20
mov al,5
reia: mov [bx],al
inc al
inc bx
dec cx
jnz reia ;S-a terminat incarcarea in memorie
;Acum se vor suma numerele din memorie
mov cx,20
mov ax,0 ;In AX va apare suma
mov bx,0
mov dh,0 ;Suma va fi pe doi octeti,
reia1: mov dl,[bx];deci se pregateste adunarea cu DX

171
add ax,dx
inc bx
dec cx
jnz reia1
mov [bx],ah;Bx este acum 20
mov [bx+1],al

term: jmp term


end start

Programul 7.5

.radix 16
.model small
.stack 100h
.code
start: mov bx,0
mov cx,20
mov ax,10 ;Progresia da si numere pe 2 octeti
reia: mov [bx],ax;deci se va folosi AX
add ax,10
inc bx ;Fiecare numar ocupa 2 octeti
inc bx ;deci bx se incrementeaza de 2 ori
dec cx
jnz reia ;S-a terminat incarcarea in memorie

term: jmp term


end start

Programul 7.6

.radix 16
.model small
.stack 100h
.code
start:
mov bx,0
mov cx,20
mov ax,200 ;Numere pe 2 octeti
reia: mov [bx],ax ;deci se va folosi AX
sub ax,10
inc bx ;Fiecare numar ocupa 2 octeti
inc bx ;deci bx se incrementeaza de 2 ori
dec cx
jnz reia ;S-a terminat incarcarea in memorie

term: jmp term

172
end start

Programul 7.7

.radix 16
.model small
.stack 100h
.code
start:
mov bx,0
mov cx,10
mov ah,[bx] ;Consideram primul numar ca maxim
inc bx
dec cx
reia: mov al,[bx] ;Ia urmatorul numar
cmp ah,al ;compara cu cel maxim
ja conti ;Daca primul e mai mare continua
mov ah,al ;Daca cel nou e mai mare, acesta
;devine noul maxim
conti: inc bx ;Incrementeaza adresa
dec cx ;decrementeaza contorul
jnz reia ;reia cautarea
mov [bx],ah ;Dupa ultima locatie citita scrie
;numarul maxim gasit

term: jmp term


end start

Programul 8.1

.radix 16
.model small
.stack 100h
LungimeBloc equ 20
.DATA
BlocSursa dw LungimeBloc dup(1122)
BlocDest dw LungimeBloc dup(?)

.code
start:
mov ax,seg BlocSursa
; Se putea folosi si
; mov ax,@data
mov ds,ax ;Segmentul sursa în DS

173
mov ax,seg BlocDest ;Necesar numai daca
;blocurile sunt în
;segmente diferite
mov es,ax ;Segmentul destinatie ES
cld ;directia în sensul
;cresterii adreselor
mov si, offset BlocSursa ;AE a sursei în SI
mov di, offset BlocSursa+60;AE a destinatiei în DI
mov cx, LungimeBloc ;Numarul de transferuri în CX
bucla:
lodsw ;Încarca în AX un octet
stosw ;si îl trimite la destinatie
loop bucla ;Decrementeaza CX si reia
;bucla pâna când CX devine 0
term:
jmp term
end start

Programul 8.4

.radix 16
.model small
.stack 100h
.DATA
BlocSursa db 'jgasjagsasasgauahdjushd'
LB equ $-BlocSursa ;Asamblorul
;calculeaza lungimea blocului
.code
start:
mov ax,@data
mov ds,ax
mov es,ax ;Încarca în ES segmentul de
;date (pentru SCASB)
mov di, offset BlocSursa ;Încarca în DI adresa
;sirului(Pentru SCASB)
mov cx, LB ;În CX lungimea sirului
mov al,'a' ;Constanta de comparat
mov bh,0 ;Valoare initiala contor
bucla:
scasb ;Compara AL cu un octetul de
;la [ES:DI] din sir
jnz conti ;Daca nu e egalitate sare
inc bh ;Daca e 'a', incrementeaza BH
conti:
loop bucla ;Reluare daca nu s-a terminat

term:
jmp term
end start

174
Programul 8.5

.radix 16
.radix 16
.model small
.stack 100h
.data
BlocSursa db 'ghfafasfasfahsyfhhhsaad'
LB equ $-BlocSursa
.code
start:
mov ax,@data
mov ds,ax
mov es,ax ;Incarca in ES segmentul de date
;(pentru SCASB)
mov di, offset BlocSursa;Incarca in DI adresa
;sirului(Pentru SCASB)

mov cx,LB ;Contorul de comparatii in CX


mov ax,'af' ;Constanta de comparat cu octetii
;inversati (cum se compara
;cu cuvintele din memorie)
bucla:
scasw ;Compara AX cu cuvantul respectiv
jnz b1 ;Daca nu este secventa 'fa', se sare
inc bh ;Daca s-a gasit 'fa' incrementeaza BH
b1: dec di
loop bucla ;Reluare daca nu s-a terminat sirul

term:
jmp term
end start

Programul 8.7

.radix 16
.model small
.stack 100h
.DATA

Sir1 db '6512631827961792'
LB equ $-Sir1 ;Lungimea este data de sirul 1
Sir2 db '7531790734264725'

175
.code
start:
mov ax,@data
mov ds,ax ;Încarca în DS segmentul de date
mov es,ax ;Încarca în ES segmentul de date
mov si, offset Sir1;Încarca în SI adresa sirului 1
mov di, offset Sir2;Încarca în DI adresa sirului 2
mov cx,LB ;Contorul de comparatii în CX

bucla:
cmpsb ;Compara AL cu octetul respectiv
jnz b1 ;Daca nu este egalitate, se sare
inc bh ;Daca s-a gasit egalitate, se
;incrementeaza BH
jmp b3 ;si se trece la urmatoarea pereche
b1: jb b2 ;Daca este mai mic sare
inc dh ;Daca e mai mare incrementeaza DH
jmp b3 ;si se trece la urmatoarea pereche
b2: inc dl ;Daca era mai mic incrementeaza DL
b3: loop bucla ;Reluare daca nu s-a terminat

term: jmp term


end start

Programul 8.8

.radix 16
.model small
.stack 100h
.DATA
Sir1 db 'ABCDEFGHIJKL'
LB equ $-Sir1 ;Lungimea este data de sirul 1
.code
start:
mov ax,@data
mov ds,ax ;Încarca în DS segmentul de date
mov es,ax ;Încarca în ES segmentul de date
mov di, offset Sir1 ;Încarca în DI adresa
sirului
mov cx,LB ;Contorul de comparatii în CX
mov al,'E'
repnz scasb ;Compara pana la prima egalitate
neg cx ;In CX este numarul ramas din LB
add cx,LB ;si trebuie scazut din LB
term: jmp term
end start

Programul 8.9

176
.radix 16
.model small
.stack 100h
.DATA
Sir1 db '123456789'
LB equ $-Sir1 ;Lungimea este data de sirul 1
Sir2 db '987654321'
.code
start:
mov ax,@data
mov ds,ax ;Încarca în DS segmentul de date
mov es,ax ;Încarca în ES segmentul de date
mov si, offset Sir1;Încarca în SI adresa sirului 1
mov di, offset Sir2;Încarca în DI adresa sirului 2
mov cx,LB ;Contorul de comparatii în CX
repnz cmpsb ;Compara pana la prima egalitate
neg cx ;In CX este numarul ramas din LB
add cx,LB ;si trebuie scazut din LB

term:
jmp term
end start

Programul 8.10

.model small
.stack 100h
.DATA
Sir1 db '112233445566'
LB equ $-Sir1 ;Lungimea este data de sirul 1
Sir2 db '112244335566'
.code
start:
mov ax,@data
mov ds,ax ;Încarca în DS segmentul de date
mov es,ax ;Încarca în ES segmentul de date
mov si, offset Sir1;Încarca în SI adresa sirului 1
mov di, offset Sir2;Încarca în DI adresa sirului 2
mov cx,LB ;Contorul de comparatii în CX

repz cmpsb ;Compara pana la prima inegalitate


neg cx ;In CX este numarul ramas din LB
add cx,LB ;si trebuie scazut din LB
term:
jmp term
end start

177
Programul 9.1

.radix 16
.model small
.stack 100h
.code
start:
mov dl,30 ;Primul cod ASCII
mov dh,80 ;Ultimul cod ASCII
reia:
mov ah,02 ;Functia 02
Int 21h
inc dl ;Urmatorul cod ASCII
cmp dh,dl ;S-a ajuns la ultimul?
jnz reia ;Daca nu, se reia ciclul

term:
mov ah,4Ch;Iesirea se face cu functia 4C
int 21 ;si se poate vedea ecranul cu
end start ;comanda "User Screen" submeniul Window

Programul 9.2

.radix 16
.model small
.stack 100h
.data
sir1 db 'Un sir de caractere terminate cu dolar$'
.code
start: mov ax,@data
mov ds,ax
mov dx,offset sir1;Adresa efectiva a sirului in DS
mov ah,09;Functia 09
Int 21h

term: mov ah,4Ch


int 21
end start

Programul 9.3

.radix 16
.model small
.stack 100h

178
.data
sir1 db 'Primul sir de caractere',0dh,0ah,'$'
sir2 db 'Al doilea sir de caractere $'
.code
start:
mov ax,@data
mov ds,ax
mov dx,offset sir1;Adresa efectiva a sirului 1 in DS
mov ah,09 ;Functia 09
Int 21h
mov dx,offset sir2;Adresa efectiva a sirului 2 in DS
mov ah,09 ;Functia 09
Int 21h
term:
mov ah,4Ch
int 21
end start

Programul 9.4

.radix 16
.model small
.stack 100h

.code
start:
mov ah,01 ;Citire tasta in AL
Int 21h
mov dl,al ;Pentru afisare, codul ASCII in DL
mov ah,02 ;Functia 02
Int 21h
cmp al,0dh;S-a tastat CR?
jnz start ;Daca nu, reia

term: mov ah,4Ch


int 21
end start

Programul 9.5

.radix 16
.model small
.stack 100h
.code

179
start:
mov ah,07 ;Citire tasta in AL, fara ecou
Int 21h
mov dl,al ;Pentru afisare, codul ASCII in DL
mov ah,02 ;Functia 02
Int 21h
cmp al,0dh;S-a tastat CR?
jnz start ;Daca nu, reia

term: mov ah,4Ch


int 21
end start

Programul 9.6

.radix 16
.model small
.stack 100h
.code
start:
mov ah,01 ;Citire tasta in AL, cu ecou
Int 21h
sub al,20
mov dl,al ;Pentru afisare, codul ASCII in DL
mov ah,02 ;Functia 02
Int 21h
add al,20
cmp al,0dh;S-a tastat CR?
jnz start ;Daca nu, reia

term:
mov ah,4Ch
int 21
end start

Programul 9.7

.radix 16
.model small
.stack 100h
.data
buff0 db 10 ;Lungimea permisa a sirului
buff1 db ? ;Rezervare (lungimea actuala)
buff2 db 10 dup (?);Bufferul de caractere

.code

180
start:
mov ax,@data
mov ds,ax
mov dx,buff0 ; Originea sirului in DX
mov ah,0A ;Citire tasta in AL
Int 21h
;Acum se formeaza sirul de afisat (terminat cu '$')
mov bh,0 ;Pregateste BX
mov bl,byte ptr ds:[1];Pentru a citi lungimea
;actuala
add bl,2 ;Se adauga 2 (octetii CR si LF)
mov ds:[bx],byte ptr '$';Sfarsitul de sir la
;lungime+2
mov buff0,0Ah ;La inceput Line Feed
mov buff1,0Dh ;si Carriage Return

mov ah,09 ;Functia 09


Int 21h

term:
mov ah,4Ch
int 21
end start

Programul 9.8

.radix 16
.model small
.stack 100h
.data
Sir1 db 'Care din urmatoarele registre indica
segmentul de date? (Apasati 1,2,3 sau 4)',0dH,0Ah,'1.
BX',0dH,0Ah,'2. BP',0dH,0Ah,'3. SI',0dH,0Ah,'4.
DI',0dH,0Ah,0dh,0ah,'$'

Sir2 db '. Corect!$'


Sir3 db '. Gresit! Era BX sau SI.$'
.code
start:
mov ax,@data
mov ds,ax ;Incarca in DS segmentul de date

mov dx, offset Sir1 ;Incarca in SI adresa sirului 1


mov ah, 09
Int 21h

mov ah,01
int 21h
cmp al,'1'

181
jz corect
cmp al,'3'
jz corect

mov dx, offset sir3


jmp afi
corect:
mov dx, offset sir2
afi: mov ah,09
int 21

term:
mov ah,4Ch
int 21
end start

Programul 10.1

.model small
.stack 100h
.code
start:
;Mod video 320x200
mov ah,0
mov al,13h
int 10h

afis: ;Afiseaza un punct la x=CX, y=DX si culoare=AL

mov cx,100
mov dx,50
mov al,2
mov ah,0Ch ;functia 0Ch
int 10h ;Cheama intreruperea 10h

term: jmp term


end start

Programul 10.2

.model small
.stack 100h
.code
start:
;Mod video 320x200

182
mov ah,0
mov al,13h
int 10h

;Afiseaza o linie la x=CX, y=DX si culoare=AL

mov dx,50
mov cx,100
lin1:
mov al,2
mov ah,0Ch ;functia 0Ch
int 10h ;Intreruperea 10h
inc cx ;Se pregateste scriereaaltui punct
cmp cx,200 ;pana se ajunge la 100 de puncte
jne lin1

term: jmp term


end start

Programul 10.3

.model small
.stack 100h
.code
;Declara parametrii
x1=50 ;Inceputul liniilor
y1=50
culoare=2
lungime=100 ;Lungimea liniilor
h=50 ;numarul de linii

start:
;Mod video 320x200
mov ah,0
mov al,13h
int 10h

afis: ;Afiseaza o linie la x=CX, y=DX si culoare=AL

mov dx,y1
mov al,culoare

lin2:
mov cx,x1
lin1:
mov ah,0Ch ;functia 0Ch
int 10h ;call bios service

183
inc cx
cmp cx,x1+lungime
jne lin1
inc dx
cmp dx,y1+h ;S-a ajuns la numarul final de linii?
jne lin2 ;Daca nu, se reia
term: jmp term
end start

Programul 10.4

.model small
.stack 100h
.code
x1=50
y1=50
culoare=2
lungime=100
h=50 ;numarul de linii
start:
;Mod video 320x200
mov ah,0
mov al,13h
int 10h

afis: ;Afiseaza un punct la x=CX, y=DX si culoare=AL

mov dx,y1

lin2:
mov al,culoare;Se reia linia cu culoarea de inceput
mov cx,x1

lin1:
inc al ;Noul punct cu alta culoare
mov ah,0Ch ;functia 0Ch
int 10h
inc cx
cmp cx,x1+lungime
jne lin1
inc dx
cmp dx,y1+h ;S-a ajuns la numarul final de linii?
jne lin2
term: jmp term
end start

184
Programul 10.5

.stack 100h
.code
x1=50
y1=50
culoare=2
lungime=100
h=50 ;numarul de linii
start:
;Mod video 320x200
mov ah,0
mov al,13h
int 10h

afis: ;Afiseaza un punct la x=CX, y=DX si culoare=AL

mov dx,y1
mov al,culoare ;Culoarea primei linii
lin2:
mov cx,x1
lin1:
mov ah,0Ch ;functia 0Ch
int 10h ;call bios service
inc cx
cmp cx,x1+lungime
jne lin1
inc al ;Urmatoarea linie are alta culoare
inc dx ;si alt y
cmp dx,y1+h ;S-a ajuns la ultima linie?
jne lin2 ;Daca nu, reia
term: jmp term
end start

Programul 10.6

.MODEL SMALL
.STACK 200H
.CODE

x1=160
culoarea =3

Start:

;Mod video 320x200


mov ah,0

185
mov al,13h
int 10h

MOV AX, 0A000H;Adresa memoriei ecran


MOV ES, AX ;in ES

mov di,x1 ;Pozitia punct este offset fata de ES


mov al,culoarea
stosb

oprire:
jmp oprire
END Start

Programul 10.7

.MODEL SMALL
.STACK 200H
.CODE

lung=200
culoarea =5

Start:

;Mod video 320x200


mov ah,0
mov al,13h
int 10h

MOV AX, 0A000H


MOV ES, AX

Linieo:
mov di,0
mov cx,lung
mov al,culoarea
rep stosb ;Repeta pana cand CX=0

oprire:
jmp oprire

END Start

Programul 10.8

186
.MODEL SMALL
.STACK 200H
.CODE

x1=100 ;Originea liliei


lung=200
culoarea =5

Start:

;Mod video 320x200


mov ah,0
mov al,13h
int 10h

MOV AX, 0A000H


MOV ES, AX
Linieo:

mov di,x1 ;Linia incepe in pozitia x1


mov cx,lung
mov al,culoarea
repz stosb ;Scrie punctele liniei

oprire:
jmp oprire

END Start

Programul 10.9

.MODEL SMALL
.STACK 200H
.CODE

x1=100
lung=200
culoarea =5

Start:

;Mod video 320x200


mov ah,0
mov al,13h

187
int 10h

MOV AX, 0A000H


MOV ES, AX
Linieo:

mov di,x1
add di,320
mov cx,lung
mov al,culoarea
repz stosb ;Scrie punctele liniei

oprire:
jmp oprire
END Start

Programul 10.10

.MODEL SMALL
.STACK 200H
.CODE
x1=100
y1=50
lung=200
culoarea =5

Start:

;Mod video 320x200


mov ah,0
mov al,13h
int 10h

MOV AX, 0A000H


MOV ES, AX
Liniev:

mov di,x1
mov bp,y1
mov cx,lung
mov al,culoarea
mov dx,bp ;Se face inmultirea
shl dx,6 ;lui BP (adica a lui Y1) cu 320
shl bp,8 ;Prin copiere in DX
add bp,dx ;deplasari la stinga si adunare
add di,bp ;Deplasamentul obtinut se aduna la DI
rep stosb ;Scrie punctele liniei

oprire:

188
jmp oprire
END Start

Programul 10.11

.MODEL SMALL
.STACK 200H
.CODE
x1=100
y1=50
lung=50
culoarea =5

Start:

;Mod video 320x200


mov ah,0
mov al,13h
int 10h

MOV AX, 0A000H


MOV ES, AX
Liniev:

mov di,x1
mov bp,y1
mov cx,lung
mov al,culoarea
mov dx,bp ;Se face inmultirea
shl dx,6 ;lui BP (adica a lui Y1) cu 320
shl bp,8 ;Prin copiere in DX
add bp,dx ;deplasari la stinga si adunare
add di,bp ;Deplasamentul obtinut se aduna la

lv1: add di,320 ;Noul punct este cu 320 mai


;departe în memoria de
ecran
mov es:[di],al ;Pune punctul
loop lv1 ;Repeta de CX ori

oprire:
jmp oprire

END Start

189
Programul 10.12

.MODEL SMALL
.STACK 200H
.CODE
x1=100
y1=50
lung=50
culoarea =5

Start:

;Mod video 320x200


mov ah,0
mov al,13h
int 10h

MOV AX, 0A000H


MOV ES, AX
Liniev:

mov di,x1
mov bp,y1
mov cx,lung
mov al,culoarea
mov dx,bp ;Se face inmultirea
shl dx,6 ;lui BP (adica a lui Y1) cu 320
shl bp,8 ;Prin copiere in DX
add bp,dx ;deplasari la stinga si adunare
add di,bp ;Deplasamentul obtinut se aduna la

lv1: add di,321;Noul punct este cu 320+1 mai


;departe în memoria de ecran
mov es:[di],al ;Pune punctul
loop lv1 ;Repeta de CX ori

oprire:
jmp oprire

END Start

Programul 10.13

190
.MODEL SMALL
.STACK 200H
.CODE

x1=100
y1=50
lung=50
culoarea =5

Start:

;Mod video 320x200


mov ah,0
mov al,13h
int 10h

MOV AX, 0A000H


MOV ES, AX
Liniev:

mov di,x1
mov bp,y1
mov cx,lung
mov al,culoarea
mov dx,bp ;Se face inmultirea
shl dx,6 ;lui BP (adica a lui Y1) cu 320
shl bp,8 ;Prin copiere in DX
add bp,dx ;deplasari la stinga si adunare
add di,bp ;Deplasamentul obtinut se aduna la

lv1: add di,319 ;Noul punct este cu 320-1 mai


;departe în memoria de
ecran
mov es:[di],al ;Pune punctul
loop lv1 ;Repeta de CX ori

oprire:
jmp oprire

END Start

Programul 10.14

.MODEL SMALL

191
.STACK 200H
.CODE

x1=100
y1=50
lung=50
culoarea =5
nrlinii=100

Start:

;Mod video 320x200


mov ah,0
mov al,13h
int 10h

MOV AX, 0A000H


MOV ES, AX
mov bx,nrlinii ;Contorul de linii verticale
mov di,x1 ;pozitia primei linii in DI

Liniev:
mov si,di ;DI va fi modificat eci se salveaza
mov bp,y1
mov cx,lung
mov al,culoarea
mov dx,bp ;Se face inmultirea
shl dx,6 ;lui BP (adica a lui Y1) cu 320
shl bp,8 ;Prin copiere in DX
add bp,dx ;deplasari la stinga si adunare
add di,bp ;Deplasamentul obtinut se aduna la

lv1: add di,320 ;Noul punct este cu 320 mai


;departe în memoria de ecran
mov es:[di],al ;Pune punctul
loop lv1 ;Repeta de CX ori
mov di,si ;Reface DI (pozitia liniei curente)
inc di ;si il incrementeaza (linia
;urmatoare)
dec bx ;Decrementeaza si contorul de linii
jnz liniev ;si daca nu a ajuns la 0, reia

oprire:
jmp oprire

END Start

192
Programul 11.2

.MODEL SMALL
.STACK 200H
.CODE
x1=100
y1=50
l=200
h=50
culoarea1 =05h
culoarea2 =01h

Start:
call sterge

;Mod video 320x240


mov ah,0
mov al,13h
int 10h

;Paleta
mov ah,0bh
mov bh,1
mov bl,8
int 10h

princ:

MOV AX, 0A000H


MOV ES, AX
mov al,culoarea1 ;in AL culoarea orizontala
call dreptunghi

oprire:
jmp oprire

;******* Subrutine *******

sterge: ;Sterge ecran


mov ah,06h
mov bh,0
int 10h
ret

lino: ;Afiseaza o linie orizontala , la y = DX din


puncte cu culoarea din DI
mov dx,bp
shl dx,8
shl bp,6
add dx,bp

193
add di,dx
repz stosb
ret

linv: ;Afiseaza o linie verticala


mov dx,bp
shl dx,8
shl bp,6
add dx,bp
add di,dx
lv1: MOV ES:[DI],al
add di,320
loop lv1
ret

dreptunghi:

mov bp,y1 ;in BP e Y1


mov di,x1 ;In DI e X1
mov cx,l ;In CX e lungimea
call lino

mov bp,y1+h ;in BP e Y1


mov di,x1 ;In DI e X1
mov cx,l ;In CX e lungimea
call lino

mov bp,y1 ;in BP e Y1


mov di,x1 ;In DI e X1
add di,320
mov cx,h ;In CX e lungimea
dec cx
mov al,culoarea2
call linv

mov bp,y1 ;in BP e Y1


mov di,x1+l-1;In DI e X2 (cu 1 mai putin decat x1+l)
add di,320
mov cx,h ;In CX e lungimea
dec cx
mov al,culoarea2
call linv
ret

END Start

Programul 11.3

.MODEL SMALL

194
.STACK 200H
.DATA
x1=100
y1=50
l=120
h=60
culoarea1 =05h
.CODE
Start:

;Mod video 320x240


mov ah,0
mov al,13h
int 10h

princ:

MOV AX, 0A000H


MOV ES, AX

mov di,x1 ;Parametrii primei linii


mov bp,y1
mov cx,l
mov al,culoarea1 ;in AL culoarea orizontala

mov bx,h

drept1:
call linieo
inc bp
dec bx
jnz drept1

oprire:
jmp oprire

;****** Subrutine **************

linieo: ;Linie orizintala


push cx
push di
push bp
mov dx,bp
shl dx,8
shl bp,6
add dx,bp
add di,dx
repz stosb
pop bp
pop di

195
pop cx
ret

END Start

Programul 11.4

.MODEL SMALL
.STACK 200H
.CODE
x1=10
y1=50
l=20
h=30
culoarea1 =05h
culoarea2 =01h

Start:

;Mod video 320x240


mov ah,0
mov al,13h
int 10h

princ:

MOV AX, 0A000H


MOV ES, AX

mov di,x1 ;Parametrii primei linii


mov bp,y1
mov cx,l
mov al,1 ;in AL culoarea orizontala
mov bx,h
mov si,20
et1: call dreptunghi
add di,5
add bp,5
inc al
dec si
jnz et1

oprire:
jmp oprire

;****** Subrutine **************


linieo: ;Linie orizontala
push cx
push di

196
push bp
mov dx,bp
shl dx,8
shl bp,6
add dx,bp
add di,dx
repz stosb
pop bp
pop di
pop cx
ret

dreptunghi:
push bx
push bp
drept1:
call linieo
inc bp
dec bx
jnz drept1
pop bp
pop bx
ret

END Start

Programul 11.5

.MODEL SMALL
.STACK 200H
.DATA
x1=100
y1=50
l=200
h=50
culoarea =1h

.CODE
Start:
;Mod video 320x240
mov ah,0
mov al,13h
int 10h

princ:
MOV AX, 0A000H
MOV ES, AX

mov bx,300h

197
p1: mov al,[bx] ;in AL culoarea
inc al
mov bp,[bx+1]
and bp,00ffh ;in BP e Y1
mov di,[bx+2]
and di,01ffh ;In DI e X1

mov cx,[bx+2]
and cx,003fh ;In CX e lungimea
inc cx ;Lungimea trebuie sa nu fie 0
mov si,20 ;In SI e inaltimea

call dreptunghi
inc bx
cmp bx,56000
jnz p1

oprire:
jmp oprire

;****** Subrutine **************

linv: ;Afiseaza o linie verticala


push di
push cx
push bp

mov dx,bp
shl dx,8
shl bp,6
add dx,bp
add di,dx
mov cx,si
lv1: MOV ES:[DI],al
add di,320
loop lv1

pop bp
pop cx
pop di
ret

dreptunghi:
;afiseaza un dreptunghi cu culoarea "culoare" la x1,y1,
de ;lungime l si inaltime h

push cx
push di

d1: call linv


inc di

198
dec cx
jnz d1
pop di
pop cx
ret

END Start

Programul 11.6

.MODEL SMALL
.STACK 200H
.CODE

h=30

Start:

;Mod video 320x240


mov ah,0
mov al,13h
int 10h

princ:

MOV AX, 0A000H


MOV ES, AX

mov bx,500h

p1: push bx
mov al,[bx] ;in AL culoarea
inc al
mov bp,[bx+1]
and bp,00ffh ;in BP e Y1
mov di,[bx+2]
and di,01ffh ;In DI e X1

mov cx,[bx+2]
and cx,003fh ;In CX e lungimea
inc cx ;Lungimea trebuie sa nu fie 0
inc cx
inc cx
mov si,h ;In SI e inaltimea

call dreptunghi
pop bx
inc bx

199
cmp bx,56000
jnz p1

oprire:
jmp oprire

MOV AH, 4CH ;Return to DOS


MOV AL, 00H
INT 21H

;****** Subrutine **************

lino: ;Afiseaza o linie orizontala , la y = BP din


;puncte cu culoarea din DI
push bp
push di
push cx
push ax

mov al,0
mov dx,bp
shl dx,8
shl bp,6
add dx,bp
add di,dx
repz stosb

pop ax
pop cx
pop di
pop bp
ret

linv: ;Afiseaza o linie verticala


push di
push cx
push bp

mov dx,bp
shl dx,8
shl bp,6
add dx,bp
add di,dx
mov cx,si
sub cx,1
add di,320
lvi: MOV ES:[DI],al
add di,320
loop lvi

200
pop bp
pop cx
pop di
ret

dreptunghi:
;afiseaza un dreptunghi cu culoarea "culoare" la
x1,y1, ;de lungime l si inaltime h

push cx
push di
call lino
push bp
add bp,si ;in BP e Y1
call lino
pop bp

push ax
mov al,0
call linv
pop ax
inc di
dec cx
dec cx

d1: call linv


inc di
dec cx
jnz d1

push ax
mov al,0
call linv
pop ax
pop di
pop cx
ret

END Start

Programul 12.2

.MODEL SMALL
.STACK 200H
.DATA
x1=100
y1=50
lung=100

201
inalt=50
culo=5
culv=1
.CODE

Linieo macro x1,y1,lung,culoarea


local lo1
mov di,x1 ;DI contine X1
mov bp,y1 ;BP contine Y1
mov cx,lung ;CX contine numarul de puncte
mov al,culoarea;In AL este culoarea
mov dx,bp ;Se face inmultirea
shl dx,6 ;lui BP (adica a lui Y1) cu 320
shl bp,8 ;Prin copiere in DX
add bp,dx ;deplasari la stinga si adunare
add di,bp ;Deplasamentul obtinut se aduna la
;adresa initiala
lo1: mov es:[di],al ;Pune punctul
inc di
loop lo1 ;Repeta de CX ori
endm

Liniev macro x1,y1,lung,culoarea


local lv1
mov di,x1 ;DI contine X1
mov bp,y1 ;BP contine Y1
mov cx,lung ;CX contine numarul de puncte
mov al,culoarea;In AL este culoarea
mov dx,bp ;Se face inmultirea
shl dx,6 ;lui BP (adica a lui Y1) cu 320
shl bp,8 ;Prin copiere in DX
add bp,dx ;deplasari la stinga si adunare
add di,bp ;Deplasamentul obtinut se aduna la
;adresa initiala
lv1: mov es:[di],al ;Pune punctul
add di,320 ;Noul punct este cu 320 mai
;departe in memoria de ecran
loop lv1 ;Repeta de CX ori
endm

Start:

;Mod video 320x200


mov ah,0
mov al,13h
int 10h

MOV AX, 0A000H; Adresa segmentului ecran in modul


13
MOV ES, AX ;in ES

202
linieo x1,y1,lung,culo
linieo x1,y1+inalt,lung,culo
liniev x1,y1+1,inalt-1,culv
liniev x1+lung-1,y1+1,inalt-1,culv

oprire:
jmp oprire

END Start

Programul 12.3

.MODEL SMALL
.STACK 200H
.DATA
x1=100
y1=20
lung=100
inalt=50
culo=5
culv=1
.CODE
;Linia orizontala
Linieo macro x1,y1,lung,culoarea
local lo1
mov di,x1 ;DI contine X1
mov bp,y1 ;BP contine Y1
mov cx,lung ;CX contine numarul de puncte
mov al,culoarea;In AL este culoarea
mov dx,bp ;Se face inmultirea
shl dx,6 ;lui BP (adica a lui Y1) cu 320
shl bp,8 ;Prin copiere in DX
add bp,dx ;deplasari la stinga si adunare
add di,bp ;Deplasamentul obtinut se aduna la
;adresa initiala
lo1: mov es:[di],al ;Pune punctul
inc di
loop lo1 ;Repeta de CX ori
endm

;Linia verticala
Liniev macro x1,y1,lung,culoarea
local lv1
mov di,x1 ;DI contine X1
mov bp,y1 ;BP contine Y1
mov cx,lung ;CX contine numarul de puncte
mov al,culoarea;In AL este culoarea

203
mov dx,bp ;Se face inmultirea
shl dx,6 ;lui BP (adica a lui Y1) cu 320
shl bp,8 ;Prin copiere in DX
add bp,dx ;deplasari la stinga si adunare
add di,bp ;Deplasamentul obtinut se aduna la
;adresa initiala
lv1: mov es:[di],al ;Pune punctul
add di,320 ;Noul punct este cu 320 mai
;departe in memoria de ecran
loop lv1 ;Repeta de CX ori
endm

;Linia spre dreapta


Lindr macro x1,y1,lung,culoarea
local lv1
mov di,x1 ;DI contine X1
mov bp,y1 ;BP contine Y1
mov cx,lung ;CX contine numarul de puncte
mov al,culoarea;In AL este culoarea
mov dx,bp ;Se face inmultirea
shl dx,6 ;lui BP (adica a lui Y1) cu 320
shl bp,8 ;Prin copiere in DX
add bp,dx ;deplasari la stinga si adunare
add di,bp ;Deplasamentul obtinut se aduna la
;adresa initiala
lv1: mov es:[di],al ;Pune punctul
add di,321 ;Noul punct este cu 320 mai
;departe in memoria de ecran
loop lv1 ;Repeta de CX ori
endm

;Linia spre stanga


Linst macro x1,y1,lung,culoarea
local lv1
mov di,x1 ;DI contine X1
mov bp,y1 ;BP contine Y1
mov cx,lung ;CX contine numarul de puncte
mov al,culoarea;In AL este culoarea
mov dx,bp ;Se face inmultirea
shl dx,6 ;lui BP (adica a lui Y1) cu 320
shl bp,8 ;Prin copiere in DX
add bp,dx ;deplasari la stinga si adunare
add di,bp ;Deplasamentul obtinut se aduna la
;adresa initiala
lv1: mov es:[di],al ;Pune punctul
add di,319 ;Noul punct este cu 320 mai
;departe in memoria de ecran
loop lv1 ;Repeta de CX ori
endm

Start:

204
;Mod video 320x200
mov ah,0
mov al,13h
int 10h

MOV AX, 0A000H; Adresa segmentului ecran in modul


;13
MOV ES, AX ;in ES

linieo x1,y1,lung,culo
lindr x1,y1,lung/2+1,culo
linst x1+lung,y1,lung/2,culo
linieo x1,y1+60+lung,lung,culo
liniev x1,y1+60,lung,culo
lindr x1,y1+60,lung+1,culo

oprire:
jmp oprire
END Start

Programul 12.4

.MODEL SMALL
.STACK 200H
.CODE
x1=100
y1=50
l=200
h=50
culoarea =1h

linv macro ;Afiseaza o linie verticala


local lv1
push di
push cx
push bp

mov dx,bp
shl dx,8
shl bp,6
add dx,bp
add di,dx
mov cx,si
lv1: MOV ES:[DI],al
add di,320
loop lv1

205
pop bp
pop cx
pop di
endm

dreptunghi macro

;afişează un dreptunghi cu culoarea "culoare" la


x1,y1, ;de lungime l si inaltime h

push cx
push di

dd1: linv ;dd1 nu trebuie declarat LOCAL


inc di
dec cx
jnz dd1
pop di
pop cx
endm
Start:

;Mod video 320x240


mov ah,0
mov al,13h
int 10h

princ:
MOV AX, 0A000H
MOV ES, AX

mov bx,300h
p1: mov al,[bx] ;in AL culoarea
inc al
mov bp,[bx+1]
and bp,00ffh ;in BP e Y1
mov di,[bx+2]
and di,01ffh ;In DI e X1

mov cx,[bx+2]
and cx,003fh ;In CX e lungimea
inc cx ;Lungimea trebuie sa nu fie 0
mov si,20 ;In SI e inaltimea

dreptunghi
inc bx
cmp bx,56000
jnz p1

oprire:
jmp oprire

206
END Start

BIBLIOGRAFIE

1. I. Spânulescu, S.I.Spânulescu - Circuite integrate digitale şi sisteme cu


microprocesoare, Editura Victor, Bucureşti, 1996;

2. I. Spânulescu, S.I.Spânulescu - Prelucrarea, înregistrarea, transmiterea şi afişarea


datelor, Universitatea din Bucureşti, 1984;

3. S.I.Spânulescu - Programarea in limbaj de asamblare a microcontrolerelor -Lucrări


de laborator, Editura Victor, 2003

4. D. Somnea, T.Vladuţ -Programarea în Assembler - Editura tehnică, Bucureşti,


1992;

5. Vlad Caprariu, Andrei Enyedi, Marius Muntean- Sistemul de operare DOS. Ghidul
programatorului, Ed. Microinformatica, Cluj-Napoca, 1993;

6. Vlad Caprariu, Sistemul de operare DOS. Funcţii sistem, Ed. Microinformatica,


Cluj-Napoca, 1995;

7. *** INTEL Microprocessors, Vol. 1, 2, Intel Corporation, Santa Clara, California,


1991;

8. Intel Architecture Sofware Developer's Manual Vol 1, 2A, 2B, 3, Intel


Corporation, Santa Clara, California, 2003.

207
CUPRINS

Introducere……………………………………………………………………………3

Lucrarea de laborator nr.1. Utilizarea macroasamblorului TASM şi a depanatorului


TD …………………………………………………………………………………….7
1.1 Utilizarea TASM şi TD în forma clasică (linie de comandă, DOS) ...........7
1.2 Utilizarea TASM şi TD în forma integrata (fereastra Windows) .............12

Lucrarea de laborator nr. 2. Instrucţiuni de transfer între registre ..............................15


2.1 Elemente ale limbajului de asamblare ......................................................15
2.2 Notaţia hexazecimală.................................................................................16
2.3 Registrele procesoarelor Intel x86 ...........................................................18
2.4. Instrucţiuni de transfer între registre ........................................................19
2.5. Instrucţiuni de interschimbare între registre ............................................20
2.6. Instrucţiuni de adunare şi scădere ............................................................21

Lucrarea de laborator nr. 3. Transferuri de date şi operaţii aritmetice cu memoria ...23


3.1 Componentele unei adrese logice .............................................................23
3.2 Componentele unei adrese efective ..........................................................25
3.3 Transferuri pe 1 octet şi pe 2 octeţi ..........................................................27
3.4 Moduri de adresare ...................................................................................28

Lucrarea de laborator nr. 4. Procedee de transfer cu memoria ..................................35


4.1 Transferuri prin adresare la memorie ......................................................35
4.2 Transferuri prin stivă ................................................................................35
4.3 Transferul prin iniţializarea/rezervarea de locaţii de catre asamblor........37
4.4 Instrucţiunea de translatare a unei adrese, XLAT ...................................39
4.5 Instrucţiuni de transfer pentru registrul de flaguri ....................................40
4.6 Încărcarea unei adrese logice din memorie ..............................................40
4.7 Încărcarea unei adrese efective..................................................................41

Lucrarea de laborator nr. 5. Operaţii aritmetice .........................................................43


5.1 Reprezentarea în complement faţă de 2 ....................................................43
5.2 Prezentarea instrucţiunilor aritmetice .......................................................45

208
Lucrarea de laborator nr. 6. Operaţii logice, deplasări şi rotaţii …………………….52
6.1. Operaţii logice .........................................................................................52
6.2. Deplasări şi rotaţii ....................................................................................53
6.3. Operaţii aritmetice BCD (opţional, vezi Anexa 1) .................................56
Lucrarea de laborator nr. 7. Instrucţiuni de salt ..........................................................58
7.1 Instrucţiuni de salt necondiţionat .............................................................58
7.2 Instrucţiuni de salt condiţionat .................................................................58
7.3 Instrucţiuni de ciclare LOOP, LOOPcc ....................................................60

Lucrarea de laborator nr. 8. Instrucţiuni de lucru cu şiruri .........................................62


8.1. Instrucţiunile LODSB, LODSW, STOSB, STOSW ................................62
8.2 Instrucţiunile MOVSB şi MOVSW ..........................................................64
8.3 Instrucţiunile pentru analiza conţinutului şirurilor, SCASB şi SCASW ..66
8.4. Instrucţiunile de comparare şiruri CMPSB şi CMPSW ..........................68
8.5 Prefixele REPE, REPZ, REPNE şi REPNZ .............................................70

Lucrarea de laborator nr. 9. Funcţii sistem (INT 21h) ..............................................71


9.1 Utilizarea întreruperilor software .............................................................71
9.2 Funcţii sistem de intrare şi ieşire ..............................................................72

Lucrarea de laborator nr. 10. Afişarea în mod grafic .................................................77


10.1 Utilizarea întreruperii 10h ......................................................................77
10.2 Scrierea directă în memoria de ecran .....................................................79

Lucrarea de laborator nr. 11. Utilizarea de subrutine (proceduri) ..............................84


11.1 Chemarea şi revenirea din subrutină .......................................................84
11.2 Salvarea şi refacerea registrelor afectate de subrutină ............................86

Lucrarea de laborator nr. 12. Utilizarea macroinstrucţiunilor ....................................90


12.1 Generalitati .............................................................................................90
12.2 Declararea şi utilizarea macroinstrucţiunilor ..........................................90
12.3 Utilizarea etichetelor locale cu directiva LOCAL ..................................94
12.4 Alte facilităţi de macroasamblare ..........................................................96

ANEXA 1. SETUL DE INSTRUCŢIUNI ALE MICROPROCESOARELOR INTEL


80x86 ÎN MODUL REAL SAU VIRTUAL 8086…………………………………..97
A 1.1 Notaţii, convenţii ……………………………………………………..97
A1.2. Instrucţiuni de transfer ………………………………………………..98
A1.3. Instrucţiuni de calcul…………………………………………………108
A1.4 Instrucţiuni de lucru pe bit …………………………………………...124
A1.5. Instrucţiuni de ramificare în program ……………………………….127
A1.6. Instrucţiuni speciale …………………………………………………133

ANEXA 2. Lista serviciilor de ecran INT 10h …………………………………....135

ANEXA 3. Lista funcţiilor sistemului de operare INT 21h ……………………….161

ANEXA 4. Rezolvările programelor………………………………………………181

Bibliografie …..…………………………………………………………………….253

209
210

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