Pentru a intelege modul in care datele si variabilele programului sunt utilizate (citite sau modificate), in aceasta parte a tutorialului assembler se analizeaza:
- Modul de adresare directa in limbaj de asamblare
- Adresare indexata
- Adresare bazata
- Adresare indexata si bazata
Pentru a intelege mai bine conceptele teoretice descrise, in acest tutorial sunt prezentate si exemple care pun in practica modurile de adresare pentru:
- Citirea unui caracter de la tastatura cu ecou intr-un program scris in limbaj de asamblare (assembler)
- Afisarea unui caracter pe ecran intr-un program scris in limbaj de asamblare (assembler)
- Citirea unui sir de la tastatura intr-un program scris in limbaj de asamblare (assembler)
- Afisarea unui sir pe ecran intr-un program scris in limbaj de asamblare (assembler)
Adresare directa in limbaj de asamblare
- Registrele sunt initializate cu valori constante
Exemplu:
mov AX, 1234h
- Numele variabilei este utilizat ca operand in instructiune.
Exemplu:
vector dw 10 dup(5) ; definire vector cu 10 elemente initializate cu valoarea 5 … mov AX, vector ;copiaza valoarea primului element de tip cuvant din vector in AX mov BX, vector[3] ;copiaza valoarea cuvantului care incepe de la offset-ul al treilea
ATENTIE, in exemplul anterior cum elementele vectorului încep de la offset cu valoare multiplu de 2, rezulta ca in BX se copiază valoarea 0500h.
Vectorul numit vector se găsește in segmentul de date memorat astfel:
DS:0000 05 00 05 00 05 00 05 00 05 00
DS:0008 05 00 00 00 00 00 00 00 00 00
iar instructiunea mov BX,vector[3] copiaza in BX 2 octeti (deoarece vector contine elemente de tip word) insa incepand de la offset-ul 0003 din DS. Deci BX va contine valoarea 0500h.
- Valoarea offset-ului este utilizata pentru a citi date direct din segmentul DS.
Exemplu:
vector dw 10 dup(5) ; definire vector cu 10 elemente initializate cu valoarea 5 … mov AX, DS:[00h] ;copiaza valoarea primului element de tip cuvant din vector in AX mov BX,DS:[08h] ;copiaza valoarea cuvantului care incepe de la offset-ul 08h
Cand se specifica offset-ul este absolut necesar sa se utilizeze expresia DS:[valoare_offset] pentru ca, daca se scrie instructiunea:
mov AX,[08h]
se copiaza in AX doar valoarea 8h (Veti primi si un WARNING – [Constant] assumed to mean immediate constant.)
Adresare indirecta in limbaj de asamblare
Se utilizeaza unul dintre registrele index SI, DI, BP sau registrul de baza BX. Atentie: utilizarea altor registre va genera eroare: Illegal indexing mode.
Se utilizeaza in general pentru parcurgerea masivelor si pentru a accesa elemente din structuri de date de tip articol.
Utilizarea registrului index SI sau DI pentru adresare indirecta indexata
- registrul SI este utilizat pentru a retine offset-ul elementului pe care dorim sa-l accesam;
vector dw 1234h,1235h,3222h,4343h,5455h … mov SI, offset vector ;incarca in SI offset-ul de inceput al vectorului mov AX, [SI] ;copiaza in AX valoarea primului element, adica 1234h mov CX, [SI+2] ;copiaza in CX valoarea elementului al doilea, adica 1235h mov DX,[SI+3] ;copiaza in DX valoarea 2212h (octetul inferior din 3222h si octetul superior din 1235h)
acelasi lucru se scrie si:
mov SI, offset vector mov AX, [SI] mov CX, [SI][2] mov DX,[SI][3]
- registrul SI sau DI este utilizat asemenea unui indice in parcurgerea masivului;
vector db 1,2,3,4,5,6 … XOR SI,SI ; ne asiguram ca SI are valoarea 0 mov AL, vector[SI] ;copiaza in AL valoarea primului element din vector inc SI mov AH, vector[SI] ;copiaza in AH valoarea elementului secund din vector mov CL,vector[SI+1] ;copiaza in CL valoarea celui de al treilea element mov AL,vector[SI][2] ;copiaza in AL valoarea celui de al patrulea element deoarece SI contine valoarea 1
in cazul in care vectorul are elemente de tip word parcurgerea acestuia se face marind SI cu valoarea 2 de fiecare data:
vector dw 1243,2342,3342,44324,53242,63432 … XOR SI,SI ; ne asiguram ca SI are valoarea 0 mov AX, vector[SI] ;copiaza in AX valoarea primului element din vector inc SI inc SI mov AX, vector[SI] ;copiaza in AX valoarea elementului secund din vector mov CX,vector[SI+2] ;copiaza in CX valoarea celui de al treilea element mov AX,vector[SI][4] ;copiaza in AX valoarea celui de al patrulea element deoarece SI contine valoarea 2
Utilizarea registrului baza BX pentru adresare indirecta bazata si indexata
- registrul BX este utilizat pentru adresare indirecta bazata;
vector db 1,2,3,4,5,6 … XOR SI,SI ; ne asiguram ca SI are valoarea 0 mov BX, offset vector ;incarcam in registrul de baza offset-ul de start al vectorului mov AL, [BX][SI] ;copiaza in AL valoarea primului element din vector inc SI add AL, [BX+SI] ;aduna in AL valoarea elementului secund din vector add AL, [BX+SI+1] ;aduna in AL valoarea celui de al treilea element add AL,[BX][SI][2] ;aduna in AL valoarea celui de al patrulea element deoarece SI contine valoarea 1
In exemplele anterioare, SI poate fi inlocuit de DI.
Registrul BX este utilizat si pentru a transmite offset-ul unui articol sau masiv ce reprezinta parametru de intrare intr-o procedura. Caracterul de generalitate al unei proceduri impune lucrul in interiorul ei cu offset-ul parametrilor de intrare si nu cu numele lor.
Cand se utilizeaza registrul BX ca registru de baza in adresarile indirecte pentru a memora offset-ul primului octet al structurii respective, adresa segmentului este data de registrul DS. Deci, fiecare element identificat prin [BX] se afla memorat la adresa DS:BX (segment:offset).
In cazul in care se utilizeaza registrul BP pentru adresari indirecte, adresa segmentului este data de registrul SS. Deci BP este utilizat pentru a accesa indirect locatii de memorie din stiva. Din acest motiv, instructiunea
mov CX,[BP]
copiaza in CX, valoarea din stiva aflata la offset-ul dat de BP, adica SS:BP.
Pentru a forta citirea din segmentul DS la offset-ul dat de BP, instructiunea devine
mov CX,DS:[BP]
Alte instructiuni din limbajul de asamblare pentru Intel 8086:
Instructiunea LOOP
- forma analitica a instructiunii este:
LOOP nume_eticheta
- decrementeaza registrul CX si sare la eticheta nume_eticheta cu conditia ca valoarea din CX sa fie mai mare decat zero;
- nu afecteaza nici un flag;
- instructiunea memoreaza intr-un octet offset-ul etichetei fata de pozitia sa in segmentul de cod; deci, eticheta trebuie sa se gaseasca la o distanta de maxim128 de octeti in interiorul segmentului de cod fata de pozitia instructiunii LOOP;
- utilizata de obicei pentru a implementa instructiuni de control repetitive;
Exemplu: determinarea sumei elementelor unui vector.
.model small .286 .stack 100h .data vector db 1,2,3,4,5,6,7 n db 7 ;dimensiunea vectorului suma db 0 ;suma elementelor .code mov AX,@data mov DS,AX xor SI,SI xor CX,CX ;ne asiguram ca CX are valoarea 0 mov CL,n ;copiem in CL dimensiunea vectorului repeat: ;definim eticheta mov AL,vector[SI] add suma,AL inc SI ;marim valoarea din SI cu 1 pentru a trece la ;elementul urmator loop repeat ;salt la eticheta cat timp CX diferit de 0 mov AX,4c00h int 21h end
Instructiunea LEA
- forma analitica a instructiunii este:
LEA registru, operand
- incarca in registrul specificat offset-ul operandului;
- registrul nu poate fi unul dintre registrele de segment;
- exemplu:
.data vb dw 1234h,1235h .code … mov SI,offset vb ;incarca registrul SI cu valoarea offest-ului variabilei vb lea DI,vb ;incarca registrul DI cu valoarea offest-ului variabilei vb …
Exemple – Citirea si afisarea pe ecran
Citirea unui caracter de la tastatura cu ecou intr-un program scris in limbaj de asamblare (assembler).
- se realizeaza utilizand rutina DOS 21h;
- registrul AH are valoarea 01h;
- codul ASCII al caracterului citit este pus in registrul AL;
- transformarea caracterului citit intr-un numar (cu conditia ca acesta sa reprezinte o cifra) cu valoarea cuprinsa intre 0 si 9 se face scazand din AL valoarea 30h, ce reprezinta codul ASCII al caracterului 0;
- exemplu:
.data nr db ? .code … mov ah,01h ;initializare AH cu codul functiei int 21h ;apel rutina sub al,30h ;transformare cod ASCII aferent cifrei in valoare intreaga mov nr,al ;copiere valoare numar …
Afisarea unui caracter pe ecran intr-un program scris in limbaj de asamblare (assembler).
- se realizeaza utilizand rutina DOS 21h;
- registrul AH are valoarea 02h;
- codul ASCII al caracterului citit este pus in registrul DL;
- afisarea unei valori numerice implica transformarea cifrelor in echivalentul lor ASCII (se adauga la valoarea cifrei valoarea 30h, ce reprezinta codul ASCII al caracterului 0);
- exemplu:
.data nr db 5 caracter db 'g' .code … mov DL,caracter mov ah,02h ;initializare AH cu codul functiei int 21h ;apel rutina si afisare caracter g pe ecran mov DL,nr mov ah,02h int 21h ;apel rutina si afisare pe ecran caracter cu codul ASCII egal cu 5 mov DL,nr add, DL,30h ;obtinere cod ASCII al cifrei din DL mov ah,02h int 21h ;apel rutina si afisare pe ecran a caracterului 5 …
Afisarea unei valori numerice mai mari decat 9 pe ecran implica prelucrari prin intermediul carora sa se obtina codul ASCII al tuturor cifrelor din numar.
Afisarea unui sir pe ecran intr-un program scris in limbaj de asamblare (assembler).
- se realizeaza utilizand rutina DOS 21h;
- registrul AH are valoarea 09h;
- adresa de inceput a sirului de caractere trebuie sa se gaseasca in DX; acest lucru se realizeaza prin intermediul instructiunii LEA sau a instructiunilor LES / LDS (descrise in Seminar 1)
- Important: ultimul caracter din sir trebuie sa fie $ (24h); functia afiseaza sirul pana intalneste primul caracter $
- exemplu:
... .data mesaj db "Afisare mesaj !!!","$" .code ... mov AH,09 lea DX,mesaj int 21h ...
Citirea unui sir de la tastatura intr-un program scris in limbaj de asamblare (assembler).
- se realizeaza utilizand rutina DOS 21h;
- registrul AH are valoarea 0Ah;
- adresa din segmentul de date (offset-ul) in care se face memorarea sirului citit trebuie scrisa in DX; sirul citit de la tastatura se scrie la adresa DS:DX
- primul octet de la adresa DS:DX trebuie sa contina numarul maxim n de caractere al sirului (rutina permite citirea de la tastatura doar a n-1 caractere); neinitializarea primului octet cu valoarea n poate conduce la situatiile: acesta are valoarea 0 si nu se citesc caractere sau acesta are o valoarea reziduala mai mare / mica decat lungimea maxima dorita;
- introducerea sirului la tastatura se incheie cu Enter (0Dh);
- rutina va scrie in al doilea octet de la adresa DS:DX numarul de caractere efectiv citit de la tastatura;
- ultimul octet din sir este codul ASCII al tastei Enter (0Dh)
- exemplu:
.data vb dw 1234h,1234h,1234h sir db 5 ;valoare necesara pentru a indica numarul maxim de caractere de citit .code mov AX,@data mov DS,AX mov dx,0006h ;incarc in DX offset-ul la care incepe scrierea sirului de caractere mov ah,0ah int 21h mov AX,4c00h int 21h end