Variabilă vom numi un obiect ce conţine date care pot varia.
Pentru limbajul ASM o variabilă vom numi o zonă de memorie alocată acestei variabile accesibile după un nume. Numele de variabilă este o eticheta în segmentul de date care reprezintă de fapt adresa către zona de memorie alocată variabilei. Spre deosebire de limbajele de nivel înalt, în ASM nu există tip al variabilei. O variabilă este caracterizată doar de numele acesteia, eticheta, şi volumul de memorie alocat acestei variabile.
Declararea Variabilei.
O variabilă se va declara în segmentul de date .DSEG şi va reprezenta o etichetă urmată de o directivă de preprocesare .BYTE care permite rezervarea unei zone de memorie pentru variabila dată.
.DSEG ; variabilele for fi declarate in
; segmentul de date
; segmentul de date
; a 1 byte pentru aceasta variabila.
var1 : .BYTE 2 ; declaratia variabilei var2 si rezervarea
; a 2 byte pentru aceasta variabila.
; a 2 byte pentru aceasta variabila.
Pentru a inţelege mai bine mecanismul de declarare a variabilelor în ASM vom prezenta o comparaţie cu declaraţia de variabile în limbajul C++.
C++ | SIZE | ASM
char ch; | 8 bit , 1 byte | ch: .BYTE 1
int a; | 32 bit , 4 byte | a: .BYTE 4
short int b; | 16 bit , 2 byte | b: .BYTE 2
long int c; | 64 bit , 8 byte | c: .BYTE 8
float d; | 32 bit , 4 byte | d: .BYTE 4
double e; | 64 bit , 8 byte | e: .BYTE 8
Operaţii de transfer cu variabilele.
Operaţiile de transfer pentru variabile va fi executat cu comenzi de acces direct la memorie cum ar fi:
- LDS R, k - încărcarea directă a valorii de la adresa k din SRAM într-un registru de uz general.
- STS k, R - stocarea directă a valorii unui registru de uz general la adresa k din SRAM.
Etichetă - numele variabilei va reprezenta adresa primei locaţii a variabilei. Locatiile superioare după principiul "little-endian" se vor accesa după adresele imediat urmatoare.
Atribuirea unei valori constante către o variabilă.
Deorece nu există comanda de transfer a unei constante direct în SRAM, va trebui mai intai să încărcăm acea valoare intr-un registru de uz general după care transferată direct la adresa specificată de numele variabilei.
;EX: var1 = 25;
.DSEG ; variabilele for fi declarate in
; segmentul de date
; segmentul de date
.CSEG ; programul se scrie in segmentul de cod
ldi r16, 25
sts var1, r16
Pentru variabile de un volum mai mare de 1 byte atribuirea se va executa pentru fiecare byte separat. De menţionat eticheta-numele de variabilă este o adresă constantă. Luând în consideraţie că compilatorul evaluează operaţiile cu constantele în faza de pre-compilare adresa urmatorilor baiţi se poate forma prin adăugarea unui displasament la eticheta-nume, <nume_var>+q care este de fapt tot o constantă.
;EX: var2 = 2345;
.DSEG ; variabilele for fi declarate in
; segmentul de date
; segmentul de date
.CSEG ; programul se scrie in segmentul de cod
ldi r16, LOW(2345)
sts var2, r16
ldi r16, HIGH(2345)
sts var2+1, r16
Transferul unei valori de la o variabila la alta.
Asa cum pentru arhitectura AVR nu există o comandă de transfer de date direct dintr-o locaţie SRAM în alta, valoarea din locaţia de la adresa reprezentată prin numele variabilei sursa se va încărca mai întîi intr-un registru de uz general cu comanda LDS după care se va descărca direct în locaţia destinaţie cu STS.
;Ex: a = b;
.DSEG ; variabilele for fi declarate in
; segmentul de date
; segmentul de date
b : .BYTE 1 ; rezervare 1 byte pentru variabila b
.CSEG ; programul se scrie in segmentul de cod
lds r16, b ; incarcarea valorii variabilei
; b in registru de lucru
; b in registru de lucru
sts a, r16 ; descardcarea valorii registrului
; de lucru in variabila a
; de lucru in variabila a
Pentru variabile de un volum mai mare de un byte vom avea câte o operaţie de transfer pentru fiecare byte. Adresele baitilor superiori se vor forma din adresa de bază, eticheta-nume, şi constanta de deplasare care va indica numărul de ordine a byte-ului în variabilă.
;Ex: a = b;
.DSEG ; variabilele for fi declarate in
; segmentul de date
; segmentul de date
a : .BYTE 2 ; rezervare a 2 byte pentru variabila a
b : .BYTE 2 ; rezervare a 2 byte pentru variabila b
.CSEG ; programul se scrie in segmentul de cod
lds r16, b ; citire byte inferior din sursa
sts a, r16 ; stocare byte inferior la destinatie
lds r16, b+1 ; citire byte superior din sursa
sts a+1, r16 ; stocare byte inferior la destinatie
Operaţii aritmetice cu variabile
Pentru a evalua o operaţie artmetică între două variabile va trebui să transferăm mai întâi valorile variabilelor în regiştri de uz general după care vom avea posibilitatea de a evalua o operaţie aritmetică sau logică. Acest fapt se datorează restricţiilor arhitecturii care permite operaţii aritmetice doar cu regiştri de uz general.
;Ex: a = b + c;
.DSEG ; variabilele for fi declarate in
; segmentul de date
; segmentul de date
b : .BYTE 1 ; rezervare a 1 byte pentru variabila b
c : .BYTE 1 ; rezervare a 2 byte pentru variabila c
.CSEG ; programul se scrie in segmentul de cod
lds r15, b ; incarcarea valorii variabilei b
; intr-un registru de lucru
; intr-un registru de lucru
lds r16, c ; incarcarea valorii variabilei c
; in alt registru de lucru
; in alt registru de lucru
add r15, r16 ; evaluarea operatiei de adunare
sts a, r15 ; descarcarea rezultatului in variabila a
Acelaşi lucru vom face şi pentru variabile de o mărime de 2 byte. În acest caz variabila poate fi încărcată într-o pereche de regiştri, de ex: [R15:R14] = b. Pentru operaţiile între variabile mai mari de un byte va trebui să luăm în consideraţie transportul generat la operaţiile aritmetice între doi operanzi de 8 biţi.
;Ex: a = b + c;
.DSEG ; variabilele for fi declarate in
; segmentul de date
; segmentul de date
b : .BYTE 2 ; rezervare a 2 byte pentru variabila b
c : .BYTE 2 ; rezervare a 2 byte pentru variabila c
.CSEG ; programul se scrie in segmentul de cod
lds r14, b ; incarcarea primului byte a vartiabilei
; b in registru de lucru
; b in registru de lucru
lds r15, b+1 ; incarcarea al 2-lea byte a vartiabilei
; b in registru de lucru
; incarcarea variabilei c intr-o pereche de registri
; b in registru de lucru
; incarcarea variabilei c intr-o pereche de registri
lds r16, c
lds r17, c+1
add r14, r16 ; adunarea baiti inferiori
adc r15, r17 ; adunarea baiti superiori luand in
; consideratie transpiortul de la
; operatia precedenta
; consideratie transpiortul de la
; operatia precedenta
sts a, r14 ; preluarea byte rezultat inferior
sts a+1, r15 ; preluarea byte rezultat superior
Vom încerca acelaşi lucru şi pentru variabile de mărimea de 4 byte.
;Ex: a = b + c;
a : .BYTE 4 ; rezervare a 4 byte pentru variabila a
;Ex: a = b + c;
.DSEG ; variabilele for fi declarate in
; segmentul de date
; segmentul de date
b : .BYTE 4 ; rezervare a 4 byte pentru variabila b
c : .BYTE 4 ; rezervare a 4 byte pentru variabila c
.CSEG ; programul se scrie in segmentul de cod
; incarcare variabila b in 4 registri de lucru
; incarcare variabila b in 4 registri de lucru
lds r12, b
lds r13, b+1
; incarcare variabila c in 4 registri de lucru
lds r16, c
lds r17, c+1
lds r18, c+2
lds r19, c+3
; operatia de adunare a 4 baiti
add r12, r16
adc r13, r17
adc r14, r18
adc r15, r19
; preluarea rezultatelor din 4 registri in variabila a sts a, r12
sts a+1, r13
sts a+2, r14
sts a+3, r15
lds r13, b+1
lds r14, b+2
lds r15, b+3
lds r16, c
lds r17, c+1
lds r18, c+2
lds r19, c+3
; operatia de adunare a 4 baiti
add r12, r16
adc r13, r17
adc r14, r18
adc r15, r19
; preluarea rezultatelor din 4 registri in variabila a sts a, r12
sts a+1, r13
sts a+2, r14
sts a+3, r15
Nu putem să nu observăm un exces de utilizare a regiştrilor de uz general pentru aceasta operaţie, 8 la număr. Dacă vom încerca să evaluăm o asemenea operaţie cu variabile de o mărime mai mare, de ex. 8 baiti, vom implica în această operaţie 16 regiştri. Vom remarca că această metodă, de a încărca variabilele în întregime în regiştri nu este eficientă.
Luând în consideraţie că operaţiile de transfer nu modifică flaguri în registrul de stare SREG, am putea să încărcăm în regiştri pe rând baiţii de acelaşi ordin şi execută operaţiile. Stocarea byte-ului curent nu va modifica flagul de transport C, la fel ca şi operaţiile de încărcare a urmatorului byte, şi respectiv putem aplica comenzi ce vor lua în consideraţie transportul de la operaţia aritmetică precedentă. În aşa mod în operaţie vor fi implicaţi doar doi regiştri de uz general. Mai jos vom aplica metoda optimizată descrisă pentru operaţia cu variabile de 4 baiţi.
. ;Ex: a = b + c;
.DSEG ; variabilele for fi declarate in
; segmentul de date
; segmentul de date
b : .BYTE 4 ; rezervare a 4 byte pentru variabila b
c : .BYTE 4 ; rezervare a 4 byte pentru variabila c
.CSEG ; programul se scrie in segmentul de cod
lds r12, b ; incarcarea primului byte al variabilei
; a in registrul de lucru
lds r13, c ; incarcarea primului byte al variabilei
; c in registrul de lucru
add r12, r13 ; adunarea primului byte
sts a, r12 ; preluarea primului byte al rezultatului
; evaluarea operatiei pentru al 2-lea byte
lds r12, b+1
lds r13, c+1
adc r12, r13 ; adunare cu transport
sts a+1, r12
; evaluarea operatiei pentru al 3-lea byte
lds r12, b+2
lds r13, c+2
adc r12, r13
sts a+2, r12
; evaluarea operatiei pentru al 4-lea byte
lds r12, b+3
lds r13, c+3
adc r12, r13
sts a+3, r12
; a in registrul de lucru
lds r13, c ; incarcarea primului byte al variabilei
; c in registrul de lucru
add r12, r13 ; adunarea primului byte
sts a, r12 ; preluarea primului byte al rezultatului
; evaluarea operatiei pentru al 2-lea byte
lds r12, b+1
lds r13, c+1
adc r12, r13 ; adunare cu transport
sts a+1, r12
; evaluarea operatiei pentru al 3-lea byte
lds r12, b+2
lds r13, c+2
adc r12, r13
sts a+2, r12
; evaluarea operatiei pentru al 4-lea byte
lds r12, b+3
lds r13, c+3
adc r12, r13
sts a+3, r12
Variabile ca parametri de intrarea in subrutina
În cazul în care se doreşte o evaluare a unei variabile cu ajutorul unei subrutine, înainte de a apela subrutina va fi nevoie de a transfera conţinutul variabilelor în regiştrii utilizaţi ca parametri de intrare a subrutinei, iar după returnarea din subrutină rezultatul se va transfera în variabila destinaţie.
;Ex: a = MySub(b);
.DSEG ; variabilele for fi declarate in
; segmentul de date
; segmentul de date
b : .BYTE 1 ; rezervare a 1 byte pentru variabila b
.CSEG ; programul se scrie in segmentul de cod
push r16 ; salvarea registrului parametru
lds r16, b ; initializarea paramentrului cu
; valoarea variabilei
rcall MySub ; apelul subrutinei
sts a, r16 ; extragerea rezultatului
lds r16, b ; initializarea paramentrului cu
; valoarea variabilei
rcall MySub ; apelul subrutinei
sts a, r16 ; extragerea rezultatului
pop r16 ; restabilirea registrului paramentru
Niciun comentariu:
Trimiteți un comentariu