Documente Academic
Documente Profesional
Documente Cultură
Sever Spânulescu
-Lucrări de laborator-
Editura Victor
2004
1
Introducere
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
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ă
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.
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
TD Nume_exefile
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
8
Figura 1.2 - Fereastra principală din TurboDebugger
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
5. În colţul din stânga jos este afişat conţinutul segmentului curent din stivă.
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).
11
produce încărcarea programului în Turbo Debugger, apărând fereastra acestuia, ca în
figura 1.2
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.
.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:
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
CX CH CL Contorizare
15
BP Adresare (baza segmentului de stivă)
SP Indicator de stivă
IP Numărator de program
Exemplul 2.1:
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.
Mnemonic general:
XCHG dst,src
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.
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
18
P 2.12 Acelaşi program ca la 2.11, numerele fiind 55667788 şi 99AABBCC.
Rezulatul trebuie să fie EF113354.
Segment n
. .
. .
. .
. .
. . Locaţia vizată
Segment 2
19
Adresa efectivă (AE)
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.
AF=AS:AE
Exemplul 3.2:
Modul de lucru:
Indicaţii:
Ambele locaţii sunt plasate în segmentul de date şi se pot vizualiza în zona
Dump din fereastra inferioară a Turbo Debugger.
MOV CH,[BP+10]
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.
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 :
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.
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
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ă
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):
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.
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.
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]
Exemplul 3.10:
MOV CX,[BX+SI+2C]
SUB DX,[BP+SI+2455]
MAT=20h
MOV BX, 18
MOV SI,3
MOV CL, MAT[BX+SI]
Modul de lucru
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
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.
Î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.
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.
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.
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
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
Modul de lucru
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
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.
Modul de lucru
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).
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).
număr+simetric =0
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
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
Exemplul 5.3:
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:
Exemplul 5.4:
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:
- 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
Exemplul 5.5:
Exemplul 5.6:
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
Modul de lucru
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.
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.
42
Lucrarea de laborator nr. 6
Operaţii logice, deplasări şi rotaţii
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.
Operanzi: -dst;
-[nr]: 1, CL,imm8.
Descriere: Operandul src este impartit cu 2 de [nr] ori.
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.
44
Operanzi: -dst.
-[nr]: 1, CL,imm8.
Descriere: Operandul src cu semn este împărţit cu 2 de [nr] ori.
Operanzi: -dst;
-[nr]: 1, CL,imm8.
Operanzi: -dst;
-[nr]: 1, CL,imm8.
Operanzi: -dst;
-[nr]: 1, CL,imm8.
Operanzi: -dst;
-[nr]: 1, CL,imm8.
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.
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.
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.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.
47
Lucrarea de laborator nr. 7
Instrucţiuni de salt
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).
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ă.
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.
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ă.
49
Acţiune: DEC CX; jump short if CX <> 0.
Se execută ciclul până când contorul CX ajunge la 0.
Modul de lucru:
50
Lucrarea de laborator nr. 8
Instrucţiuni de lucru cu şiruri
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:
Exemplul 8.2:
.
.
.
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
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 .
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.
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.
Modul de lucru
.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
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.
Funcţiile sistem sunt apelate prin execuţia întreruperii 21H, cu anumite valori
în registre.
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.
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
.
.
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.
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.
Exemplul 9.4:
;Afişează caracterul '1'
MOV AH, 02
MOV DL,31h ; Caracterul '1' are codul ASCII 31H
INT 21h
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.
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:
62
P 9.5 Se va modifica programul precedent pentru afişare fără ecou.
63
Următoarea secvenţă va trece ecranul în modul 13H:
Exemplul 10.1:
;Mod video 320x200
mov ah,0
mov al,13h
int 10h
Exemplul 10.2:
sterge: ;Sterge ecran
mov ah,06h
mov al,0
int 10h
Exemplul 10.3:
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
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
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:
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.
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.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.
68
Lucrarea de laborator nr. 11
Utilizarea de subrutine (proceduri)
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
69
culoarea1 =5
x2=100
y2=150
lung2=200
culoarea2 =3
.CODE
Start:
oprire:
jmp oprire
;*********** Subrutine********************
Linieo:
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.
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
Exemplul 11.3:
pop bp ;Reface
pop di ;registrele
pop cx ;care s-au modificat
ret
Exemplul 11.4:
12.1 Generalitati
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).
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
.CODE
Start:
oprire:
jmp oprire
END Start
Exemplul 12.2:
.MODEL SMALL
.STACK 200H
.DATA
x1=50
y1=50
lung=100
culoarea=0Eh
.CODE
Start:
76
MOV ES, AX ;în ES
oprire:
jmp oprire
END Start
Modul de lucru.
Exemplul 12.3:
77
.MODEL SMALL
.STACK 200H
.DATA
x1=50
y1=50
lung=100
culoarea=0Eh
.CODE
Start:
liniev x1,y1,lung,culoarea
liniev 20,120,30,1
oprire:
jmp oprire
END Start
78
Modul de lucru
REPT expresie
Corpul macro care se va repeta
ENDM
79
SETUL DE INSTRUCŢIUNI ALE MICROPROCESOARELOR
INTEL 80x86 ÎN MODUL REAL SAU VIRTUAL 8086.
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)
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.
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.
S Z x A x P x C
Acţiune: F ← AH
82
Bitii AH5 şi AH3 trebuie să fie 0.
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).
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).
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.
85
Acţiune: [DI]← AL
DI← DI +1 dacă DF=0, DI← DI-1 dacă DF=1
MOVS,MOVSB, MOVSW,MOVSD
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.
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: 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
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).
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.
89
Acţiune: dst ← dst + src;
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:
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:
- 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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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
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.
Operanzi: -src:r8,r16,r32,m8,m16,m32;
-[nr]: 1, CL,imm8.
Operanzi: -src:r8,r16,r32,m8,m16,m32;
-[nr]: 1, CL,imm8.
100
Operanzi: -src:r8,r16,r32,m8,m16,m32;
-[nr]: 1, CL,imm8.
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.
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)
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).
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.
103
dacă al doilea operand este o valoare imediată.
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)
adr: r16,r32,m16,m32,rel8,rel16,rel32,ptr16:16,ptr16:32,m16:16,m16:32.
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.
adr: rel8,rel16,rel32.
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.
LOOP, LOOPE,(LOOPZ),LOOPNE(LOOPNZ)
Acţiune: Există doua variante ale acestei instrucţiuni, a caror Acţiune este
urmatoarea:
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).
109
A1.6. Instrucţiuni speciale
110
ANEXA 2
111
INT 10h, 00h (0) Stabilire mod video
Intrări: AH 00h;
AL Modul video.
------------------------------------------------------------------
Tabelul modurilor video
Adresa de
Mod Tip Rezoluţia Adaptor Culori memorie
Vezi şi : INT 10h, 06h INT 10h, 07h INT 10h, 0Fh.
Intrări: AH 01h;
CH Linia de început a cursorului (0 - 31);
112
CL Linia de sfârşit a cursorului (0 - 31).
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.
Intrări: AH 02h;
BH Numarul paginii afişate;
DH Linie;
DL Coloană.
------------------------------------------------------------------
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.
Intrări: AH 03h;
BH Numărul paginii afişate.
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
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.
Intrare: AH 04h.
115
INT 10h, 05h (5) Setează pagina activă afişată
Setează pagina activă afişată.
Intrare: AH 05h;
AL Numărul paginii afişate.
------------------------------------------------------------------
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.
------------------------------------------------------------------
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ă.
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.
Intrare: AH 08h;
BH Afişează numărul paginii (numai în
modurile text).
Rezultate: AH Atributele caracterului (mod text);
AL Valoarea ASCII a caracterului.
118
Vezi şi: INT 10h, 09h
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.
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.
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).
------------------------------------------------------------------
Paleta 0 (BL = 0)
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.
------------------------------------------------------------------
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
------------------------------------------------------------------
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ă)
122
------------------------------------------------------------------
Valori valide
Intrare: AH 0Eh;
AL Caracterul de scris;
BL Culoarea (numai modurile grafice);
BH Numarul paginii afişate (numai
modurile text).
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.
Intrare: AH 0Fh;
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.
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
------------------------------------------------------------------
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
------------------------------------------------------------------
Numai VGA:
126
Subserviciul 9 (Citeşte regiştrii de culoare)
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;
127
BL Blocul de fonturi de încarcat (0-3);
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).
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.
129
BL Memorie EGA
00h 64K;
01h 128K;
02h 192K;
03h 256K;
CH Biţii adaptorului;
CL Setările comutarii.
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.
------------------------------------------------------------------
Observaţii:
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);
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.
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).
------------------------------------------------------------------
Tabelul adaptoarelor video compatibile PC
Cuvant Monocrom CGA LCD (CGA) LCD (Monocrom)
ANEXA 3
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.
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.
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.
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.
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
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.
137
FFh dată invalidă, data sistemului neschimbată.
Observaţie: DOS 3.3+ setează deasemenea ceasul din CMOS;
Vezi şi: AH=2Ah,AH=2Dh.
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.
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.
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.
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.
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.
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
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.
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.
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
147
Vezi şi: AX=5700h.
ANEXA 4
Rezolvările programelor
Programul 2.1
.model small
.stack 100h
.code
; terminate program
term: jmp term
end start
Programul 2.2
.model small
.stack 100h
.code
; 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
Programul 2.4
.model small
.stack 100h
.code
start: mov bx,1122h
mov cx,3344h
mov dx,bx
mov ax,cx
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
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
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
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
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
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
Programul 3.1
.model small
.stack 100
.code
start: mov al,22
MOV BX,0
MOV bx[20],al
MOV DS:[30],al
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
Programul 3.3
.model small
.stack 100h
.code
start: mov ax,3344h
MOV BX, 20h
MOV [bx],al
Programul 3.4
.model small
.stack 100
.code
start: MOV BX,0
MOV [bx+20h],1122h
MOV [BX+30h],byte ptr 44h
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
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
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
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
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
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
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
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
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
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.
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
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]
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
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
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
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
Programul 6.1
.radix 16
.model small
.stack 100h
.code
start:
mov ax,0EEEEh
and ax,0F
Programul 6.2
.radix 16
.model small
.stack 100h
.code
start:
mov ax,0EEEEh
or ax,1111111100001111b
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
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
ror dl,1
adc al,0
mov [bx+2],al
xor al,al
ror dl,1
adc al,0
mov [bx+3],al
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
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
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
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
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
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
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
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
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
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
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)
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
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
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
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
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
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
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,'$'
mov ah,01
int 21h
cmp al,'1'
181
jz corect
cmp al,'3'
jz corect
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
mov cx,100
mov dx,50
mov al,2
mov ah,0Ch ;functia 0Ch
int 10h ;Cheama intreruperea 10h
Programul 10.2
.model small
.stack 100h
.code
start:
;Mod video 320x200
182
mov ah,0
mov al,13h
int 10h
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
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
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
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
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:
185
mov al,13h
int 10h
oprire:
jmp oprire
END Start
Programul 10.7
.MODEL SMALL
.STACK 200H
.CODE
lung=200
culoarea =5
Start:
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
Start:
oprire:
jmp oprire
END Start
Programul 10.9
.MODEL SMALL
.STACK 200H
.CODE
x1=100
lung=200
culoarea =5
Start:
187
int 10h
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:
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:
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
oprire:
jmp oprire
END Start
189
Programul 10.12
.MODEL SMALL
.STACK 200H
.CODE
x1=100
y1=50
lung=50
culoarea =5
Start:
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
oprire:
jmp oprire
END Start
Programul 10.13
190
.MODEL SMALL
.STACK 200H
.CODE
x1=100
y1=50
lung=50
culoarea =5
Start:
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
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:
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
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
;Paleta
mov ah,0bh
mov bh,1
mov bl,8
int 10h
princ:
oprire:
jmp oprire
193
add di,dx
repz stosb
ret
dreptunghi:
END Start
Programul 11.3
.MODEL SMALL
194
.STACK 200H
.DATA
x1=100
y1=50
l=120
h=60
culoarea1 =05h
.CODE
Start:
princ:
mov bx,h
drept1:
call linieo
inc bp
dec bx
jnz drept1
oprire:
jmp oprire
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:
princ:
oprire:
jmp oprire
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
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
198
dec cx
jnz d1
pop di
pop cx
ret
END Start
Programul 11.6
.MODEL SMALL
.STACK 200H
.CODE
h=30
Start:
princ:
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 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
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
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
Start:
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
Start:
204
;Mod video 320x200
mov ah,0
mov al,13h
int 10h
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
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
push cx
push di
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
5. Vlad Caprariu, Andrei Enyedi, Marius Muntean- Sistemul de operare DOS. Ghidul
programatorului, Ed. Microinformatica, Cluj-Napoca, 1993;
207
CUPRINS
Introducere……………………………………………………………………………3
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
Bibliografie …..…………………………………………………………………….253
209
210