CATEGORII DOCUMENTE |
Instructiuni aritmetice si logice
A doua categorie importanta de instructiuni o constituie instructiunile aritmetice si logice. Rezultatul operatiei este totdeauna depus intr-unul din operanzi. La instructiunile cu doi operanzi, rezultatul este depus in primul operand. Instructiunile modifica flagurile CF, AF, ZF, SF, PF si OF, motiv pentru care acestea mai sunt numite si flaguri aritmetice.
1 Semnificatia flagurilor aritmetice
Flagul Carry = 1 semnifica un transport / imprumut din / in bitul cel mai semnificativ (b.c.m.s.) al rezultatului, unde b.c.m.s. poate fi bitul 7 sau bitul 15. Interpretarea acestui transport sau imprumut este cea de depasire la operatiile de adunare / scadere cu operanzi fara semn.
. Flagui Auxiliarry Carry = 1 semnifica un transport / imprumut din / in bitul 4 al rezultatului, fiind utilizat la operatiile cu numere BCD.
. Fiagul Zero este 1 daca rezultatul operatiei este nul.
. Flagul Sign este 1 daca bitul de semn al rezultatului (bitul 7 sau 15) este 1.
. Flagul Parity este 1 daca suma modulo 2 a celor 8 biti mai putin semnificativi ai rezultatului este 0.
. Flagul Overflow este 1 daca operatia a condus la un transport inspre b.c.m.s., dar nu din b.c.m.s. al rezultatului, sau invers. Altfel, OF se pozitioneaza la zero. Similar, in cazul imprumutului: OF = 1 daca a avut loc un imprumut dinspre b.c.m.s., dar nu din exterior, sau invers. Situatiile descrise sunt ilustrate in Figura
Interpretarea flagului OF este aceea de depasire la operatiile de adunare / scadere cu operanzi cu semn.
Sa consideram valoarea pe 1 octet 0FFH si sa adunam 1 la aceasta valoare. Rezultatul este 0 si transport atat din bitul 7, cat si din bitul 6 in bitul 7. Astfel, CF = 1 si OF = 0. Considerand operanzii fara semn (255 si 1), adunarea lor provoaca depasire, ceea ce corespunde cu CF = 1. Daca se considera operanzii cu semn, (-1 si 1), adunarea lor nu provoaca depasire si OF = 0.
Sa consideram, in mod similar, valorile 70H si 10H si suma acestora. Rezultatul este 80H si nu apare transport din bitul 7, dar este transport din bitul 6 in bitul 7. Ca atare, CF = 0 si OF = 1. In interpretarea fara semn, valorile operanzilor sunt 112 si 16, suma lor fiind 128, deci nu apare depasire (CF = 0). In interpretarea cu semn, valorile sunt tot 112 si 16, dar suma lor depaseste domeniul admisibil al octetilor cu semn si OF = 1.
Figura 2.2 Pozitionarea bistabilului Overflow
In fine, sa consideram operanzii 0FDH si 02H si suma lor. La adunare, se obtine valoarea 0FFH si nu apare transport nici din bitul 7, nici din bitul 6. Ca atare, CF = 0 si OF = 0. Valorile fara semn sunt 253 si 2, iar suma lor (255) este in domeniul admisibil, deci CF = 0. Valorile cu semn sunt -3 si 2, iar suma lor (-1) este in domeniul de reprezentare al numerelor cu semn, deci OF = 0.
La fiecare instructiune aritmetica sau logica, se vor preciza explicit flagurile afectate, adica flagurile care se pozitioneaza conform rezultatului. Un flag neafectat ramane la vechea valoare. Exista si situatii in care unele flaguri au valori nedefinite.
2 Instructiuni specifice adunarii (ADD, ADC, INC, DAA, AAA)
Instructiunea ADD (Add - Aduna)
Are forma generala:
in care destinatie poate fi un registru general sau o locatie de memorie, iar sursa poate fi un registru general, o locatie de memorie sau o valoare imediata. Cei doi operanzi nu pot fi simultan locatii de memorie. Semnificatia este:
(destinatie) <- (destinatie) + (sursa)
Flaguri afectate: AF, CF, PF, SF, ZF, OF (toate).
Operanzii pot fi pe 8 sau 16 biti si trebuie sa aiba aceeasi dimensiune. In caz de ambiguitate in ceea ce priveste lungimea operanzilor, se foloseste operatorul ptr. lata cateva exemple
ADD AX, BX
ADD AX, 1 ; Lungime 16 biti
ADD AL, 1 ; Lungime 8 biti
ADD word ptr [DI], -1 ; Dest. in memorie, sursa
; imediata
ADD byte ptr ALFA, 3 ; Fortare instructiune pe octet
Instructiunea ADC (Add with Carry - Aduna cu transport)
Forma generala este:
Formatul este similar cu instructiunea ADD, ceea ce difera fiind adunarea bistabilului CF:
(destinatie) <- (destinatie) + (sursa) + (CF)
Flaguri afectate: AF, CF, PF, SF, ZF, OF (toate).
Adunarea cu Carry se foloseste la adunari de operanzi pe mai multe cuvinte, in care poate aparea un transport intermediar. De exemplu, secventa de adunare a doua numere pe 4 octeti este:
.data
ALFA dd 145A789FH
REZ dd ?
.code
; adr. mici
ADD AX, word ptr BETA ; Aici poate aparea
; transport
MOV word ptr REZ, AX
MOV AX, word ptr ALFA+2 ; Cuvintele m.s. la
; adr. mari
ADC AX, word ptr BETA+2 ; Se ia in considerare
; transportul precedent
MOV word ptr REZ+2, AX
Instructiunea INC (Increment - Incrementeaza)
Are forma generala:
INC destinatie
in care destinatie este un registru sau un operand in memorie, de tip octet sau cuvant. Semnificatia este:
(destinatie) <- (destinatie) + 1
Flaguri afectate: AF, PF, SF, ZF, OF (fara CF).
Instructiunea DAA (Decimal Adjust for Addition - Corectie zecimala dupa adunare)
Instructiunea nu are operanzi si efectueaza corectia zecimala a acumulatorului AL, dupa o adunare cu operanzi in format BCD despachetat. Semnificatia este:
daca (AL0:3) > 9 sau (AF) = 1, atunci
daca acum (AL4:7) > 9 sau CF = 1, atunci
Flaguri afectate: CF, AF, CF, PF, SF, ZF. Flagul OF este nedefinit.
Daca cifra BCD mai putin semnificativa (AL0:3) este mai mare decat 9, deci este incorecta, sau daca a avut loc un transport din bitul 3 in bitul 4, se corecteaza aceasta cifra prin adunarea valorii 6. Daca cifra BCD mai semnificativa este acum mai mare decat 9, se corecteaza similar aceasta cifra. In ambele situatii, se pozitioneaza corespunzator AF si CF, pentru a indica depasirea care a avut loc.
Sa consideram, de exemplu, adunarea valorilor BCD 65 si 17. Aceste valori se reprezinta prin octetii 65H si 17H. In urma adunarii, se obtine rezultatul 7CH, care este incorect ca rezultat BCD. Operatia de corectie (DAA) conduce la rezultatul 82H, ceea ce reprezinta suma BCD a celor doua valori. Secventa de adunare trebuie sa fie:
.data
BCD1 db 65H
BCD2 db 17H
REZ db ?
.code
MOV AL, BCD1
ADD AL, BCD2
DAA
MOV REZ, AL
Instructiunea AAA (ASCll Adjust for Addition - Corectie ASCII a acumulatorului)
Instructiunea nu are operanzi si efectueaza corectia acumulatorului AX, dupa operatii de adunare cu operanzi BCD despachetati (o cifra BCD pe un octet). Semnificatia este urmatoarea:
daca (AL0:3) > 9 sau (AF) = 1, atunci
Flaguri afectate: AF, CF, restul nedefinite.
Corectia se face tot prin adaugarea valorii 6 la (AL), dar se face si o incrementare a registrului (AH), in ideea ca acolo s-ar putea tine cifra BCD despachetata mai semnificativa. Totodata se sterg bitii 4:7 ai registrului AL, pentru a avea o cifra BCD despachetata. Sa consideram ca registrele AX si BX contin valorile 0309H si 0104H, ceea ce ar corespunde valorilor BCD despachetate 39 si 14. In urma adunarii, se obtine rezultatul 040DH, care este incorect. Instructiunea AAA, corecteaza acest rezultat la 0503H, care este suma corecta a celor doua valori initiale:
MOV AX, 0309H
MOV BX, 0104H
3 Instructiuni specifice scaderii (SUB, SBB, DEC, NEG, CMP, DAS, AAS)
Instructiunea, SUB (Subtract - Scade)
Are forma generala:
SUB destinatie, sursa
unde destinatie si sursa sunt la fel ca la instructiunea ADD. Semnificatia este:
(destinatie) <- (destinatie) - (sursa)
Flaguri afectate: AF, CF, PF, SF, ZF, OF (toate).
Scaderea poate fi privita ca o adunare cu complementul fata de 2 al operandului sursa, dar cu inversarea rolului bistabilului CF, in sensul ca, daca la aceasta adunare echivalenta apare transport, atunci CF = 0 si reciproc. Sa consideram secventa de instructiuni:
MOV AL, 1
SUB AL, 05EH
Rezultatul este 0A3H si exista imprumut, deci CF = 1. Daca luam complementul fata de 2 al sursei, obtinem valoarea 0A2H, care, adunata la destinatie (adica la 1), conduce la valoarea 0A3H. La aceasta adunare echivalenta nu exista transport, deci, conform regulii de mai sus, operatia de scadere de la care am pornit va conduce la CF = 1.
Instructiunea SBB (Subtract with Borrow - Scade cu imprumut)
Are forma generala:
in care destinatie si sursa sunt la fel ca la instructiunea ADD. Semnificatia este:
(destinatie) <- (destinatie) - (sursa) - (CF)
deci se ia in considerare un eventual imprumut anterior.
Flaguri afectate: AF, CF, PF, SF, ZF, OF (toate).
Instructiunea SBB se utilizeaza la scaderi de operanzi pe mai multe cuvinte, ca in exemplul urmator:
.data
ALFA dd 145A789FH
BETA dd 92457ABCH
REZ dd ?
.code
MOV AX, word ptr ALFA ; Cuvintele m.p.s. la
; adr. mici
SUB AX, word ptr BETA ; Aici poate aparea
; imprumut
MOV word ptr REZ, AX
MOV AX, word ptr ALFA+2 ; Cuvintele m.s. la
; adr. mari
SBB AX, word ptr BETA+2 ; Se ia in considerare
; imprumutul precedent
MOV word ptr REZ+2, AX
Instructiunea DEC (Decrement - Decrementeaza)
Are forma generala:
DEC destinatie
in care destinatie este la fel ca la instructiunea INC. Semnificatia este:
(destinatie) <- (destinatie) - 1
Flaguri afectate: AF, PF, SF, ZF, OF (fara CF).
Instructiunea NEG (Negate - Schimba semnul)
Are forma generala:
in care destinatie este un registru sau o locatie de memorie, pe 8 sau pe 16 biti. Semnificatia este:
(destinatie) <- 0 - (destinatie)
deci se face o schimbare a semnului operandului.
Flaguri afectate: AF, CF, PF, SF, ZF, OF (toate).
De observat ca schimbarea semnului poate conduce uneori la aceeasi valoare, in cazul depasirii domeniului admisibil. De exemplu, secventa:
MOV AL, -128
NEG AL
va lasa registrul AL neschimbat (80H), deoarece 128 si -128 au aceeasi reprezentare interna.
Instructiunea CMP (Compare - Compara)
Are forma generala:
CMP destinatie, sursa
iar semnificatia este executia unei scaderi temporare (destinatie) - (sursa), fara a se modifica vreun operand, dar cu pozitionarea bistabililor de conditie.
Flaguri afectate: AF, CF, PF, SF, ZF, OF (toate).
Testand bistabilii de conditie, putem deduce relatia dintre cei doi operanzi. De exemplu, instructiunea CMP AX, BX va provoca o scadere temporara (AX) - (BX). Daca ZF = 1 inseamna ca (AX) = (BX). Daca CF = 1 inseamna ca la scadere a aparut un imprumut, deci (AX) < (BX), daca sunt considerate ca numere fara semn.
Instructiunea CMP se foloseste, de obicei, impreuna cu instructiuni de salt conditionat (vezi 2.4.3).
Instructiunea DAS (Decimal Adjust for Subtraction - Corectie zecimala dupa scadere)
Instructiunea nu are operanzi si executa corectia zecimala a acumulatorului AL, dupa operatii de scadere cu numere in format BCD impachetat. Semnificatia este:
daca (AL0:3) > 9 sau (AF) = 1, atunci
daca acum (AL4:7) > 9 sau CF = 1, atunci
Flaguri afectate: AF, CF, PF, SF, ZF. Flagul OF este nedefinit.
Explicatia operatiilor de mai sus este similara cu cea de la instructiunea DAA. De exemplu, in urma secventei:
.code
MOV AL, 52H
SUB AL, 24H ; AL = 2EH
DAS ; AL = 28H
se obtine in AL rezultatul corect 28H (28= 52 - 24).
Instructiunea AAS (ASCII Adjust for Subtraction - Corectie ASCII dupa scadere)
Instructiunea nu are operanzi si efectueaza corectia acumulatorului AX, dupa operatii de scadere cu operanzi BCD despachetati (o cifra BCD pe un octet). Semnificatia este urmatoarea:
daca (AL0:3) > 9 sau (AF) = 1, atunci
Flaguri afectate: AF, CF, restul nedefinite.
Se observa analogia cu instructiunea AAA, specifica adunarii in format BCD despachetat.
4 Instructiuni specifice inmultirii (CBW, CWD, MUL, IMUL, AAM)
Operatiile de inmultire se fac intre acumulator si un al doilea operand. Rezultatul operatiei este pe 16 sau, respectiv, 32 de biti. Se folosesc urmatoarele notiuni, definite diferit la operatii de 8 sau 16 biti:
. acumulator - registrul AL, respectiv, AX
. acumulator extins - registrul AX, respectiv perechea de registre DX:AX
. extensia acumulatorului - registrul AH, respectiv DX
. extensia de semn a acumulatorului - continutul registrului AL, respectiv AX, reprezentat, ca numar cu
semn, pe o lungime dubla (16, respectiv 32 de biti).
Instructiunea CBW (Convert Byte to Word - Converteste octet la cuvant)
Este fara operanzi si are urmatoarea semnificatie:
daca (AL7) = 0, atunci
(AH) <- 0
altfel
(AH) <- 1
Flaguri afectate: nici unul.
Practic, se extinde bitul de semn din AL la intreg registrul AH. Acest lucru este echivalent cu reprezentarea lui AL in complement fata de 2, pe un numar dublu de biti. De exemplu, daca AL = -3 (OFDH), atunci instructiunea CBW va forta in AX valoarea 0FFFDH, care este chiar reprezentarea in complement fata de 2 a valorii - 3.
Instructiunea CWD (Convert Word to DoubleWord - Converteste cuvant la dublu-cuvant)
Este fara operanzi si are urmatoarea semnificatie:
daca (AX15) = 0, atunci
(DX) <- 0
altfel
(DX) <- 1
Flaguri afectate: nici unul.
Se extinde bitul de semn din AX la intreg registrul DX, obtinandu-se astfel o reprezentare a lui AX pe 32 de biti.
Prin instructiunile CBW si CWD, se obtin extensiile de semn ale acumulatorului in acumulatorul extins.
Instructiunea MUL (Multiply - Inmulteste fara semn)
Are forma generala:
MUL sursa
in care sursa poate fi un registru sau o locatie de memorie de 8 sau 16 biti. Variantele noi de procesoare accepta si date imediate ca operand sursa. Rezultatul se obtine pe un numar dublu de biti (16 sau 32). Semnificatia este:
(acumulator extins) <- (acumulator) * (sursa)
in care ambii operanzi se considera numere fara semn. Mai precis, daca sursa este pe octet:
(AH:AL) <- (AL) * (sursa)
iar daca sursa este pe cuvant:
(DX:AX) <- (AX) * (sursa)
Flaguri afectate: daca extensia acumulatorului (adica AH sau DX) este diferita de 0, atunci CF si OF sunt 1, altfel CF si OF sunt 0. Restul flagurilor sunt nedefinite. Exemple:
.data
ALFA db 10H
BETA dw 200H
.code
MOV AL, 10H
MUL ALFA ; (AX) <- (AL) * ALFA
MOV AX, 20H
MUL BETA ; (DX:AX) <- (AX) * BETA
MOV AX, 100H
MOV BX, 20H
MUL BX ; (DX:AX) <- (AX) * (BX)
In situatia in care un operand este de tip byte, iar celalalt de tip word, se converteste operandul de tip byte la word, ca numar fara semn, deci cu partea mai semnificativa 0. De exemplu, pentru a inmulti valorile ALFA si BETA, se poate scrie:
MOV AL, ALFA
MOV AH, 0 ; (AX) = 0010H
MUL BETA ; (DX:AX) = 2000H
Se observa ca instructiunea MUL nu poate conduce la depasiri. Inmultind fara semn cele mai mari valori posibile pe 8 / 16 biti, se obtin valori corecte pe 16 / 32 de biti. De exemplu,
(216 - 1)*(216 - 1) = 232 - 217 + 1, care este o valoare reprezentabila pe 32 de biti.
Instructiunea IMUL (Integer Multiply - Inmulteste cu semn)
Are forma generala:
IMUL sursa
fiind similara cu instructiunea MUL. Deosebirea este ca operatia de inmultire se face considerand operanzii numere cu semn.
Flaguri afectate: daca extensia acumulatorului reprezinta extensia de semn a acumulatorului, atunci CF si OF se pozitioneaza la 0. Altfel, CF si OF devin 1. Restul flagurilor sunt nedefinite.
Nu pot aparea situatii de depasire. Inmultind cele mai mari valori in modul, se obtin valori corect reprezentabile. De exemplu, 127*127 = 16129, care se reprezinta corect ca numar cu semn pe 16 biti. Similar,
Daca sunt necesare conversii de la byte la word, se va folosi instructiunea CBW, ca in secventa urmatoare:
.data
ALFA db -113
BETA dw -147
REZ dd ?
.code
MOV AL, ALFA
CBW ; Conversie la word
MUL BETA ; Inmultire pe 16 biti
MOV word ptr REZ, AX ; Partea m.p.s. la
; adrese mici
MOV word ptr REZ+2, BX ; partea m.s. la
; adrese mari
Instructiunea AAM (ASCII Adjust for Multiply - Corectie ASCIl dupa inmultire)
Instructiunea nu are operanzi si efectueaza o corectie a acumulatorului AX, dupa o inmultire pe 8 biti cu numere in format BCD despachetat. Semnificatia este:
(AH) <- (AL) / 10
(AL) <- (AL) MOD 10
Flaguri afectate: PF, SF, ZF, restul nedefinite.
De exemplu, sa consideram secventa:
MOV AL, 5
MOV CL, 9
MUL CL
AAM
In urma inmultirii, registrul AX va contine valoarea 2DH (45). Corectia prin AAM conduce la AH = 4 si AL = 5, deci AX = 0405H, adica reprezentarea BCD despachetat pentru valoarea zecimala 45.
5 Instructiuni specifice impartirii (DIV, IDIV, AAD)
Impartirea presupune ca deimpartitul este pe o lungime dubla decat impartitorul. Prin impartire se obtin catul si restul, de lungime egala cu a impartitorului.
Instructiunea DIV(Divide - Imparte fara semn)
Are forma generala:
DIV sursa
in care sursa e un operand (registru sau locatie de memorie) pe octet sau pe cuvant. Procesoarele moderne accepta si date imediate ca operand sursa. Semnificatia este urmatoarea:
(acumulator) <- (acumulator extins) / (sursa)
(extensia acumulatorului) <- (acumulator extins) MOD (sursa)
Detaliind operatiile, se obtine, in cazul in care sursa este pe octet:
(AL) <- (AX) / (sursa)
(AH) <- (AX) MOD (sursa)
iar daca sursa este pe cuvant:
(AX) <- (DX:AX) / (sursa)
(DX) <- (DX:AX) MOD (sursa)
Flaguri afectate: toate flagurile sunt nedefinite.
Impartirea poate conduce la depasiri. In situatia in care catul rezulta mai mare decat valoarea maxima reprezentabila pe 8, respectiv 16 biti, sau daca impartitorul este 0, rezultatele sunt nedefinite si se genereaza o intrerupere soft pe nivelul 0 (Divide Overflow - Depasire la impartire). De exemplu, in secventa:
MOV AX 1000
MOV BL, 2
DIV BL
catul ar trebui sa fie 500, valoare care nu se poate reprezenta pe un octet. Ca atare, apare depasire si se va genera o intrerupere pe nivelul 0. Rutina afectata acestui nivel de intrerupere opreste de obicei programul executabil si afiseaza un mesaj de eroare la consola.
Sa consideram cateva exemple de operatii de impartire fara semn, care ilustreaza pregatirea operanzilor in situatiile care nu corespund celor doua tipuri de baza (impartire cuvant la octet si impartire dublu-cuvant la cuvant):
.data
B1 db ?
B2 db ?
W1 dw ?
W2 dw ?
Dl dd ?
.code
; impartire octet la octet
MOV AL, B1
MOV AH, 0
DIV B2 ; AL = cat, AH = rest
; impartire cuvant la octet
MOV AX, W1
DIV B1 ; AL = cat, AH = rest
; impartire dublu-cuvant la cuvant:
MOV AX, word ptr D1
MOV DX, word ptr D1 + 2
DIV W1 ; AX = cat, DX = rest
; impartire cuvant la cuvant
MOV AX, W1
MOV DX, 0
DIV W2 ; AX = cat, DX = rest
; impartire dublu-cuvant la byte
MOV AX, word ptr D1
MOV DX, word ptr D1 + 2
MOV BL, B1
MOV BH, 0
DIV BX ; AX = cat, DX = rest
Instructiunea IDIV (Integer Divide - Imparte cu semn)
Are forma generala:
in care sursa este la fel ca la instructiunea DIV. Semnificatia este aceeasi ca la instructiunea DIV, cu diferenta ca operanzii sunt considerati cu semn, iar impartirea se face cu semn.
Flaguri afectate: toate flagurile sunt nedefinite.
In situatia in care catul rezulta in afara domeniului reprezentabil pe 8, respectiv 16 biti, sau daca impartitorul este 0, rezultatele sunt nedefinite si se genereaza o intrerupere soft pe nivelul 0. Concret, catul trebuie sa fie in domeniul [-128, +127] la impartire pe octet, respectiv in domeniul [-32768, +32767] la impartire pe cuvant. De exemplu, in secventa:
MOV AX, 400
MOV BL, 2
IDIV BL
catul ar trebuie sa rezulte 200, valoare care nu se poate reprezenta ca numar cu semn pe un octet. Ca atare, va aparea o intrerupere pe nivelul 0.
In ceea ce priveste calculul restului la impartirea cu semn, acesta este totdeauna calculat astfel incat sa fie indeplinita identitatea urmatoare:
a = b*(a / b) + a MOD b
in care a / b si a MOD b sunt catul si restul calculate de instructiunea IDIV. De exemplu, in secventa:
MOV AX, -10
MOV BL, -3
IDIV BL ; AL = 3, AH = 0FFH
catul rezulta +3, iar identitatea de mai sus conduce la restul - 1. Asadar (-10) MOD (-3) = -1 si in registrul AH se va gasi 0FFH (-1 reprezentat pe un octet).
Tipurile posibile de impartiri sunt aceleasi ca la instructiunea DIV, cu observatia ca operanzii trebuie pregatiti folosind instructiunile CBW si CWD. Consideram aceleasi definitii de date ca la instructiunea DIV:
. code
; impartire octet la octet
MOV AL, B1
CBW
IDIV B2 ; AL = cat, AH = rest
; impartire cuvant la octet
MOV AX, W1
IDIV B1 ; AL = cat, AH = rest
; impartire dublu-cuvant la cuvant
MOV AX, word ptr D1
MOV DX, word ptr D1 + 2
IDIV W1 ; AX = cat, DX = rest
; impartire cuvant la cuvant
MOV AX, W1
CWD
IDIV W2 ; AX = cat, DX = rest
; impartire dublu-cuvant la byte
MOV AL, B1
CBW
MOV BX, AX ; BX = deimpartit
MOV AX, word ptr D1
MOV DX, word ptr D1 + 2 ; DX:AX = impartitor
IDIV BX ; AX = cat, DX = rest
O aplicatie tipica a instructiunilor de impartire este conversia unui cuvant de 16 biti, cu sau fara semn, la un sir de caractere (cifre) in baza 10. Daca presupunem ca n este variabila care contine numarul, iar sir este variabila unde se depun cifrele generate, algoritmul poate fi descris (intr-o notatie specifica limbajului C), in felul urmator:
adrsir = sir;
do while (n != 0);
*sir = 0;
inverseaza (sir);
Interpretam numarul n fara semn. In bucla de program cu test la partea inferioara, se calculeaza restul si catul impartirii lui n la 10. Catul furnizeaza cifra curenta, careia i se aduna codul ASCII al cifrei 0. Se avanseaza adresa sir la urmatorul caracter, bucla terminandu-se cand n devine 0.
Se observa ca acest algoritm furnizeaza cifrele numarului in ordine inversa; ca atare, rutina inverseaza(sir), trebuie sa inverseze ordinea caracterelor din sirul generat. De exemplu, daca n = 1234, atunci prima iteratie produce rest = 4 si n = 123, a doua iteratie produce rest = 3 si n = 12 etc.
Sa implementam acest algoritm printr-o secventa in limbaj de asamblare.
.data
n dw ?
sir db 20 dup (?)
.code
lea si, sir
mov ax, n
mov dx, 0
mov bl, 10
mov bh, 0
_do:
div bx ; AX = cat; DX (DL) = rest
add dl, '0'
mov [si] , dl
inc si
mov dx, 0
cmp ax, 0
jne _do ; Salt daca AX diferit de 0
mov byte ptr [si], 0
; Inverseaza
mov di, si
dec di ; DI indica ultimul caracter util
lea si, sir ; SI indica primul caracter
_test:
cmp si, di
jae _gata ; Salt daca SI >= DI
mov al, [si] ; Interschimba octetii de la
xchg al, [di] ; adresele din SI si DI
mov [si], al
inc si
dec di
jmp _test
_gata:
Declaratia sir db 20 dup (?) rezerva o zona de 20 de octeti in segmentul de date. Simbolurile _do:, _test:, _gata: sunt etichete folosite la instructiuni de salt.
Desi avem de facut o impartire la 10 (deci la o cantitate care se poate reprezenta pe un octet), iar deimpartitul este un cuvant, vom folosi totusi impartirea dublu-cuvant la cuvant, pentru a evita depasirile. Se pregateste deci deimpartitul in DX:AX si catul in BX. Pentru accesul la sirul de caractere, folosim registrul SI. Asadar, variabilele n si sir din algoritm vor fi tinute in registrele AX si SI.
Prin impartire, se obtine catul in AX si restul in DX. De fapt, fiind o impartire la 10, restul nu poate depasi valoarea 9, deci il vom gasi, de fapt, in DL. Adaugam '0' si depunem caracterul la adresa data de SI, incrementam SI si pregatim deimpartitul pentru pasul urmator (adica fortam DX = 0). Se testeaza acum AX (adica variabila n), prin comparatie cu 0. Instructiunea JNZ inseamna "Jump on Not Equal', deci salt daca operanzii din ultima comparatie sunt diferiti. Acest salt conditionat reia bucla de program.
Pentru a inversa caracterele generate, se pozitioneaza registrele SI si Dl pe primul si, respectiv, pe ultimul caracter util din sir, dupa care se executa o bucla de inversare, care continua cat timp SI < Dl. Instructiunea JAE inseamna "Jump if Above or Equal', deci salt daca la ultima comparatie primul operand a fost mai mare sau egal cu al doilea. In bucla respectiva, se interschimba caracterele de la adresele Dl si SI, prin doua MOV-uri si un XCHG.
Instructiunea AAD (ASCII Adjust for Division - Corectie ASCII inainte de impartire)
Instructiunea nu are operanzi si efectueaza o corectie a acumulatorului AX, interpretat ca doua cifre BCD despachetate. Semnificatia este urmatoarea:
(AL) <- (AH) * 10 + (AL)
(AH) <- 0
Flaguri afectate: PF, SF si ZF, restul nedefinite.
Operatia de corectie trebuie facuta inainte de impartirea unui numar pe doua cifre BCD, reprezentat pe un cuvant, la o cifra BCD reprezentata pe un octet.
De exemplu, daca AX = 0305H, adica valoarea BCD 35 si BL = 2, secventa de impartire va fi:
AAD ; AX = 23H
DIV BL ; AL = 11H, AH = 1
Instructiunea AAD incarca AX cu valoarea 22H (35) si impartirea se face corect, obtinandu-se catul 11H (17) si restul 1.
6 Instructiuni logice (NOT, AND, TEST, OR, XOR)
Instructiunile logice realizeaza functiile logice de baza, pe octet sau pe cuvant. Operatiile se fac la nivel de bit, deci se aplica functia logica respectiva tuturor bitilor sau perechilor de biti corespunzatori din operanzi. Instructiunea NOT are un singur operand, celelalte avand fiecare doi operanzi.
Instructiunea NOT (Not - Negare logica bit cu bit)
Forma generala este:
NOT destinatie
in care destinatie poate fi un registru sau o locatie de memorie de 8 sau 16 biti. Instructiunea provoaca negarea tuturor bitilor operandului, deci calculul complementului fata de 1.
Flaguri afectate: nici unul.
Instructiunea AND (And - Si logic bit cu bit)
Are forma generala:
AND destinatie, sursa
in care destinatie poate fi un registru sau o locatie de memorie de 8 sau 16 biti, iar sursa poate fi un registru, o locatie de memorie sau o constanta, pe 8 sau 16 biti. Semnificatia este:
(destinatie) <- (destinatie) AND (sursa)
Flaguri afectate: SF, ZF, PF, CF = 0, OF = 0, AF nedefinit.
Instructiunea TEST(Test - Testeaza)
Are forma generala:
TEST destinatie sursa
in care destinatie si sursa sunt la fel ca la instructiunea AND. Efectul este executia unei operatii AND intre cei doi operanzi, fara a se modifica destinatia, dar cu pozitionarea flagurilor la fel ca la instructiunea AND.
Flaguri afectate: SF, ZF, PF, CF = 0, OF = 0, AF nedefinit.
Aceasta instructiune si raportul ei cu instructiunea AND sunt similare cu instructiunea CMP si raportul cu instructiunea SUB.
Instructiunea OR (Or - Sau logic bit cu bit)
Are forma generala:
in care destinatie si sursa sunt la fel ca la instructiunea AND. Semnificatia este:
(destinatie) <- (destinatie) OR (sursa)
Flaguri afectate: SF, ZF, PF, CF = 0, OF = 0, AF nedefinit.
Instructiunea XOR (Exclusive Or - Sau-exclusiv bit cu bit)
Are forma generala:
in care destinatie si sursa sunt la fel ca la instructiunea AND. Semnificatia este:
(destinatie) <- (destinatie) XOR (sursa)
Flaguri afectate: SF, ZF, PF, CF = 0, OF = 0, AF nedefinit.
Functia sau-exclusiv este 1 cand operanzii sai sunt unul 0, iar celalalt 1 si este 0 cand operanzii sunt ambii 0 sau ambii 1. Din acest motiv, functia sau-exclusiv se mai numeste si anticoincidenta.
Instructiunile logice sunt folosite frecvent pentru anumite operatii tipice, cum ar fi:
. stergerea rapida a unui registru, cu pozitionarea flagurilor
XOR CL, CL
. fortarea unor biti la valoarea 1, restul ramanand neschimbati
MASCA EQU 01101101B
OR AL, MASCA
Pseudo - instructiunea EQU defineste constante simbolice, iar prefixul B inseamna numar scris in baza 2. In secventa de mai sus, bitii cu valoarea 1 din MASCA vor fi fortati la 1 in registrul AL, iar bitii cu valoarea 0 din MASCA vor ramane neschimbati.
. fortarea unor biti la valoarea 0 cu ceilalti neschimbati
AND AL, MASCA
Bitii cu valoarea 0 din MASCA vor deveni 0 in AL, iar cei cu valoarea 1 in MASCA vor ramane neschimbati.
testarea unui singur bit dintr-un operand
TEST AL, 01000000B
JZ eticheta ; sau JNZ
. pozitionarea flagurilor fara a modifica operandul
OR AX, AX ; Pozitioneaza FLAGS
; conform AX
AND AX, AX ; Similar
TEST AX, AX ; Similar
. complementarea unui grup de biti, cu ceilalti neschimbati
Presupunem constanta MASCA, definita ca mai sus, si operandul aflat in AL. Dorim ca bitii cu valoarea 1 din MASCA sa fie complementati in AL, iar ceilalti sa ramana neschimbati.
MASCA EQU 01110110B
MOV BL, AL ; Salvare
AND AL, MASCA ; Selectie biti care
; se modifica
NOT AL ; Complementare
XCHG AL, BL ; Refacere
AND AL, NOT MASCA ; Selectie biti care
; nu se modifica
OR AL, BL ; Rezultat final
Expresia NOT MASCA este evaluata la asamblare, producandu-se o constanta cu toti bitii negati.
7 Instructiuni de deplasare (SHL, SAL, SHR, SAR) si de rotatie (ROL, RCL, ROR, RCR)
Acest grup de instructiuni realizeaza operatii de deplasare si de rotatie la nivel de bit. Instructiunile au doi operanzi: primul este operandul propriu-zis, iar al doilea este numarul de biti cu care se deplaseaza sau se roteste primul operand. Ambele operatii se pot face la dreapta sau la stanga. Deplasare inseamna translatarea tuturor bitilor din operand la stanga / dreapta, cu completarea unei valori fixe in dreapta / stanga si cu pierderea bitilor din stanga / dreapta. Depistarea cu un bit la stanga este echivalenta cu inmultirea operandului cu 2, iar deplasarea la dreapta, cu impartirea operandului la 2.
Rotatie inseamna translatarea tuturor bitilor din operand la stanga / dreapta, cu completarea in dreapta / stanga cu bitii care se pierd in partea opusa.
Ambele operatii se fac cu modificarea bistabilului CF, care poate chiar participa la operatiile de rotatie.
Forma generala a instructiunilor este:
OPERATIE OPERAND, CONTOR
in care OPERAND este un registru sau o locatie de memorie de 8 sau 16 biti, iar CONTOR (numarul de biti) este fie constanta 1, fie registrul CL, care contine numarul de biti cu care se deplaseaza / roteste operandul. Procesoarele de generatie noua (80286 si peste) accepta un numar oarecare de biti, specificat si printr-o constanta intreaga.
Flagurile sunt afectate in felul urmator. La operatiile de deplasare, se modifica toate flagurile conform rezultatului, in afara de AF, care este nedefinit. La operatiile de rotatie, se modifica numai CF si OF.
Modificarea flagului OF se face printr-un algoritm destul de complicat. Pentru a nu repeta acest algoritm, consideram urmatoarele secvente definite in pseudo - cod:
pozit_OF_left
pozit_OF_right
Se vede deci ca flagul OF este pozitionat numai daca se face o operatie de deplasare / rotatie de 1 bit.
Descrierea instructiunilor se va face intr-un format de tip pseudo - cod, cu evidentierea operatiilor aritmetice echivalente.
La instructiunile de deplasare, se considera deplasari logice si aritmetice, care se pot utiliza dupa natura operanzilor.
Instructiunea SHL/SAL (Shift Logic / Arithmetic Left - Deplaseaza logic / aritmetic la stanga)
Are forma generala:
SHL / SAL OPERAND, CONTOR
Desi exista doua mnemonice (SHL si SAL), in fapt este vorba de o unica instructiune. Semnificatia este urmatoarea:
temp <- CONTOR
cat timp temp ! = 0
pozit_OF_left
Aceasta descriere nu spune altceva decat ca bitul cel mai semnificativ al operandului trece in CF, dupa care toti bitii se deplaseaza la stanga cu o pozitie (vezi Figura 2.3). Operatia se repeta de atatea ori cat este valoarea lui CONTOR (1 sau continutul registrului CL).
Instructiunea SHR (Shift Logic Right - Deplaseaza logic la dreapta)
Are forma generala:
SHR OPERAND, CONTOR
Semnificatia este urmatoarea:
temp <- CONTOR
cat timp temp != 0
pozit_OF_right
Descrierea de mai sus spune ca bitul cel mai putin semnificativ din OPEFAND trece in CF, dupa care se deplaseaza toti bitii cu o pozitie la dreapta (impartire la 2). Faptul ca operatia de impartire se executa fara semn inseamna ca se completeaza cu un bit 0 dinspre stanga (vezi Figura 2.3). Operatia se repeta de atatea ori cat este valoarea lui CONTOR (1 sau continutul registrului CL).
Instructiunea SAR (Shift Arithmetic Right - Deplaseaza aritmetic la dreapta)
Are forma generala:
Semnificatia este urmatoarea:
temp <- CONTOR
cat timp temp != 0
pozit_OF_right
Singura diferenta fata de deplasarea logica la dreapta este realizarea impartirii la 2, luand in considerare semnul operandului. Aceasta inseamna ca se conserva bitul de semn, mai precis, completarea dinspre stanga se face cu bitul de semn (vezi Figura 2.3).
Aceste doua tipuri de deplasare la dreapta se reflecta si in implementarile limbajelor de nivel inalt. De exemplu, standardul ANSI al limbajului C lasa neprecizat faptul ca deplasarea la dreapta a unui intreg de tip signed se face cu completare dinspre stanga cu 0 sau cu bitul de semn (deci operatie de tip SHR sau SAR); aceasta alegere revine implementarii. Totusi, la deplasarea cantitatilor de tip unsigned, se completeaza intotdeauna dinspre stanga cu 0 (deci se face deplasare logica). Acest fapt este important mai ales in cazul tipului char, care nu este specificat in standardul ANSI ca fiind cu semn sau fara semn.
Instructiunea ROL (Rotate Left - Roteste la stanga)
Are forma generala:
ROL OPERAND, CONTOR
Semnificatia este urmatoarea:
temp <- CONTOR
cat timp temp != 0
pozit_OF_left
Descrierea de mai sus spune ca bitul cel mai semnificativ din OPERAND trece atat in CF, cat si in bitul cel mai putin semnificativ din OPERAND, dupa ce toti bitii acestuia s-au deplasat la stanga cu o pozitie (vezi Figura 2.3). Operatia se repeta de atatea ori cat este valoarea lui CONTOR (1 sau continutul registrului CL).
Instructiunea RCL (Rotate Left through Carry - Roteste la stanga prin carry)
Are forma generala:
RCL OPERAND, CONTOR
Semnificatia este urmatoarea:
temp <- CONTOR
cat timp temp 1 = 0
pozit_OF_left
Descrierea de mai sus spune ca bitul cel mai semnificativ din OPERAND trece in CF, se deplaseaza toti bitii din OPERAND cu ( pozitie la stanga, iar CF original trece in bitul cel mai putin semnificativ din OPERAND. Cu alte cuvinte, CF participa efectiv la rotatie (vezi Figura 2.3). Operatia se repeta de atatea ori cat este valoarea lui CONTOR (1 sau continutul registrului CL).
Instructiunea ROR (Rotate Right - Roteste la dreapta)
Are forma generala:
ROR OPERAND, CONTOR
Semnificatia este:
temp <- CONTOR
cat timp temp != 0
pozit_OF_right
Descrierea de mai sus spune ca bitul cel mai semnificativ din OPERAND trece atat in CF, cat si in bitul cel mai putin semnificativ, dupa ce toti bitii s-au deplasat la dreapta cu o pozitie (vezi Figura 2.3). Operatia se repeta de atatea ori cat este valoarea lui CONTOR (1 sau continutul registrului CL).
Instructiunea RCR (Rotate Right through Carry - Roteste la dreapta prin carry)
Are forma generala:
RCR OPERAND, CONTOR
Semnificatia este urmatoarea:
temp <- CONTOR
cat timp temp != 0
pozit_OF_right
Descrierea de mai sus spune ca bitul cel mai putin semnificativ din OPERAND trece in CF, se deplaseaza toti bitii din OPERAND cu o pozitie la dreapta, iar CF original trece in bitul cel mai semnificativ din OPERAND. Cu alte cuvinte, CF participa efectiv la rotatie (vezi Figura 2.3). Operatia se repeta de atatea ori cat este valoarea lui CONTOR (1 sau continutul registrului CL).
Semnificatiile celor 7 instructiuni de deplasare si rotatie sunt ilustrate in Figura 2.3.
Sa consideram cateva exemple de rotatii si deplasari.
Inmultirea / impartirea cu puteri ale lui 2. Operatiile de asemenea tip se executa mult mai eficient prin deplasari la stanga / dreapta. Secventa:
MOV CL, 4
MOV AH, 0
SHL AX, CL
realizeaza inmultirea lui AL cu valoarea 16. Rezultatul se regaseste in AX. Secventa:
MOV CL, 3
SAL BX, CL
realizeaza impartirea lui BX (considerat numar cu semn) la valoarea 8.
Similar, se realizeaza si inmultiri cu valori care se pot exprima prin sume cu un numar redus de termeni de puteri ale lui 2. Secventa urmatoare realizeaza inmultirea unei valori N presupuse initial in AL cu valoarea 13, prin deplasari si adunari repetate. Rezultatul se regaseste in BX.
MOV AH, 0
MOV BX, AX ; Salvare N
MOV DX, AX ; Salvare N
MOV CL, 3
SHL AX, 3 ; AX <--- N * 8
ADD BX, AX ; BX <--- N * 8 + N
MOV AX, DC ; Refacere N
MOV CL, 2
SHL AX, CL ; AX <--- N * 4
ADD BX, AX ; BX <--- N * 8 + N * 4 + N
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 2568
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved