Tutorial Limbaj de Asamblare (Assembler) Intel 8086 – Partea 3 – Moduri de adresare

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
  • Modul de adresare indirecta 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