Microprocesoare (MP) #2

Tema: Subrutine cu parametri
Laborator Nr 2

Scopul lucrări:

 - initiere in procesul de chemare a subrutinei,
- protectia starii globale a registrilor
- transmiterea parametrilor catre subrutina

Sarcina lucrarii:
Sa se realizeze un program, care ar realiza calculul unei expresii simple: a * b + 22 cu ajutorul unei subroutine cu parametri. Sa se realizeze protectia starii globale a registrilor. Expresia: a*b+22

Consideraţii teoretice:

            Formatul subrutinei:
                                   My_sub:
                                                           …
                                                           …
                                                           …       
                                               RET


Subrutine poate fi chemata cu: RCALL(ne permite sa chemam o subrutina care nu este mai departe decat adresa de 256 locatii), ICALL(chemarea unei subrutine adresa careia se afla intr-un registru indirect. Aceasta comanda presupune ca adresa subrutinei preeliminar va fi incarcată în registrul indirect Z), CALL
O etichetă în Assembler va reprezenta adresa curentă.
Pentru a avea salvata adresa de returnare din subrutină, adresa curentă, de unde a avut loc chemarea subrutinei se va salva automat în stivă, adică PC + 1 -> Stack (se execută automat 2 PUSH-uri). Apoi are loc salt necondiţionat: PC <- My_sub şi se execută subrutina după ce se realizează PC <- Stack.
            Subrutinele sunt utila atunci când vrem să executăm un set de instrucţiuni de mai multe ori în diferite locuri a programului, dar şi pentru modularizarea şi reutilizarea codului.
            Subrutina reintrantă presupune că oricând va fi apelată – vom avea acelaşi rezultat, adică ea nu depinde de starea globală a sistemului.  
            Subrutina securizată – execuţia ei nu modifică starea globală.
            Pentru ca subrutina sa fie securizată, adică să nu modifice starea globală a regiştrilor se recomandă ca regiştrii utilizaţi pentru lucrul în interiorul subrutinei să fie salvaţi în stivă la începutul subrutinei (ex: PUSH R16, PUSH R18) şi restabiliţi imediat înainte de returnarea din ea (POP R18, POP R16).  Ordinea de restabilire este inversă celei de salvare(LIFO). Numărul de salvări în stivă trebuie să fie strict egal cu numărul de restabiliri, pentru evitarea spargerii stivei.   Cresterea necontrolată a stivei va duce la supraîncărcarea stivei şi invers, micşorarea necontrolată a stivei va provocarea spargerea ei.      Subrutina cu parametri. Parametrii către subrutină pot fi transmişi prin intermediul regiştrilor de uz general ca valori sau referinţe(pointeri) către anumite resurse.  Pentru returnarea din subrutină se vor folosi regiştri ca valori sau referinţe. Regiştrii utilizaţi ca parametrii se vor salva în stivă înainte de iniţializarea lor şi se vor restabili după colectarea rezultatelor returnate de către subrutină. Regiştrii utilizaţi ca parametri nu vor fi salvaţi în interiorul subrutinei. Mecanismul de protejare a lor este realizat în afara subrutinei.

Mersul lucrării:   
1) Schema bloc
2)      Următorul pas este crearea ciruitului în programul de simulare PROTEUS, unde se demonstrează cum funţionează porturile de I/O şi respectiv programul microcontrolerului.

Figura 1

Listengul programului:
Descrierea instrucţiunilor utilizate:

Instructiunea MOV

Sintaxa:
§  mov dest, source // echivalenta cu dest = source
Descriere:
Instructiunea copiaza o valoare dintr-o locatie in alta locatie. Aceasta locatie poate fi zona de memorie, variabila, registru. De retinut este ca nu exista variante ale instructiunii care copiaza direct dintr-o zona de memorie in alta.
Flaguri afectate
Instructiunea mov nu modifica nici un flag.

Restrictii:
Ambii operanzi trebuie sa aiba aceeasi marime. De exemplu pentru ultima varianta a instructiunii mov trebuie specificata marimea zonei de memorie. Instructiunea "mov [bx], 0" nu este corecta deoarece compilatorul nu stie ce vrea sa faca instructiunea: sa copieze valoarea 0 in byte-ul, in word-ul sau in doubleword-ul de la adresa bx. Astfel variantele corecte sunt:
1
2
3
mov byte ptr [bx], 0
mov word ptr [bx], 0
mov dword ptr [bx], 0
Exemplu:

mov ax, 3 // ax = 3
mov bx, ax // bx = ax

Instructiuni aritmetice. Instructiunile ADD, SUB, INC, DEC

Sintaxa:
§  add dest, source // echivalenta cu dest+=source
§  sub dest, source // echivalenta cu dest-=source
§  inc dest // echivalenta cu dest++
§  dec dest // echivalenta cu dest--
Descriere:
Instructiunea "add" este folosita pentru a aduna doua valori, "sub" pentru a scadea o valoare din alta, "inc" - incrementarea unei variabile, "dec" - decrementarea unei variabile (registru/memorie).
Flaguri afectate:
§  carry flag - pentru "signed overflow"
§  overflow flag - pentru overflow
§  sign flag - activat daca rezultatul este negativ
§  zero flag - activat daca rezultatul operatiei a fost 0
§  parity flag - este setat in functie de paritatea rezultatului
Restrictii:
Destinatia trebuie sa aiba aceeasi marime ca si sursa.
Exemplu:

mov ax, 3 // ax = 3
add bx, ax // bx = ax+3

 

Instructiunile PUSH/POP

Descriere:
Aceste instructiuni sunt folosite pentru accesarea stivei sistemului. Instructiunea PUSH pune pe stiva sistemului o valoare, iar instructiunea POP extrage valoarea din varful stivei.
Sintaxa:
§  push val
§  pop val
Instructiunea IN:
Forma: IN destinatie, port
Efect: citeste de la portul dat in destinatie.
Nota: destinatia poate fi doar AX sau AH.
Instructiunea OUT:
Forma: OUT destinatie, port
Efect: scrie la portul dat valoarea destinatiei.
Nota: destinatia poate fi doar AX sau AL.


Concluzi:

Efectuînd lacrarea de laborator „Subrutine cu parametri” am aflat inportanţa utilizări subrutinelor.
Subrutina este o secventa de instructiuni grupata intre o eticheta (label) si instructiune de returnare din subrutina RET. Eticheta reprezinta o adresa in memoria de programe fiindui atribuit un nume de acces. In program va fi reprezentata de un nume de eticheta urmata de (:). Dar mai întîi  trebuie de iniţializat stiva şi anume operatia de initializare a stivei va consta in initializarea indicatorului de stiva SP.
    SP = RAMEND,         [SPH:SPL] = RAMEND
Secventa de cod in ASM pentru operatia de mai sus va arata in felul urmator:
       ldi R16, LOW(RAMEND)    
       out SPL, R16          ; initializare byte inferior SP
       ldi R16, HIGH(RAMEND)   
       out SPH, R16          ; initializare byte superior SP 
unde:
LOW - macroinstructiunea pentru selectarea byte-ului inferior dintr-o constanta.
HIGH - macroinstructiunea pentru selectarea byte-ului superior dintr-o constanta.