Sunteți pe pagina 1din 51

Curs 1 - 21.02.

2011

CAPITOLUL I
1.1 Arhitectura procesorului I8086
Executia unui program intr-un sistem cu microprocesor are ca efect ( intr-o abordare simplificata) respectarea ciclica a urmatorilor pasi: 1. extragerea instructiunii din memorie; 2. citirea unui operand sau a mai multor operanzi (daca instructiunea o cere); 3. executia instructiunii 4. scrierea rezultatului( daca instructiunea o cere). Datorita arhitecturii specifice, executia acestor pasi are loc in doua unitati separate de procesare a datelor din cadrul CPU (Unitatea Centrala de Prelucrare) : EU (Unitatea de Executie) si BIU (Unitatea de Interfata Magistrala). CPU= EU + BIU In EU are loc executia instructiunilor, in timp ce BIU extrage instructiunile, citeste operanzii si scrie rezultatele in memorie. Cele doua unitati pot opera independent una de cealalta si pot asigura in majoritatea cazurilor suprapunerea in timp a etapei de extragere a instructiunilor cu etapa de executie a unei instructiuni precedent extrase din memorie. In acest mod dispare timpul necesar extragerii din memorie crescand viteza de lucru a microprocesorului deoarece EU executa instructiuni al caror cat a fost deja adus de catre BIU din memorie in microprocesor .

Fig. 1.1. Suprapunerea in timp a etapelor de extragere si executie a instructiunilor procesorului 8086

Figura 1 ilustreaza aceasta suprapunere a fazelor de extragere si executie a lor printr-un exemplu in care timpel necesar executiei a 3 instructiuni este mai mic ca 8086 in comparatie cu microprocesoarele din generatia precedenta.

1.1.1 EU Unitatea de Executie


EU contine registri de uz general, unitatea aritmetico-logica , registrul indicatorilor de conditie, un bloc logic de control si o magistrala interna de date de 16 biti.

Fig. 1.2. 8086 schema bloc

Functiile EU acopera executia tuturor instructiunilor, furnizarea datelor si a adreselor catre BIU, controlul registrelor de uz general si a indicatorulor de conditie. Cu exceptia catorva pini de control unitatea de executie este complet izolata de lumea exterioara. Asa cum se observa din Fig. 1.2, EU preia instructiunea urmatoare de executat dintr-o coada de asteptare, alimentata continuu de BIU. In situatia in care nu exista nici o instructiune de preluat, pentru a fi executata, EU asteapta pana cand coada esre realimentata de BIU. Daca in cursul executiei instructiunii este necesar accesul la o locatie de memorie sau la un echipament periferic, EU solicita BIU sa transfere data executand ciclul de magistrala corespunzator (citire / scriere la memorie sau port). Totodata, desi magistrala EU are doar 16 biti, se poate accesa prin exterior intregul spatiu de 1 megaoctet de memorie prin intermediul BIU.

1.1.2 BIU (Unitatea de Interfata cu Magistrala)


Aceasta executa toate operatiile externe de magistrala ce sunt necesare pe parcursul extragerii si executiei unei instructiuni. Ea se compune din registri de segment, un registru de tip control de program ( PC), denumir si pointer de instructiuni, registri de comunitatie interna, o schema logica pentru generarea adresei pe cele 20 de linii de adresa ale microprocesorului 8086 si pentru controlul magistralei multiplexate precum si o coada de instructiuni. Aceasta este realizata cu o memorie RAM de 8 octeti si contine instructiuni ce sunt extrase in avans de BIU si urmeaza sa fie prelucrate de EU pentru decodificare si executie. Cele doua unitati de procesare ale CPU opereaza independent una de alta ins ensul ca ori de cate ori 2 sau mai multi octeti dinc oada sunt liberi , iar EU nu solicita BIU la efectuarea vreunui ciclu de magistrala, unitatea de interfata cu magistrala executa in avans ciclul de extragere de instructiuni pentru a realimenta locatiile libere din coada de instructiuni. Acest mod de lucru permite BIU sa furnizeze EU, instructiuni extrase anterior fara a monopoliza magistrala sistemului, caci in mod normal, in majoritatea situatiilor, doada de instructiuni contine cel putin nu octet ce poate fi preluat de EU pentru decodificare si executie. In plus, cum sistemelor cu microprocesor 8086 au uzual magistrala de date de 16 biti , intr-un singur ciclu de extragere se alimenteaza coada cu 2 octeti, cu exceptia cazurilor cand adresa de la care se citeste instructiunea urmatoare este impara. Instructiunile extrase in avans de BIU sunt cele care urmeaza in mod logic intr-o procesare seriala a programului, ele aflandu-se in memorie in locatii adiacente si la adrese superioare adresei instructiunii ce se executa cu o instructiune care transfera controlul programului catre o alta locatie de memorie , BIU reseteaza coada, extrage instructiunea de la noua adresa transferand-o imediat unitatii de executie, apoi incepe o realimentare a cozii de la noua loactie. De asemenea BIU suspenda operatiile de extragere de instructiuni( cu exceptia celei in curs de desfasurare) ori de cate ori unitatea de executie solicita efectuarea pe lagistrala a unui transfer cu memoria sua pe un port de intrare/iesire.

1.1.3 Registrele de uz general


Microprocesorul 8086 are 8 registre generale de 16 biti grupare in doua seturi a cate 4 registre fiecare : registre de date ( uneori denumite grupul registrelor N & L ) si registrele de coindex si index ( denumite si grupul P & I). Un registru apartinand grupului N&L se caracterizeaza prin faptul ca poate di adresat ca registru de 16 biti, dat se compune din doua entitati de 8 biti, partea High si partea Low, ce pot fi adresate separat ca registre pe 8 biti. Registrele de pointer si inder nu pot fi adresate decat ca registre pe 16 biti. Atat registrele de date cat si registrele coindex si index pot fi utilizate in majoritatea operatiilor aritmetice, oricare dintre ele putand juca rolul registrului acumulator existent la generatiile precedente de microprocesoare. Pentru a permite utilizarea unui set compact dar puternic de instructiuni , anumite registre sunt folosite in mod implicit de unele instructiuni asa cum arata tabelul 1.1

Tabelul 1.1. Utilizarea implicita a registrelor de uz general

1.1.4 Registrele de segment


Spatiul fizic de memorie de 1 megaoctet direct adresabil de microprocesorul 8086 este divizat in segmente logice de pana la 64 kiloocteti fiecare. CPU are acces direct in orice memoent la 4 segmente logice ale caror adrese de baza( adresele de inceput ale segmentelor )se afla in registri de segment ai microprocesorului. Spatiul segmentului de cod (CS) contine adresa de inceput a segmentului din care sunt extrase instructiunile(segmente de cod). Stiva programului se afla in asa-numitul segment de stiva catre care pointeaza registrul segmentului de stiva (SS). Mai exista de asemenea doua segmente de date, unul propriuzis (DS) si unul suplimentar (ES) fiecaruia fiindui asociat cate un registru de segment ce contine adresa de inceput respectiva. Si registrele de segment sunt accesibile programatorului, continutl lor putand fi modificat de anumite instructiuni ( Fig 1.4)

Curs 2 28.02.2011 1.1.5 Registrul pointerului de instructiuni


Este similar cu registrul contor de program (Program Counter) al microprocesorului pe 8 biti. Actualizat de BIU el contine offset-ul ( distanta in octeti) urmatoarei instructiuni, masurat de la inceputul segmentului curent de cod. Altfel spus IP (Instruction Pointer) reprezinta in mod normal un pointer catre urmatoarea instructiune ce urmeaza a fi extras de BIU, iar atunci cand

este salvat in stiva, se modifica automat pentru a indica offset-ul urmatoarei instructiuni ce rumeaza a fis executata de EU. Operarea cu continutul IP, odata salvat in stiva constituie calea prin care aceasta poate fi modificata indirect in decursul executiei unui program.

1.1.6 Indicatorii de conditie Microprocesorul are 6 biti de stare si 3 biti de control, grupati in registrul indicatorilor de conditie (Flags). Cei de stare sunt pozitionati in unitatea de executie pentru a reflecta anumite proprietati ale rezultatlui unei operatii aritmetice sau logice. Acestia pot fi utilizati de un grup al setului de isntructiuni pentru a modifica secventialitatea executiei programului inf unctie de rezultatul operatiei anterioare. In geneal Flags reflecta urmatoarele conditii: AF auxiliary quierry flag. Daca AF=1 a existat un transport dinspre bitul 7 spre bitul 8, sau un imprumut dinspre bitul 8 spre bitul 7. Acest indicator este folosit indeosebi in cazuri ce implica operatii aritmetice de numere zecimale codificate binar. CF carry flag. Daca CF=1 a existat un transport dinspre, sau un imprumut spre cel mai semnificativ MSB utilizat de instructiunile ce implica operatii de adunare sau scadere cu numere reprezentate pe unul sau mai multi octeti. Biti ai operanzilor din memorie sau registri pot fi izolati in CF prin intermediul instructiunilor de rotire si deplasare. OF overflow flag. Daca OF=1, a aparut o depasire aritmetica, adica s-a pierdut cel mai semnificativ bit al rezultatului, pentru ca dimensiunea acestuia a depasit capacitatea locatiei destinate.Este de remarcat faptul ca exista o instructiune( INTerrupt On Overflow) caregenereaza o cerere de intrerupere pentru semnalarea aparitiei acestei situatii. SF sign flag. SF=1 indica faptul ca cel mai semnificativ bit al rezultatului are valoarea 1. Cum numerele intregi cu semn sunt reprezentate in complement fata de 2 rezulta ca SF arata semnul rezultatului ( 0= pozitiv, 1=negativ). PF parity flag. PF=1 atunci cand rezultatul are un numar par de biti pozitionati pe 1. ZF - zero flag. Valoarea 0 al rezultatului este evidentiata prin ZF=1. Cei 3 indicatori de control pot fi modificati prin program pentru a determina anumite operatii ale procesorului. Astfel : DF direction flag. Acest indicator este utilizat de instructiunile ce opereaza cu siruri de caractere(string) si semnaleaza autodecrementarea (DF=1) respectiv autoincrementarea ( DF=0), registrilor SI siDI ce contin offset-ul adreselor sursa si destinatie ce intervin in transfer. IF interrupt flag. Setarea IF prin instructiunea SeT Interrupt enable flag permite CPU sa recunoasca cererile de intrerupere externa in timp ce resetarea aceluiasi indicator cu instructiunea CLear Interrupt enable flag le va dezactiva. Modificarea valorii lui IF nu are efect asupra intreruperilor generale intern in CPU sau a celor externe nemascabile. TF trap flag. Daca TF=1 procesorul intra in modul de operare pas cu pas in care CPU genereaza automat o intrerupere interna dupa fiecare instructiune pentru a permite examinarea starii programului deci depanarea acestuia ( fig 1.5)

Fig. 1.5. Indicatorii de conditii

1.7 Organizarea memoriei


Microprocesorul 8086 poate adresa direct un spatiu de 1 megaoctet= 1048576 octeti organizat liniar cu adresele joase la inceput si adresele inalte la sfarsit. Instructiunile si datele pe octet sau cuvant pot fi plasate liber la orice adresa fie ea para sau impara, pentru a permite o stocare densa a codului programului in memorie acestea fiind unui din conceptele impuse la proiectarea procesorului. ( fig 1.6)

Fig . 1.6. Organizarea memoriei Memorarea variabilelor si instructiunilor

Trebuie remarcat faptul ca memoria unei variabile de tip word la o adresa impara (situatie in care se spune ca variabila este nealiniata) anuleaza din punct de vedere al transferului variabilei respective avantajul microprocesorului 8086 de a avea o magistrala de date de 16 biti. In ceea ce priveste instructiunile, alinierea sau nealinierea lor nu afecteaza performantele microprocesorului datorita cozii de asteptare din BIU. Conform conventiilor Intel, o variabila de tip word este mereu memorata cu octetul cel mai semnificativ in locatia de memorie au adresa superioasa. Aceasta regula se extinde si la memorarea datelor de tip pointer(variabile pe un cuvant dublu folosite pentru a adresa date in afarasegmentului de date sau de program) ce este adresata in mod curent la momentul respectiv: cuvantul ce contine offset-ul se memoreaza la cele doua adrese inferioare, cuvantul ce contine adresa de baza al segmentului se memoreaza la cele doua adrese superioare la

care este stocat pointerul, iar in cazul fiecarui cuvant, octetul cel mai semnificativ este la randul lui memorat la adresa superioara. (fig. 1.7)

Valoarea variabilei word VALOAREA POINTERULUI STOCAT LA 4H: memorata la 246H este 8C04H ADRESA BAZA SEGMENT:3B4CH OFFSET:65H
Fig. 1.7. Memorarea variabilelor de tip word si pointer

1.7.1 Segmentarea memoriei


8086 localizeaza spatiul de memorie fizica de un megaoctet prin intermediul unui grup de segmente logice, definite de fiecare aplicatie in parte. Segmentele sunt unitati logice de memorie continua cu marimea de 64 kocteti fiecare, independente unele de altele si adresabile in mod separat. Fiecarui segment i se asigneaza software o adresa de baza ce reprezinta adresa de inceput a respectivului segment, mai concret adresa celei mai de jos locatii de memorie a segmentului. Singura restrictie ce se aplica segmentelor logice este ca aceasta adresa de baza sa fie un multiplu de 16.In rest segmentele pot fi adiacente, disjuncte, suprapuse partial sau total (fig 1.8) astfel incat o locatie fizica de memorie poate fie sa nu apartina niciunui segment, fie sa apartina unui segment , fie mai multor segmente.

Fig. 1.8. Alocarea segmentelor in memoria fizica

Amintindu-ne ca in BIU exista 4 registre de segment ce contin fiecare cate o adresa de baza de segment rezulta ca la un moment dat exista 4 segmente adresabile in mod curent ( fig 1.9).

Fig. 1.9. Segmentele adresabile in mod curent

In cursul executiei unui program, accesul la instructiuni sau date, apartinand altor segmente decat cele adresabile in mod curent se face prin simpla modificare a continuturilor registrelor de segment corespunzator. Fiecare aplicatie trebuie sa defineasca de la inceput adresele de baza ale segmentelor pentru a se putea asigura localizarea informatiilor in memorie. Daca 64 kocteti de cod, 64 kocteti de stiva si 128 kocteti de date sunt suficienti pentru aplicatia respectiva, registrele de segment raman nemodificate pana la terminarea executiei acesteia. Pentru aplicatii mai complexe, se recomanda fie modularea programelor, fiea\ utilizarea corecta a registrelor de segment.

1.7.2 Generarea adresei fizice


Se poate imagina ca fiecare locatie de memorieare doua feluri de adresa: fizica si logica. Adresa fizica este acea valoare pe 20 de biti care poate identifica un mod unic fiecare octet din spatiul de memorie de un megaoctet. Ea este curpinsa intre 0h si FFFFFh si exista pe liniile magistralei multiplexate la inceputul fiecarui ciclu de scriere sau citire din/in memorie. Programatorul opereaza mai mult cu adresa logica decat cu cea fizica, ceea ce permite scrierea unui program fara a sti dinainte locul unde codul acestuia va fi incarcat in memorie si faciliteaza controlul dinamic al resurselor din memorie. O adresa logica consta intr-o valoare de baza a segmentului si o valoare de offset, ambele fiind marimi fara semn reprezentate pe 16 biti. Pentru orice locatie de memorie, valoarea de baza a segmentului indica primul octet continut in segment( inceputul segmentului), iar valoarea de offset reprezinta distanta in octeti de la inceput pana la locatia respectiva.Primul octet( cel mai de jos) apartinand unui segment are deci offsetul 0. Avand in vede conceptul de segment logic rezulta ca locatia fizica de memorie poate avea o multime de adrese logice. Acest fapt este ilustrat in figura 1.10 in care locatia de memorie fizica 2C3H este continut in segmente logice, suprapuse partial, unul incepand la 200h iar altul la 2C0h.

Fig. 1.10. Adresa fizica si adrese logice

Ori de cate ori unitatea de interfata cu magistrala acceseaza memoria pentru a extrage o instructiune sau pentru a obtine sau stoca o variabila, ea genereaza adresa fizica pe baza adresei logice. Aceasta se realizeaza prin deplasarea la stanga cu 4 pozitii binare a valorii de baza din registrul de segment si adunarea valorii de offset. (fig 1.11)

Fig. 1.11.

BIU obtine adresa logica a locatiei de memorie din diferite surse in functie de scopul accesului la memorie ( tabel 1.2).

Tabelul 1.2. Sursele de adresa logica

Instructiunile sunt extrase din segmentul de cod, iar offset-ul este dat de registrul IP, operatiile cu stiva sunt executate in segmentul de stiva curent, iar offset-ul este dat de registrul SP, s.a.m.d. Offset-ul unei variabile de executie este calculat de unitatea de executie in functie de modul de adresare specificat in instructiune; rezultatul se numeste adresa efectiva ( effective address EA).

Curs 3 07.03.2011 (continuare)


In majoritatea cazurilor utilizarea segmentelor implicite pentru accesul datelor in memorie este convenabila pentru programator. Este posibil si accesul unei variabile in oricare dintre segmentele adresate in mos curent (cu exceptia instructiunilor ce manipuleaza siruri de caractere unde operandul destinatiei este obligatoriu sa se gaseasca in segmentul de date suplimentar). Pentru a obtine acest lucru, instructiunea trebuie precedata de un prefix, ce indica BIU ce registru de segment sa utilizeze pentru a accesa variabila respectiva.

Modul de obtinere a adresei fizice si structura sa a memoriei creaza posibilitatea realizarii de programe ce nu depind de locul unde sunt icanrcate in memorie, adica programe relocabile in mod dinamic, ceea ce permite utilizarea de plina a memoriei disponibile si realizarea de sisteme multitasking. Astfel programele inactive pot fi indepartate din memorie (transferate de disc) si spatiul ocupat de ele, alocat altor programe. Activarea unui program se face prin incarcarea lui in orice zona libera din memorie si lansarea in executie. In mod similar daca un program are nevoie de un spatiu de memorare continuu, de capacitate mare, iar zona disponibila este fragmentata, segmentele altui program pot fi compactate pentru a elibera spatiul. (fig 1.12)

Fig. 1.12. Relocatarea dinamica a programelor

Pentru a fi relocabil dinamic, un program trebuie sa nu-siincarce sau modifice registrele de segment sau sa transfere controlul intr-o locatie aflata in afara segmentului curent de cod. Toate offset-urile pot fi relative la valorile fixe continute in registrele de segment. Programul poate fi mutat oriunde in memorie prin simpla actualizare a adreselor de baza pe segment.

1.7.3 Stiva
Stiva microprocesorului 8086 este implementata in memorie prin intermediul registrului de segment SS si al registrului de stiva SP ( Spack Pointer). Un sistem poate avea un numar nelimitat de stive a cate cel mult 64 kocteti fiecare dar una singura este direct adresabila la un moment dat: aceasta este stiva curenta sau stiva. SP contine offset-ul varfului stivei ( TOS - top off stack) fata de adresa de baza indicata de registrul SS. Cum elementele stivei sunt cuvinte de 16 biti, instructiunile ce opereaza cu stiva cauzeaza decrementarea ( pentru PUSH) respectiv incrementarea ( pentru POP) cu 2 a registrului indicator pe stiva SP. (fig 1.13)

10

Fig. 1.13. Operatii cu stiva

Cu alte cuvinte stiva creste in jos in memorie catre adresa de baza a segmentului de stiva. Este de remarcat faptul ca operatiile cu stiva nu transfera elemente dintr-o zona in alta a acesteia, nici nu le sterge, ci doar provoaca modificari varfului stivei prin actualizarea registrului SP. O constrangere ce se aplica tuturor segmentelor de memorie, nu numai stivei este cauzata de existenta unor locatii de memorie dedicate sau rezervate. Aceste locatii prezentate in figura 1.14 sunt : de la 0h pana la 7Fh(128 octeti) si de la FFFF0h pana la FFFFFh (16 octeti). Ele sunt folosite pentru intrerupeti si pentru pornirea sistemului dupa reset putand fi si rezervate de firma pentru dezvoltari ulterioare, iar utilizarea lor de catre programator trebuie sa se faca respectand scopul pentru care au fost definite ca locatii speciale.

Fig. 1.14. Spatiul de memorie si I/E cu precizarea "locatiilor speciale"

11

1.8 Sistemul de intreruperi


Una din cele mai utilizate metode pentru a efectua operatiile de intrare-iesire se bazeaza pe utilizarea tehnicilor intreruperilor. Prin aceasta metoda executia programului principal de CPU este oprita in mod asincron, de un echipament de IE care solocita printr-o cerere de intrerupere un tratament preferential(tratament ce sa rezolve cauza ce a generat aparitia evenimentului semnificativ ce a determinat cerere de intrerupere). Procesorul termina de executat instructiunea curenta si prin intermediul unui vector de intrerupere ajunge la rutina de tratare a intreruperii respective in care serveste echipamentul ce a solicitat intreruperea. La sfarsitul acestei subrutine, procesorul revine la programul principal, reluandu-l de la instructiunea urmatoare celei ce a fost executate inainte de acceptarea intreruperii.Prin acest mecanism operatiile de IE sunt executate practic fara intarziere fata de momentul in care apare necesitatea efectuarilor. Aceasta implica insa existenta unui hardware suplimentar, care sa permita implementarea unui astfel de mod de operare (circuitul Intel 8259 programmable interrupt controller este special proiectat in acest scop ), fiind pe deplin compatibil cu sistemul de intrerupere a lui 8086. In plus fata de intreruperile generate de porturile IE, care apartin clasei intreruperilor generate, 8086 poate fi solicitat si de intreruperi generate intern, ca urmare a executiei programului.

1.8.1 Sursele de generare a intreruperilor


Microprocesorul 8086 accepta intreruperi externe(generate de un echipament extern) si intreruperi interne ( generate intern in CPU) fie prin executia unei instructiuni specifice ( intreruperi software), fie ca urmare a intrunirii unor conditii specifice la nivelul microprocesorului. Fiecarei intreruperi i se atribuie un cod numit tipul intreruperii, ce permite identificarea acesteia de microprocesor. 8086 poate manipula pana la 256 tipuri diferite de intreruperi. Figura 1.15 prezinta posibile surse de intrerupere intr-un sistem cu microprocesor 8086, iar figura 1.16 ilustreaza secventa de raspuns a logicii de control a intreruperilor.

Fig. 1.15. Sursele de intrerupere

12

Fig. 1.16. Secventa de raspuns la intrerupere

1.8.2 Vectorii de intrerupere


Legatura dintre tipul intreruperii si procedura care deserveste intreruperea respectiva este prezenta de tabela vectorilor de intrerupere. Aceasta tabela ocupa primul koctet de memorie incepand cu adresa 0 si are pana la 256 de intrari, corespunzand la 256 vectori de intrerupere cate unul pentru fiecare tip de intrerupere ce poate fi definit intr-un sistem cu microprocesor 8086. Un vector de intrerupere al microprocesorului 8086 reprezinta un pointer (4 octeti) continand adresa rutinei de tratare a intreruperii asociate. Cuvantul cel mai semnificativ al pointerului contine adresa de baza de segment ( si se va incarca in

13

registrul CS), iar cuvantul mai putin semnificativ contine offset-ul fata de inceputul segmentului subrutinei respective ( offset ce se va incarca in registrul IP) astfel incat urmatoarea instructiune din cadrul subrutinei de intrerupere. Cum fiecare intrare in tabela vectorilor de intrerupere are o lungime de 4 octeti, CPU calculeaza locatia vectorului asociat unei intreruperi prin simple * cu 4 a numarului ( cuprins intre 0 si 255) ce reprezinta tipul intreruperii respectve ( fig 1.17).

Fig. 1.17. Directionarea catre rutina de tratare a intreruperii prin intermediul tabelei vectorilor de intrerupere

Primii 5 octeti de intrerupere sunt dedicati intreruperilor generate prin software precum si unei intreruperi externe, NMI ( 0- devide error, 1- single step, 2- NMI, 3- break point, 4- over flow), urmatorii 27 ( pana la locatia 07Fh) sunt rezervati de firma Intel, iar restul vectorii 32 pana la 255 sunt la dispozitia utilizatorului.

Curs 4 14.03.2011 1.8.3 Intreruperile externe


Microprocesorul 8086 pune la dispozitia surselor externe de intrerupere doua linii de intrare prin care se poate comunica CPU, o cerere de intrerupere. Una este linia NMI(cerere de intrerupere nemascabila), o intrerupere pe aceasta cale aparand ca rezultat al tranzitiei pozitive a semnalului NMI. Cum intrarea este asincrona, pentru a fi sigur ca este recunoscuta, NMI trebuie sa aiba o durata de minim 2 perioade de ceas. Cererea de intrerupere nemascabila este utilizata de obicei pentru a semnala procesorului aparitia unui eveniment catastrofal ce semnifica existenta unui pericol major pentru buna functionare a sistemului. Exemple tipice sunt iminenta cadere a tensiunii de alimentare, aparitia unei erori de memorie sau a unei erori de paritate pe magistrala.

14

Deoarece intreruperii NMI ii este asociat tipul 2 de intrerupere, la acceptarea acestuia ( la sfarsitul executiei interactiunii curente) controlul programului este transferat rutinei de tratare a intreruperii nemascabile a carei adrese este data de vectorul 2. Aceasta implica salvarea din stiva a continutului registrelor, indicatorilor de conditie (SP este decrementat cu 2) si apoi resetarea indicatorilor IF si TF (dezactivandu-se automat intreruperile mascabile si intreruperea pentru modul de operare pas cu pas). Registrele CS si IP sunt incarcate cu adresele continute de vectorul 2, urmand extragerea si executia primei instructiuni din rutina de tratare a intreruperii nemascabile. A doua cale rpin care sistemul extern de intreruperi poate emite o cerere de intrerupere este linia INTR. Aceasta este de obicei activata de controllerul de intreruperi 8259A ale carui sarcini in ceea ce priveste declansarea unui proces de intrerupere sunt urmatoarele: a. primeste cerere de intrerupere de la echipamentele de I/O atasate la el; b. determina acre dintre solicitani(daca apar mai mult de 1) are cea mai inalta prioritate; c. activeaza linia INTR catre microprocesor daca solicitantul selectat are un nivel de prioritate mai mare decat al celui care este servit in acel moment ( daca exista unul in aceasta situatie). Cele aratate mai sus sugereaza faptul ca Intel 8259A este un circuit programabil fiind controlat prin software de catre programul executat 8086 in care controllerul de intreruperi este privit ca o interfata specializata ( un set de porturi I/O ).

Fig. 1.18. Schema bloc si configuratia pinilor circuitului INTEL 8259A

15

In plus circuitul are un rol important in specificarea vectorului asociat unei cereri de intreruperi a circuitului de microprocesor. Aparitia semnalului INTR cauzeaza actiuni diferite ale CPU in functie de starea indicatorului de pozitie, de activare a intreruperii mascabile(IF). Starea acestuia este controlata de instructiunile STI (IF=1) si CLI (IF=0). Nici o actiune nua re loc insa pana la tensiunea instructiunii curente. Apoi daca IF=0 (ceea ce inseamna ca intreruperile ce apar pe linia INTR sunt mascate, dezactivate) CPU ignora cererea de intrerupere si continua cu executia urmatoarei instructiuni. Este de notat faptul ca semnalul INTR nu este memorat intr-un circuit latch in microprocesor astfel incat el trebuie mentinut activ pana se primeste un raspuns sau cererea este retrasa. Din punct de vedere al specificatiei de semnal, intrarea INTR este activa pe nivel si triggerata pe frontul pozitiv al ceasului CLK. Ea trebuie sa fie deci activa pe durata perioadei de ceas ce precede sfarsitul executiei instructiunii curente. Daca intreruperile sunt activate(IF=1) atunci CPU recunoaste intreruperea ( o accepta) si urmeaza sa o proceseze in afara isntructiunilor CLI si CTI, intreruperile ce sosesc la controlul de intreruperi pot fi selectiv mascate ( unele imbibate) altele activate prin cuvinte de comanda trimise catre 8259A cuvinte ce programreaza starea bitilot unui registru de mascare a cererilor de intrerupere ce exista la nivelul acesteia..

Fig. 1.19. Secventa de recunoastere a intreruperii INTR

Asa cum se vede in figura 1.19 recunoasterea unei intreruperi mascabile implica executia de catre microprocesor a doua cicluri de masgitrala de acceptare a intreruperii (cliclii INTA). Pe durata primului ciclu CPU isi trece starea de inalta impedanta driver-ele de magistrala si furnizeaza semnalul de control INTA ( INTerrupt Acknowledge) din starea T2 pana in starea T4. Daca este modul minim microprocesorul va refuza recunoasterea unei cereri de magistrala (HOLD) pana la terminarea completa a secventei de acceptare a intreruperii. Daca este in modul maxim, 8086 isi activeaza iesirea LOCK incepand cu starea T2a primului ciclu si pana in starea T2 a celui de-al doilea ciclu, pentru a semnala un eventual arbitru de masgistrala (Intel 8259) interzicerea accesului unui alt procesor pe magistrala. Rolul acestui prin ciclu INTA este de a avertiza controllerul de intrerupero ca cererea transmisa pe linia INTR este onorata de microprocesor.

16

8259A este gata sa participe la transferul executiai programului catre rutina de tratare a intreruperii in cauza. Aceasta se realizeaza pe parcursul celui de-al doilea ciclu INTA initial pe microprocesor, in care 8259 plaseaza pe liniile cel mai putin semnificative ale magitralei de date (AD7 AD0) un octet ce contine tipul intreruperii asociale liniei INTerrupt Request ( vezi figura 1.18) activata de echipamentul care a solicitat intreruperea. In acest mod se realizeaza identificarea sursei externe ce a generat intreruperea.

Tabelul 1.3. Octetul vectorului de intrerupere

In tabelul 1.3 este ilustrat modeul ce constituie octetul respectiv. Bitii D7 D3 sunt la dispozitia utilizatorului si sunt incarcati printr-un cuvant de comanda la programarea circuitului. Bitii D2-D0 sunt automat inserati de 8259A pentru a specifica pe care dintre cele 8 intrari IR7-IR0 a primit o cerere de intrerupere in urma careia a general semnalul INDR catre microprocesor , cauzand astfel cele doua cicluri INTA> Octetul in discutie( reprezentand chiar tipul intreruperii) este citit de CPU intocmai ca un ciclu READ ( in ambele cicluri INTA etse acompaniat de semnalele DT/R si DEN), valoarea lui multiplicata cu 4 implicit adresa din tabela vectorilor de intrerupere unde se gaseste ( prin grija programatorului) adresa rutinei de tratare a intreruperii determinanta de tipul respectiv. Saltul efectiv la rutina de serviciu se face din acest moment la fel ca si in cazul intreruperii nemascabile(procedeul este valabil si pentru intreruperile interne): se salveaza in stiva indicatorii de conditie , se reseteaza IF si TF, se salveaza CS si IP si se incarca noile valori ale registrelor TS si IP din tabela vectorilor de intrerupere. Intreruperea INTR are prioritate mai mica decat NMI.

Curs 5 21.03.2011
1.8.5 Subrutina de tratare a intreruperii
Cand se intra intr-o rutina de trarae a intreruperii se salveaza in stiva in mod automat indicatorii de conditie in registrele CS si IP iar TF si IF sunt resetati. Procedura respectiva poate reactiva intreruperile externe cu instructiunea STI, permitand sa fie ea insasi intrerupta de o cerere pe linia INTR si desigur, ca o rutina de tratare a intreruperii poate fi oricand suspendata de o cerere de intrerupere nemascabila. Acelasi efect il are si aparitia uneiintreruperi interne. Trebuie evitata posibilitatea ca o intrerupere de un anumit tip sa-si intrerupa propria rutina de serviciu a intreruperii interne. Trebuie evitata posibilitatea ca o intrerupere de un anumit tip sa-si intrerupa propria rutina de serviciu a intreruperii ( de exemplu o incercare de impartire la 0 in rutina de tratare a intreruperii de tip 0 ar avea ca efect reintrarea continua in procedura respectiva).

17

Subrutina de trarae a unei intreruperi trebuie sa salveze toti registri pe care ii utilizeaza inainte de a initializa toti registri pe care ii utilizeaza inainte de a initializa si sa ii restaureze inainte de terminarea rutinei. Ca urmare in cazul procesarii unor intreruperi simultane, stiva trebuie sa aiba la dispozitie un spatiu suficient pentru salvarile succesive ce pto aparea. O alta problema ce trebuie avuta in vedere este faptul ca dezactivarea intreruperilor externe intr-o rutina de tratare a unei intreruperi poate duce la pierderea acestora daca rutina are un cod prea mare. Toate subrutinele de intrerupere trebuie sa se termine cu instructiunea IRET ( Interrupt RETurn), instructiunea a carei executie se bazeaza pe ipoteza ca stiva este dina ceiasi conditie in care a fost la intrarea in procedura. IRET extrage din stiva 3 cuvinte succesive pe care le incarca in IP,CS si registrul indicatorilor de conditie determinand astfel reluarea executiei programului cu instructiunea ce urma in mod logic daca nu s-ar fi efectuat saltul la intrerupere. Ceea ce se proceseaza efectiv in cazul unei rutine de tratare a intreruperii depinde de aplicatia respectiva. De exemplu in cazul unei proceduri care serveste o cerere de intrerupere externa, prima actiune ce trebuie executata( daca nu se intampla automat) este trimiterea comenzii catre echipamentul ce este servit prin care sa se determine cererea de intrerupere. Urmatoarea actiune uzuala este de a se citi starea echipamentului pentru a se identifica motivul care s-a solicitat o intrerupere. In functie de cauza respectiva se comanda executia unor operatii corespunzatoare.

CAPITOLUL II Structutarea programelor, definirea si initializarea datelor. Operatori.


Capitolul curent si cel urmator sunt dedicate in limbajul de asamblare. Pe langa instructiunile propriuzise, un program asm poate curpinde directive prin intermediul carora se definesc date, etichete si proceduri, se structureaza segmente, se definesc si se utilizeaza macroinstructiuni, se controleaza in general procesul de asamblare, etc. Directivele nu reprezinta instructiuni ci comenzi catre asamblor, efectul lor manifestanduse exclusiv in faza de asamblare.

3.1 Segmantarea.Directive pentru definirea segmentelor


Un modul de program in limbaj de asamblare poate conduce la : o portiune dintr-un segment; un segment; portiuni de segmente diferite; mai multe segmente. Mai multe module obiect se leaga prin operatia de linkeditare.

3.1.1 Directivele SEGMENT si ENDS


Indiferent de modul de dezvoltare a unui program asm atat instructiunile cat si datele trebuie sa se gaseasca in interiorul unui segment. Directiva SEGMENT controleaza: numele segmentului; alinierea;

18

combinarea cu alte segmente; continuitatea (adiacenta) segmentelor.

Forma generala a directivei SEGMENT este : nume SEGMENT [tip_aliniere] [tip_combinare] ['nume_clasa'] nume ENDS Cod 3.1

Parametri inclusi in [ ] sunt optionali.Daca sunt prezenti acestia trebuie sa fie in ordinea specificata. Semnificatia parametrilor este : 1. Tip aliniere - specifica la ce limita va fi relocat segmentul in memorie; poate avea una din formele : PARA ( implicit) aliniere la paragraf ( segmentul fizic adica adresa pe 20 de biti va fi relocat la prima adresa obsoluta divizibila prin 16); BYTE fara aliniere (segmentul va fi relocat la umatorul octet liber); WORD - aliniere la cuvant ( segmentul se va reloca la urmatorul octet liber aflat la adresa para); DWORD aliniere la dublu cuvant( segmentul se va reloca la prima adresa divizibila cu 4); PAGE aliniere la pagina ( segmentul se va reloca la prima adresa absoluta divizibila prin 256); Se considera urmatoarele definitii de segmente: DAT1 SEGMEMT BYTE X1 db 7 dup (?) DAT1 ENDS DAT2 SEGMENT WORD x21 dw 300 dup (?) x22 dw ? DAT2 ENDS DAT3 SEGMENT PARA x3 db 5 dup (?) DAT3 ENDS Cod 3.2 Daca prima adresa disponibila este 1000h cele 3 segmente vor fi relocate la urmatoarele adrese fizice : DAT1 : 1000 : 0 - 1000 : 6 DAT2: 1000 : 8 - 1000 : 261 DAT3: 1027 : 0 - 1027 : 4 Adresele de segment se obtin prin trunchierea la primele 4 cifre ale adresei fizice de inceput, iar offset-urile se calculeaza corespunzator. Offset-urile la executie difera in general de offset-urile la asamblare. Offset-ul la asamblare pentru X21 este 0 , care furnireaza deplasamentul unei variabile sau unui etichete in cadrul unui segment, va produce offset-ul de la executie. Instructiunea mov bx, OFFSET X21 va icnarca un bx valoarea 8 .

19

Daca dorim ca offset-ul la asamblare sa coincida cu offset-ul la executie putem folosi tiupl de aliniere PARA ( ultima cifra a adresei fizice de inceput a segmentului este 0). 2. Tip combinare specifica daca si cum se va combina segmentul respectiv cu alte segmente la operatia de link-editare. Poate fi : necombinate ( implicit) nu se scrie nimic; PUBLIC segmentul curent va fi concatenat cu alte segmente cu aceleasi nume si cu atributul PUBLIC COMMA specifica faptul ca segmentul curent si toate segmentele cu aceleasi nume si tipul COMMA se vor suprapune in memorie ( incep la aceiasi adresa fizica).Lungimea unui segment COMMA este cea mai mare lungime a segmentelor componente. STACK - marcheaza segmentul curent ca reprezentand stiva programului. Daca sunt mai multe segmente pe tipul STACK ele vor fi tratate ca PUBLIC; urmatorul exemplu este o definire si o initializare explicita a unui segment de stiva. stiva SEGMENT STACK db 256 dup (?) stiva_sp label WORD

stiva ENDS cod SEGMENT mov ax, stiva mov ss, ax mov sp, OFFSET stiva_sp cod ENDS Cod 3.3 AT EXPRESIE specifica faptul ca segmentul ca fi palsat la o adresa fizica absoluta in memoriel urmatorul exemplu ilustreaza definirea explicita a tabelei de vectori de intreruperi. INT_TABLE SEGMEMT AT 0 dd PROC_NIV_0 dd PROC_NIV_1 INT_TABLE ENDS Cod 3.4 3. NUME CLASA specifica un nume de clasa pentru segment, extinzand astfel numele segmentului. De exemplu daca segmentul are si atributul NUME CLASA, atunci atributele COMMA si PUBLIC vor actiona numai asupra segmentelor cu acelasi nume si acelasi nume de clasa.Ca nume de clase se folosesc de obicei : code , data , stack . Sa consideram doua module asc, asamblate distinct; in primul modul avem urmatoarele definitii de segmente. dseg1 SEGMENT PARA PUBLIC 'data'

20

db 100 dup (?) dseg1 ENDS dseg2 SEGMENT PARA COMMON db 50 dup (?) dseg2 ENDS cseg SEGMENT PARA PUBLIC 'code' db 20 dup (?) cseg ENDS Cod 3.5 In al doilea model exista urmatoarele definitii : dseg1 SEGMENT PARA PUBLIC 'data' db 30 dup (?) dseg1 ENDS dseg2 SEGMENT PARA COMMON db 200 dup (?) dseg2 ENDS cseg SEGMENT PARA PUBLIC 'code' db 70 dup (?) cseg ENDS Cod 3.6 Imaginea segmentelor rezultate in urma link-editarii si a relocarii este cea din figura 3.1

Figura 3.1 Combinarea segmentelor este controlat de directiva SEGMENT

21

Curs 6 28.03.2011 3.1.2 Directiva ASSUME


Directiva ASSUME realizeaza o conexiune simbolica (logica) intre definirea instructiunilor si a datelor, in segmente logice (cuprinse intre SEGMENT si ENDS) la momentul asamblarii si accesul la executie la instructiuni si date prin registrele de segment. Are forma generala : ASSUME reg_seg:expresie, ... ( cod 3.7) unde reg_seg este un registru de segment , iar expresia poate fi : un nume de segment; un nume de grup de segmente; seg nume_segment; nothing. In aceiasi directiva ASSUME se pot asocia mai multe registre de segment, de exemplu : ASSUME CS:CSEG, DS:DSEG1, ES:DSEG2, SS:SSEG Cod 3.8 Directiva ASSUME nu ne scuetste de icnarcarea registrelor de segment cu adresele de segment. Daca un nume de segment nu apare intr-o directiva ASSUME, datele definite in acel segment pot fi accesate numai prin prefixe de segment. Sa consideram urmatorul exemplu : dseg SEGMENT BETA dw 5 dseg ENDS cseg SEGMENT ASSUME cs:cseg, es:dseg mov ax, dseg mov es, ax mov bx, BETA ; se va genera o instructiune MOV, ; cu adresare prin registrul ES ; conform asocierii ES:dseg cseg ENDS Cod 3.9

Daca nu s-ar fi asociat registrul CS cu segmentul dseg prin directiva ASSUME, accesul la variabila BETA trebuia scris in forma : mov sx, es: BETA In formatul intern al instructiunii ( in codificare) trebuie sa apara prin ce registru de segment se calculeaza adresa fizica : daca simbolul care apare intr-o instructiune ( ex. BETA) face parte dintr-un segment care este asociat intr-o directiva ASSUME cu un registru de segment,atunci se va codifica intern accesul prin acel registru de segment ( in cazul de fata prin ES). Codificarea registrului de segment se face: implicit datele sunt accesate in toate modurile de adresare prin registrul DS, cu exceptia celor care implica registrul BP, caz in care se foloseste SS, iar intructiunile sunt adresate intotdeauna prin CS. explicit prin utilizarea premiselor de segment

3.1.3 Directiva GROUP

22

- serveste la gruparea mai multor segmente( inclusiv cu nume si atribute diferite), a caror lungime totala nu depaseste 64 kocteti, sub acelasi nume. Are forma generala : nume_grup GROUP nume_seg1, nume_seg2, ... Cod 3.10 Aceasta directiva reprezinta o alta modalitate de combinare a mai multor segmente, pe langa cea oferita de atributul public. Numele de grup se poate folosi in directive ASSUME, la initializarea unor registre de segment sau la calculul unui offet. Sa consideram urmatorul exemplu :
d1 SEGMENT y dw 20 d1 ENDS d2 SEGMENT x db 2 d2 ENDS data GROUP d1, d2 Cod 3.11

Putem scrie instructiuni de forma :


mov mov mov mov ax, data ds, ax ax, OFFSET x ax, OFFSET data:x

Cod 3.12 , sau directive de forma : ASSUME ds:data (Cod 3.13)


Expresia OFFSET X furnizeaza offset-ul variabiler x in cadrul segmentului d1, iar expresia OFFSET data x produce offset-ul variabilei x in cadrul grupului de segmente dat.

3.2 Definirea simplificata a segmentelor


Avantajul major este faptul ca se respecta acelasi format (structura a programului obiect) ca si la programele dezvoltate in limbaj de nivel inalt. Concret, daca utilizam definirea simplificata se vor genera segmente cu nume si atribute identice de nivel inalt. Toate directivele simplificate incep cu un punct.

3.2.1 Modele de memorie


Directiva pentru specificarea modelului de memorie are forma generala : .model tip , in care tipul poate fi : tiny, small, medium, compact, large sau huge. Semnificatia acestor tipuri este : tiny toate segmentele (date, cod, stiva) se pot genera intr-un spatiu de 64 kocteti si formeaza un singur grup de segmente. Toate salturile, apelurile si definitiile de proceduri sunt implicit de tip NEAR. small datele si stiva sunt grupate intr-un singur segment, iar codul in alt segment. Fiecare dintre acestea nu trebuie sa depaseasca 64 kocteti. Toate salturile si apelurile sunt implicit te tip NEAR. medium datele si stiva sunt grupate intr-un singur segment (cel mult = 64 kocteti) dar codul poate fi in mai multe segmente separate ( nu se grupeaza), deci poate depasi 64 kocteti. Salturile si apelurile sunt implicit de tip NEAR, iar definitiile de proceduri sunt implicit de tip FAR.

23

compact codul generat ocupa cel mult 64 kocteti (se grupeaza), dar datele si stiva sunt segmente separate ( pot depasi 64 kocteti). Apelurile si salturile sunt implicit de tip NEAR. Seutilizeaza adrese complete (segment si offset) atunci cand se acceseaza date definite in alte segmente. large atat datele cat si codul general pot depasi 64 kocteti huge este asemanator cu modelul large dar structurile de date pot depasi 64 kocteti; se utilizeaza adrese complet normalizate in care offset-ul este redus la minim ( in domeniul 0 -15), ceea ce face ca o adresa fizica sa fie descrisa de o unica pereche ( segment, offset). La modelele compact si large, o structura compacta de date ( de tip tablou) nu poate depasi limitele unui segment fizic (64 kocteti); la modelul huge aceasta restrictie dispare. Folosirea directivelor simplificate prezinta si avantajul ca nu mai sunt necesare directive ASSUME : asocierile intre segmente generate si registrele segment sun implicite. Se utilizeaza urmatoarele terminologie: modele de date mici : small , compact ; modele de cod mic : small , medium; modele de date mari : medium, large, huge; modele de cod mare : compact, large, huge.

3.2.2 Directive simplificate de definire a segmentelor


Formele generale ale acestor directive sunt : .stack dimensiune . code[nume] . data .data? ; date neinitializate in limbaj de nivel inalt. .fardata[nume] ; segmente de date utilizate in adrese complete in limbaj de nivel inalt. .fardata?[nume] ; const ; definire de constante in limbaj de nivel inalt

Daca parametrul nume lipseste, se atribuie nume implicite segmentelor generate dupa cum urmeaza: pentru .code i se atribuie automat _TEXT; pentru .data? -> _BSS pentru .data -> DATA pentru .const -> CONST pentru .stack - > STACK pentru .fardata -> _FAR_DATA pentru .fardata? -> _FAR_BSS Se genereaza grupul de segmente DGroup. Aceasta cuprinde : toate segmentele la modelul de date tiny; DATA, _BSS, CONST, STACK in rest ; Se considera ca exista o sirectiva ASSUME implicita (care nu mai trebuie scrisa in textul sursa) de forma : la modelele small si compact :
ASSUME cs:TEXT, ds:DGROUP, ss:DGROUP (cod 3.14)

24

la modelele large si huge :

ASSUME cs:nume_TEXT, ds:DGROUP, ss:DGROUP ; nume este numele din directiva .code ; sau numele fiierului sursa Cod 3.15 la modelul tiny : ASSUME cs:DGROUP, ds:DGROUP, ss:DGROUP

(Cod 3.16)

Daca se folosesc directivele .fardata? si/sau .fardata, atunci segmentele respective trebuie gestionate explicit prin directive ASSUME. Adresele de inceput ale segmentelor si ale grupurilor de segmente definite cu directivele simplificate si disponibile prin simbolurile globale : @data @data? @fardata @fardata? dgroup Daca in acelasi text sursa ( model de cod mare) se folosesc mai multe directive .code cu nume diferite atunci pana la intalnirea unei alte directive de segmente este ca si cum s-ar fi scris o directiva ASSUME CS : cu numele respectiv. Segmentele generate cu numele de clasa : STACK, CODE , DATA , BSS , FAR_BSS , FAR_DATA. Segmentul const are numele de clasa DATA. Tipurile de combinare sunt : PUBLIC (la .code, .data, .data? si .const); STACK la .stack; fara combinare la .fardata si .fardata? Tipul de aliniere este PARA ( pentru .stack, .fardata si .fardata?) si WORD pentru celelalte. Sa consideram fisierul sursa exemplu.asm cu continutul de mai jos :
.model large .data .const .stack 256 .data? .fardata .fardata? .code end Cod 3.17

Fisierul listing generat cuprinde printre altele urmatoarele informatii :


SymbolName Type Value ??DATE Text "06/02/96" ??FILENAME Text "exemplu" ??TIME Text "15:21:50" ??VERSIOM Number 0200 @CODE Text EXEMPLU_TEXT @CODESIZE Text 1 @CPU Text 0101H @CURSEG Text EXEMPLU_TEXT

25

@DATA Text DGROUP @DATASIZE Text 1 @FARDATA Text FAR_DATA @FARDATA? Text FAR_BSS @FILENAME Text EXEMPLU @MODEL Text 5 @WORDSIZE Text 2 Groups & Segments Bit Size Align Combine Class DGROUP Group CONST 16 0000 Word Public DATA STACK 16 0100 Para Stack STACK _BSS 16 0000 Word Public BSS _DATA 16 0000 Word Public DATA EXEMPLU_TEXT 16 0000 Word Public CODE FAR_BSS 16 0000 Para none FAR_BSS FAR_DATA 16 0000 Para none FAR_DATA (Fiier Listing)

Listingul releva o serie de simbolurie predefinite si valorile asociate. Se remarca adresele de inceput ale segmentelor, cel mai important fiind simbolul @data care are aceiasi valoare cu adresa grupului dgroup. Partea a doua a listingului descrie segmentele si grupurile de segmente. Initializarea registrilor DS si CS la inceputul unui program principal se poate face cu simbolul @data sau cu simbolul dgroup. MAcroisntructiunea init_ds_es realizeaza operatia :
mov ax, dgroup mov ds, ax mov es, ax Cod 3.18

Curs 7 04.04.2011

3.3 Directive pentru legarea modulelor


In programul asamblat se compune din mai multe module asamblate separat, este ncesara specificarea simbolurilor care sunt definite intr-un modul si utilizarea in alte module. Acest simbol sub nume de variabile, etichete sau nume de proceduri. In mod normal un simbol este vizibil doar in modul in care este definit (simbol local). Simbolurile care sunt vizibile in mai multe module de program se numesc simboluri globale. Se folosesc urmatoarele notiuni : simboluri publice sunt simboluri ce sunt definite intr-un modul curent de program si folosite(eventual) si in alte module ; aceste simboluri se declara ca simboluri publice in modulul in care sun definite. simboluri externe sunt simboluri care sunt folosite intr-unul din modulele in care nu sunt definite; aceste simboluri se declara ca simboluri externe in modulele in care sunt folosite. Se observa ca un simbol global trebuie declarat ca simbol public in modulul in care este definit si ca simbol extern in modulele in care este folosit, altele decat cel in care ste definit .

26

Declaratia unui simbol ca simbol public si respectiv extern se face cu directivele public si respectiv extern. Directiva public are forma generala :
PUBLIC nume, nume, ... Cod 3.19

Simbolurile declarate ca publice pot fi variabile, etichete, nume de proceduri sau constante numerita simbolice. Directiva extrn are forma generala :
EXTRN nume:tip, nume:tip, ... Cod 3.20

, in care tip precizeaza tipul simbolului. Aceasta poate fi: byte, word, dword sau qword, in cazul in care este o variabila. near sau far in cazul in care simbolul este e eticheta sau un nume de procedura; abs in cazul in care simbolul este o constanta numerica simbolica. Sa consideram doua module de program M1.asm si M2.asm :
; Modul M1.ASM ; .model large extrn var1:word, output:far public var2 .data var2 dw 7 .code start: mov ax, dgroup mov ds, ax add var1, 3 call output end start ; Modul M2.ASM ; .model large public varl, output extrn var2:word .data var 1 dw5 .code output proc far add var2, 1 retf output endp end Cod 3.21

In acest exemplu accesul la simbolurile globale este facilitat de faptul ca atat var1 cat si var2 sunt in acelasi segment de date fiind accesibile prin registre DS, initializate cu grupul de segmente dgroup. Daca nu am fi folosit directive simplificate accesul la var1 si var2 ar fi fost mai complicat deoarece nu s-ar fi cunoscut segmentul in care acestea sunt definite. In asemenea situatii se foloseste operatorul seg care produce adresa de segment a simbolului :
mov ax, SEG var1 mov es, ax

27

add es:var1, 3 Cod 3.22

Directiva END
Aceasta directiva marcheaza sfarsitul logic al unui modul de program si este obligatorie in toate modulele. Tot ce se gaseste in fisierul sursa dupa aceasta directiva este ignorat la asamblare. Forma generala este :
END [punct_de_start] Cod 3.23

, in care punct_de_start este o eticheta sau un nume de procedura care marcheaza punctul in care se va da controlul dupa incarcarea programului in memorie.

3.4 Contoare de locatii si directiva ORG


Contoarele de locatii controleaza procesul de asamblare, aratand la ce offset in cadrul segmentului curent se vor asambla instructiuni ale datelor urmatoare. Un contor de locatii poate si accesat explicit prin simbolul $. La prima utilizare a unui nume de segment contorul de locatii este initializat cu 0. Daca se revine intr-un segment care a mai fost utilizat, contorul de locatii revine la ultima valoare, utilizata in cadrul aceluiasi segment ca in exemplul urmator :
.data db 5 dup(?) .code ;$=0 .data db 7 ;$=5 Cod 3.24 ;$=0 ;$=5

Contoarele de locatii sunt utile la calculul automat al unor deplasamente sau dimensiuni. In exemplul urmator se defineste tabloul de cuvinte TAB si o variabila LNG care contine numarul de cuvinte din tablou:
TAB dw 1, 2, 3, 4, 5, 6, 7, 8, 9 LNG dw ($ - TAB)/2 Cod 3.25

Expresia ($-TAB) reprezinta numarul de octeti de la adresa TAB pana la adresa curenta. Impartind acest numar la 2 se deduce numarul de elemente din tablou. Putem acum adauga sau diminua date din tabloul TAB, fara a actualiza lungimea LNG : ansamblorul va calcula corect numarul de elemente dint ablou. Alte exemple de utilizate pot fi :
JMP $ JMP $ + 5 ; Ciclu infinit: $ este chiar adresa ; instructiunii JMP ; salt relativ Cod 3.26

Directiva ORG Aceasta directiva modifica explicit contorul de locatii curent, avand forma generala:
ORG expresie

28

Exemplu :
ORG $ + 5 ORG 100H ; Sare 5 octeti la asamblare ; Asambleaza la offset-ul absolut 100H Cod 3.28

3.5 Definirea si initializarea datelor


Asamblorul recunoaste 3 categorii sintactice de baza: - constante - variabile - etichete ( inclusiv nume de proceduri) Constantele pot fi absolute( numerice) sau simbolice. Constantele simbolice reprezinta nume generice asociate unor valori numerice. Variabilele identifica datele ( un spatiu de memorie rezervat), iar etichetele identifica codul ( program sau procedura). Instructiuni de tipul MOV, ADC, ENT, etc, folosesc variabile si constante, iar instructiunile jmp si call folosesc etichete. Variabilele si etichetele au asociate atribute cum ar fi segmentul in care sunt definite, offset-ul la care sunt definite in intervalul segmentului, etc.

3.5.1 Constante
Constantele numerice pot fi : constante binare se utilizeaza sufixul B sau b. Constante octale se utlizeaza sufixele O,Q,o sau q; constantele zecimale fara sufix sau cu sufixele T si t; constante hexazecimale se utilizeaza sufixele H sau h si prefixul 0 daca prima cifra este >9; pentru cifrele peste 9 se utilizeaza simbolurile A pana la F sau a....f; constante ASCII se scriu unul sau mai multe caractere ASCII intre sau . Cateva exemple de constante absolute : 123, 123D, 10001100B, 177q, oAAH, 3fh, a, AB. Constantele simbolice se definesc cu directiva EQU, in forma generala :
nume EQU expresie Cod 3.29

De exemplu liniile de program :


CR EQU 0DH LF EQU 0AH Cod 3.30 , definesc constantele simbolice CR si LF cu valorile 0DH si 0AH.

Putem folosi aceste constante simbolice in orice context in care este permisa folosirea unei constante numerice..

3.5.2 Definirea si utilizarea variabilelor


Pentru definirea variabilelor se utilizeaza directiva db,dw,dd,dq sau dt. Forma generala a unei definiti de date este :
nume directiva lista_de_valori Cod 3.31

29

, in care nume este identificatorul asociat definitiei respective, iar lista_de_valori este lista valorilor initiale care poate cuprinde: - constante numerice ( absolute sau simbolice) - simbolul ? - o adresa, adica un nume de variabila sau de eticheta; de foloseste la dw si dd - un sir ASCII - operatorul dup(expresie), in care expresie poate fi :constanta numerica, liste de valori , simbolul ? , operatorul dup ; Semnificatia simbolului ? este locatia neinitializata iar cea a operatorului dup este repetarea de un numar de ori a expresiei din paranteza. Se considera definitia urmatoare:
var_a var_b adr_n adr_f db 2 dup (0, 3 dup (1)) db 1, 2, 3, ?, ?, ? dw var_a dd var_b Cod 3.32

Prima definitie este echivalenta cu :


var_a db 0, 1, 1, 1, 0, 1, 1, 1 Cod 3.33

Atributele datelor definite sut : - segment cel curent - offset cel curent - tip 1,2,4,8,10, dupa cum s-a utilizat ca directiva de baza db,dw,dd,dq sau dt. Variabilele pot fi utilizate ca: - variabile simple : var_a, var_b; - variabile indexate : var_a[bx], var_b[2], ALFA[si][bx]. In cazul variabilelor indexate trebuie tinut seara de tipul variabilei de baza. De exemplu in urma definitiei :
B dw 10 dup(?) Cod 3.34

, exemplele indexate corecte din punct de vedere logic, care acceseaza elementele din B sunt B[0], B[2], etc. Din punct de vedere sintactic putem scrie si :
mov ax, B[1] Cod 3.35

Dar aceasta forma va incarca in AL partea high a primului cuvant din tablou si in AH partea low a celui de-al doilea cuvant din tabloul B. In cazul accesarii variabilelor prin expresii anonime poate aparea necesitatea operatorului ptr. Instructiunile :
lea bx, B inc byte ptr [bx][4] inc word ptr [bx][4] Cod 3.36

, incrementeaza octetul respectiv cuvantul de la adresa BX+4.

30

3.6 Definirea etichetelor . Directiva label


Etichetele sunt folosite pentru specificarea punctelor tinta la instructiunile sau sau apel sau pentru o specificarea alternativa a datelor. in ambele cazuri numere etichetei devine un nume simbolic adsociat adresei curente de memorie. Atributele etichetelor sunt : Segment, offset si tip. Pana acum am intalnit doua modalitati de definire a etichetelor : - prin nume urmat de caractere : se defineste o eticheta de tip near; - prin directiva proc numele procedurii este interpretat ca o eticheta a tipului derivat din tipul procedurii; O alta posibilitate este directiva Label care are forma generala :
nume LABEL tip Cod 3.37

Daca ceea ce urmeaza reprezinta instructiuni sau tipul etichetei va fi de regula near sau fac si eticheta va fi folosita ca punct tinta in instructiuni de tip jmp/call. Daca ceea ce urmeaza reprezinta definitia de date, tipul etichetei va fi de regula byte,word, dword, etc. Atributele near sau fac pot aparea numai daca eticehta este definita intr-un segment asociat cu registrul CS printr-o directiva assume (explicita sau implicita) Directiva Label este utila atunci cand dorim sa accesam variabilele in moduri diferite , de exeplu in urma definitiei :
ALFAB label ALFAW dw BYTE 1234H Cod 3.38

, o instructiune de forma inc Alfa B va incrementa la octetul mai putin semnificativ al cuvantului, iar una de tip inc alfa W va incrementa intreg cuvantul; un efect similar se poate obtine prin operatorul ptr. Similar definitia :
adr_proc label dword proc_off dw ? proc_seg dw ? Cod 3.39

, permite definirea explicita a segmentului si a offset- ului , dar si accesul la nivel de dublu cuvant, de exemplu intr-o instructiune de ael indirect intersegment.

Curs 8 11.04.2011

3.7Definirea structurilor.Operatii specifice


Structurile sunt proiectii de date ( campuri sau membri) plasate succesiv in memorie, grupate sub un unic element sintactic.Dimentiunea unei structuri este suma dimensiunilor campurilor componente. Forma grupata a definitiei unei structuri este :
nume_structura STRUC nume_membru definitie_date

31

nume_structura ENDS Cod 3.40

Prin aceasta se defineste forma structurii (sablonul) fara a rezerva spatiu in memorie. Definitii de date pot cuprinde directiva db,dw,etc cu valori initiale asociate, ?,dup,etc, exact ca orice definitie chiar daca apartin unor structuri distincte. exemplu de definitie de tip structura :
ALFA STRUC a db ? b dw 1111H c dd 1234 d db ? ALFA ENDS Cod 3.41

O structura definita este interpretata ca un tip nou de date, care poate apoi participa la definitii concrete de date cu rezervare de spatiu de memorie. De exemplu putem defini o structura de tipul cu numele x:
x ALFA <, , 777, 5> Cod 3.42

, in care este tipul de date , x este numele variabilei iar intre < > se trec valorile initiale ale campurilor structurii x. Prezenta virgulelor din lista de valori initiale, precizeaza ca primii 2 membri sunt initializati cu valorile implicite de la definitia tipului , al treilea membru este initializat cu valoarea 777, iar al patrulea cu valoarea 5. Astfel definitia variabilei x este echivalenta cu secventa de definitie:
a db ? b dw 1111H c dd 777 d db 5 Cod 3.43

Principalul avantaj al structurilor este accesul la membrii intr-o forma asemanatoare limbajelor de nivel inalt. De exemplu pentru a incarca in SI campul b al structurii x, putem scrie :
mov si, x.b Cod 3.44

, accesul la membrii structurii x poate fi detaliat: o x.a variabilei de tip byte; o x.b variabilei de tip word; o x.c variabilei de tip dword; o x.d variabilei de tip byte; Putem defini 5 structuri de tip :
y ALFA 5 dup <, , , 10> Cod 3.45

, in care primii 3 membri sunt initializati cu valorile de la definitia tipului structurii , iar al patrulea cu valoarea 10. Acum au sens expresii de forma: y[0].a , y[si], y[8.c], etc. De fapt toate aceste expresii se evalueaza din adresa de inceput a variabilei y la care se adauga un deplasament corespunzator. Se observa ca gestiunea deplasamentelor cade in sarcina utilizatorului. daca dorim sa accesam campul c a celei de-a doua structurii din tabloul y, nu putem scrie y[1].c asa cum am scrie intr-un limbaj de nivel inalt , ci y[0].c. Limbajul de asamblare ne

32

pune la dispozitie operatorul TYPE, care intoarce numarul de octeti ocupat de o structura. Pentru a generaliza accesul la al- i lea element al tabloului y , (i= 0,4) putem scrie: y[i * TYPE ALFA].c . Problema se complica daca indicile i este cunoscut de-abia la momentul executiei ( de exemplu fiind memorat intr-un registru). O expresie de forma :
mov a1, y[SI*TYPE ALFA].d Cod 3.46

, are sens numai la procesoarele care accepta adresare cu factor de scara ( 80386 si epste) si numai daca factorul de scara este 1,2, 4 sau 8. In caz contrar deplasamentul trebuie calculat explicit prin operatii aritmetice. Cu toate aceste limitari, structurile sunt intens utilizate atunci cand se lucreaza cu anumite sabloane intr-o procedura sau tyransmiterea prin referinta a unei zone de date. Sa consideram o inregistrare logica descrisa prin campuri: o campul NUME, sir ASCII de 30 de caractere; o campul PRENUME, sir ASCII de 20 de caractere o campul COD, intreg pe 4 octeti. Dorim sa transmitem unei proceduri FAR cu nume de prelucare cu asemenea inregistrare. Cel mai simplu mod este de a transmite adresa ( near sau far) a zonei de memorie in care este stocata inregistrarea, de exemplu printr-un registru sau o pereche de registre; pentru accesul comod la campuri definim structura :
PERSOANA STRUC NUME db 30 dup (?) PRENUME db 20 dup (?) COD dd ? PERSOANA ENDS Cod 3.47

Definitia concreta a datelor si secventa de apel a procedurii este :


.data om PERSOANA <'Ionescu', 'Ion', 77206> adr_om dd om ; Pointer la om .code les di, adr_om call PRELUCRARE Cod 3.48

Se pune problema accesului la campurile inregistrarii prin intermediul procedurii. Beneficiem acum de structura persoana. Ca sa incarcam adresa campului prenume vom scrie :
lea bx, es:[di].PRENUME Cod 3.49

Perechea es:di contine adresa structurii om iar expresia es[du].PRENUME reprezinta deplasamentul campului prenume. In acest moment in es:bx avem adresa sirului de caractere de tip prenume similar se procedeaza si prin celelalte campuri: ca sa preluam din dx:ax campul cod putem scrie:
mov ax, word ptr es:[di].COD mov dx, word ptr es:[di].COD + 2 Cod 3.50

Este evident ca toate secventele de mai sus se puteau inlocui cu deplasamente calculate explicit de catre programator. Incarcarea campului cod ar fi putut fi scrisa:
mov ax, word ptr es:[di + 50]

33

mov dx, word ptr es:[di + 52] Cod 3.51

, dar forma cu numele de campuri este mult mai clara si mai comoda. In plus mai putem gresi ca calculul unui deplasament, dar asamblorul nu. Aceasta tehnica este benefica si din punct de vedere al intretinerii unui program.Daca se modifica anterior inregistrarea PERSOANA si se adauga inca un camp intre PRENUME si COD, toate deplasamentele calculate explicit trebuie modificate. In varianta cu structura trebuie doar sa schimbam definitia structurii restul fiind facut automat la asamblare.

3.8 Definirea inregistrarilor. Operatii specifice


Inregistrarile (record) corespund de fapt, unor structuri de validare din limbajele de nivel inalt. Concret o inregistrare este o definitie de campuri de biti de lungime maxima 8 sau 16. Din punct de vedere sintactic definitia unei inregistrari este similara cu cea a unei structuri, forma generala fiind:
nume_inregistrare RECORD nume_camp:valoare, ... Cod 3.52

, sau cu initializarea implicita:


nume RECORD nume_camp:valoare = expresie, ... Cod 3.53

Valorle care apar asociate cu numele de campuri dau de fapt, numarul de biti pe care se memoreaza campul respectiv. In varianta cu initializare, expresia ce apare dupa egal ( =) se evalueaza la o cantitate care se reprezinta pe numarul de biti asociat campului respectiv. La fel ca la structuri, numele campurilor trebuie sa fie distincte chiar daca apartin unor intregistrari diferite. Sa consideram un exemplu :
BETA record X:7, Y:4, Z:5 Cod 3.54

, prin care se defineste un sablon pe 16 biti grupati in campurile x,y si z

Figura 3.2 Definiia unei nregistrri

La fel ca la structuri putem defini variabile de tipul intregistrarii de date:


VAL BETA <5, 2, 7> Cod 3.55

, in care valorile dintre < > initializeaza cele 3 campuri de biti. Se observa ca aceasta definitie este echivalenta cu definitia explicita:
VAL dw 0000101001000111B Cod 3.56

Exista 2 operatori specifici inregistrarilor: MASK si WIDTH. Operatorul MASK primeste un nume de camp si furnizeaza o masca cu bitii 1 pe pozitia campului respectiv si 0 in rest. Astfel expresiile MASK x si MASK y sunt echivalente cu constantele binare : 1111111000000000B si 0000000111100000B

34

Asemenea expresii pot fi utilizate pentru selectarea campurilor respective ca in exemplele de mai jos :
AND AX, MASK Y ; Filtreaza campul Y AND BX, NOT MASK Z ; Forteaza campul Z la 0 Cod 3.57

Operatorul WIDTH primeste un nume de inregistrare, sau un nume de camp dintr-o intregistrare intorcand numarul de biti ai inregistrarii sau ai campului respectiv. De exemplu secventa:
MOV AL, WIDTH BETA ; AL <--- 16 MOV BL, WIDTH Y ; BL <--- 4 Cod 3.58

, va incerca in AL valoarea 16 si un BL valoarea 4. Daca se utilizeaza un nume de camp intr-o instructiune de tip MOV, se va incarca un contor de deplasare util pentru a deplasa campul respectiv pe pozitiile cel mai putin semnificative. Sa presupunem ca dorim sa testam valoarea numerica a campului Y din inregistrarea ALFA. Nu este suficient sa-l izolam si sa folosim o instructiune de comparatie. Inainte de comparatie,campul y trebuie adus pe pozitiile cele mai din dreapta. Realizam aceste operatii prin secventa :
MOV AX, VAL AND AX, MASK Y MOV CL, WIDTH Y SHR AX, CL ; Preluare inregistrare ; Selectare camp Y ; Incarcare in CL a valorii 4 ; Deplasare camp Y la dreapta Cod 3.59

3.9 Operatori in limbajul de asamblare


Limbajul de asamblare dispune de un set de operatori cu care se pot forma expresii aritmetice si logice, aceste expresii sunt evaluate la momentul asamblarii, producand de fapt constante numerice. Este esential sa deosebim instructiunile executabile ( codul masina) de operatiile care se fac in momentul asamblarii.

3.9.1 Operatori aritmetici si logici


Operatorii aritmetici sunt : + , - , * , / , MOD, SHL si SHR. Primii 4 au semnificatii evidente si opereaza numai cu cantitati intregi. Operatorul MOD produce restul la impartire, iar SHL si SHR provoaca deplasare la stanga sau la dreapta. De exemplu instructiunea :
mov ax, 1 SHL 3 ; 1 deplasat la stanga cu 3 biti Cod 3.60

, este echivalenta cu instructiunea:


mov ax, 100B Cod 3.61

Similar in directiva :
COUNT dw ($ - TAB)/2 Cod 3.62

,se va evalua la momentul asamblarii expresia ($ - TAB) /2, adica diferenta intre contorul curent de locatii si adresa TAB, impartita la 2. Operatorii logici sunt :NOT, AND, OR, XOR cu semnificatii evidente. Toti acesti operatori accepta drept operanzi constante intregi; opertiile respective se fac la nivel de bit. Ei nu trebuie confundati cu intructiunile executabile cu acelsi nume. In instructiunea:

35

and al, (1 SHL 3 ) OR (1 SHL 5) Cod 3.63

,registrul ALU va fi incarcat cu constanta 101000B.

3.9.2 Operatori relationali


Operatorii relationali sunt: eq, ne, lt, le, gt, ge cu semnificatii evidente.Acestea intorc valori logice codificate ca 0 sau ca secvente de 1 pe un numar corespunzator de biti. In urma definitiilor:
x db 1 EQ 2 y dw 1 NE 2 z dd 1 LT 2 Cod 3.64

,variabilele x,y si z vor fi initializate cu constantele 0, 0FFFFH respectiv 0FFFFFFFFH. Operatorii relationali sunt utilizati in special in directivele de asamblare conditional.

3.9.3 Operatorul de atribuite =


Acest operatorul defineste constante simbolice, fiind similar cu directiva EQU, dar permite redefinirea simbolurilor utilizate. O definitie de forma :
N EQU 1 N EQU 2 Cod 3.65

, este semnalata ca eroare, dar secventa:


N=1 N=2 Cod 3.66

,este corecta. Acest operator este utilizat in special in definitiile de macroinstructiuni.

3.9.4 Operatori care intorc valori


Acesti operatori se aplica unor entitati ale programului in limbaj de asamblare( variabile, etichete), intorcand valori asociate acestora: operatorul SEG se aplica atat variabilelor cat si etichetelor si furnizeaza adresa de segment asociata variabilei respective. Daca var este o variabila, atunci putem scrie secventa :
mov ax, SEG var mov ds, ax Cod 3.67

operatorul OFFSET este siminal cu SEG furnizand OFFSET-ul asociat variabilei sau etichetei :
mov bx, OFFSET var Cod 3.68

operatorul THIS acest operator creaza un operand care are asociata o adresa de segment si un offset identice cu contorul curent de locatii. Forma generala a operandului este:
THIS tip Cod 3.69

, in care tip poate fi byte, word, dw, qw sau tbyte, pentru definitii de date, respectiv near sau fac pentru etichete. Operatorul THIS se utilizeaza de obicei cu directiva EQU. De exemplu definitia constantei simbolice :

36

ALFA EQU THIS WORD Cod 3.70

, este echivalenta cu :
ALFA LABEL WORD Cod 3.71

Curs 9 18.04.2011
operatorul TYPE se aplica variabilelor si etichetelor intorcand tipul acostora. Pentru variabile intoarce valorile 1,2,4,8 sau 10, pentru variabilele simplu ( definite cu directivele db,dw,dd,dq respectiv dt), iar pentru structuri intoarce numarul de octeti pe care este memorata structurarespectiva. Pentru etichete intoarce tipul etichetei ( near sau far). operatorul Length se aplica numai variabilelor se intoarce numarul de elemente finite din variabila respectiva. De exemplu in definitia :
A DW 100 dup (?) Cod 3.72 ,expresia Length A are valoarea 100

operatorul SIZE - se aplica doar variabilelor si intoarce dimensiunea in octeti a variabilei respective. In definitia de mai sus expresia size A are valoarea 200. Pentru o variabila oarecare para , are lor intotdeauna identitadea:
SIZE var = (LENGTH var) * (TYPE var) Cod 3.73

Acesti operatori sunt utili la prelucrarea tablourilor. Secventa urmatoare nu depinde de tipul de caza al tabloului TAB si nici de dimensiunea sa:
.data TAB dd 100 dup (?) .code mov cx, LENGTH TAB lea si, TAB bucla: .... add si, TYPE TAB loop bucla Cod 3.74

Daca inlocuim tipul de baza al tabloului TAB cu o structura de tip persoana( definita in 3.7) modificand si dimensiunea:
PERSOANA STRUC ..... PERSOANA ENDS .data TAB PERSOANA 50 dup <,,,> Cod 3.75

Partea de program nu trebuie modificata , pentru ca asamblorul va evalua corect expresiile Length TAB si TYPE TAB.

3.9.5 Operatorul PTR


Acest operator se aplica atat variabilelor cat si etichetelor avand ca efect schimbarea tipului variabilei sau a atichetei respective. Este obligatoriu in cazul in care se folosesc referinte anonime la memorie, din care nu se poate deduce tipul operandului:

37

add word ptr [bx], 2 call dword ptr [bx] call near ptr proc Cod 3.76

3.10 Directive de asamblare conditionata


Permit ignorarea unor portiuni din textul sursa, functie de o conditie ce se poate evalua la asamblare. Directiva de baza este IF cu forma generala:
IF expresia [ELSE] ENDIF Cod 3.77

Daca expresia din directiva IF este adevarata ( diferita de 0) se asambleaza portiunea de program dintre IF si ELSE si se ognora portiunea dintre ELSe si ENDIF. Daca expresia din IF este falsa se asambleaza portiunea dintre ELSE si ENDIFsi se ignora portiunea dintre IF si ELSE. Ramura ELSE este optionala. Aceste operatii se petrec la momentul asamblarii permitand intretinerea comoda a unui program de dimensiuni mari sau chiar mentinerea in acelasi text sursa a mai multor variante de program executate. Sa presupunem ca dorim un program care sa poate fi configurat rapid pentru modelele date mici respectiv mari.Aceasta presupune ca oricare secventa de instructiuni ce defineste , citeste sau scrie o adresa sa fie inclusa in directive de asamblare conditionata :
FALSE equ 0 TRUE equ NOT FALSE DATE_MARI equ TRUE DATE_MICI equ NOT DATE_MARI .data X dw 100 dup (?) IF DATE_MARI ADR_X dd X ELSE ADR_X dw X ENDIF .code IF DATE_MARI lds si, ADR_X ELSE mov si, ADR_X ENDIF ; ; Prelucrare TABLOU ; Cod 3.78

Exista si directivele IFDEF /ENDIF si IFNDEF/ENDIF, care testeaza daca un simbol este definit sau nu si directivele IFB/ENDIF ( IF Blank), respectiv IFNB/ENDIF (IF

38

Not Blank), care testeaza daca un simbol este vid sau nevid. Aceastea din urma pot fi utilizate la definirea macroinstructiunilor. In expresiile ce apar in directivele de tip IF se utilizeaza de obicei operatori logici si operationali. Sa consideram de exemplu un program sursa multifunctional. Se doreste scrierea unei secvente care sa calculeze in acumulator suma elementelor unui tablou A ( de octeti sau de cuvinte) definit in segmentul curent de date ca suma pe octeti si pe cuvinte, indiferent de tipul si dimensiunea tabloului. Tipul sumei este dictat de constantele simbolice SUM_B si SUM_W:
FALSE equ 0 TRUE equ NOT FALSE SUM_B equ TRUE SUM_W egu NOT SUM_B .code if SUM_B mov cx, SIZE A ; Numar de iteratii else mov cx, (SIZE A)/2 endif xor bx, bx ; Indice initial mov ax, bx ; Suma initiala bucla: if SUM_B add al, byte ptr A [bx] ; Suma pe octet inc bx ; Actualizare adresa else add ax, word ptr A [bx] ; Suma pe cuvant inc bx ; Actualizare adresa inc bx endif loop bucla ; Bucla if SUM_W AND (TYPE A EQ 1) AND ((SIZE A) MOD 2) EQ 1 push ax mov al, byte ptr A [bx] ; Un eventual cbw ; ultim mov dx, ax ; octet pop ax add ax, dx endif Cod 3.79

Se observa ca nu putem initializa contorul cx cu expresia Length A, deoarece numarul de iteratii este dictat de modul de calcul al sumei si nu de tipul tabloului. Ca atare luam dimensiunea in octeti a tabloului pe care o impartim la 2 in cazul sumei de cuvant. Calculul sumei si actualizarea adresei sunt evidente. Apare o problema speciala din urmatoarea situatie: se cere suma pe cuvant iar tabloul definit ca tablou de octeti au un numar impar de elemente. In aceasta situatie este evident ca ultimul octet nu este considerat in bucla de sumare. Ca atare el este adaugat la sfarsit. De remarcat formularea situtatiei de mai sus in termenii conditiei logice de la ultima directiva IF: SUM_W codifica cererea de calcul a simei la nivelul de cuvant. (TYPE A EQ 1) codifica situatia in care tabloul A este definit la nivel de octet.

39

( (SIZE A) MOD 2) codifica situatie in care tabloul are numar de octeti.

Curs 10 02.05.2011

CAPITOLUL IV Macroinstructiunea
4.1 Scopul macroinstructiunii. Definire si expandare
Macroinstructiunile permit programatorului sa defineasca simbolic secvente de program( instructiuni, definitii de date , directive, etc) asociate cu un nume. Folosind numele macroinstructiunii in program se va genera intreaga secventa de program. In esenta este vorba de un proces de substitutie (expandarea) in textul programului . Un asamblor care dispune de macroinstructiuni se numeste macroasamblor. Sunt doua etape de lucru cu macroinstructiuni: 1. Definirea macroinstructiunii 2. Utilizarea macroinstructiunii. Utilizarea se mai numeste invocare sau chiar apel de macroinstructiune, dar ultima denumire poate produce confuzie, termenul utilizanduse in cadrul procedurilor. Spre deosebire de proceduri , macroinstructiunile sunt expandate la fiecare utilizare, deci programul nu se micsoreaza. Avantajul este ca textul sursa scris de programator sdevine mai clar si mai scurt. MAcroinstructiunile pot fi cu parametri sau fara.Din punct de vedere sintactic, ele sunt asemanatoare cu directivele de top definire din limbajul de nivel inalt, dispunand in general de mecanisme mai evoluate decat acestea. Definitia unei macroinstructiuni fara parametri se face in forma generala:
nume_macro MACRO ; ; Corp macroinstructiune ; ENDM Cod 3.80

Invocarea consta in scrierea in textul sursa a numelui macroinstructiunii. Macroinstructiunea init_ds_es este definita in fisierul IO.h :
init_ds_es macro mov ax, DGROUP mov ds, ax mov es, ax endm Cod 3.81

Instructiunea exit_dos este definita prin :


exit_dos macro mov ax, 4C00H int 21H endm Cod 3.82

O pereche de macroinstructiuni care salveaza si refac registrele generale poate fi conceputa astfel :
save macro rest macro

40

push ax push bx push cx push dx push si push di endm

pop di pop si pop dx pop cx pop bx pop ax endm Cod 3.83

Putem utiliza aceste macroinstructiuni la intrarea si la iesirea dintr-o procedura:


PROCEDURA proc near save rest ret PROCEDURA endp Cod 3.84

Din punct de vedere simbolic este ca si cum setul de instructiuni al masinii ar fi fost extins cu doua noi instructiuni : save si rest.

4.2 Macroinstructiuni cu parametri


Macroinstructinile importante sunt cele cu parametri. Definitia unei macroinstructiuni cu parametri are forma generala:
nume_macro MACRO P1, P2, ..., Pn ; ; Corp macroinstructiune ; ENDM Cod 3.85

,in care p1,p2,...pn sunt identificatori ce specifica parametri formali. Apelul (invocarea) unei macroinstructiuni cu parametri se face prin speficicarea numelui urmata de o lista de parametri actuali:
nume_macro X1, X2, ..., Xn Cod 3.86

La expandarea macroinstructiunilor pe langa expandarea propriuzisa se va inlocui fiecare parametru formal cu parametrul actual respectiv. Sa consideram cateva exemple. Apelurile de functii DOS presupun numarul finctiei in registrul ah. Putem deci defini o macroinstructiune de forma :
dosint macro N mov ah, N int 21H endm Cod 3.87

si putem invoca instructiunea prin linii de forma:


dosint 2 Cod 3.88

Similar pentru deschiderea unui fisier pentru citire ( operatii realizate prin functia DOS 3DH), putem scrie o macroinstructiune de forma:
o_read macro fname, hand mov al, 0C0H lea dx, fname

41

dosint mov endm

3DH hand, ax Cod 3.89

, in care fname contine numele fisierului, iar hand este o variabila de tip word in care se depude un indicator catre fisierul deschis. Parametrul 0C0H codifica modul de acces. Se observa utilizarea macroinstructiunii dosint in definitia lui o_read. Citirea din fisier poate di codificata intr-o macroinstructiune de forma:
f_read macro hand, buf, nr mov bx, hand mov cx, nr lea dx, buf dosint 3FH endm Cod 3.90

, in care hand este indicatorul catre fisierul deschis anterios, nr este numarul de octeti care se citeste, iar buf este adresa unei zone de memorie in care se vor depunde datele citite. Inchiderea unui fisier deschis se poate face cu o macroinstructiune de forma :
f_close macro hand mov bx, hand dosint 3EH endm Cod 3.91

Macroinstructiunile de mai sus sunt definite in fisierul IO.H.Ne propunem sa scriem un program executabil care sa afiseze la consola un fisier text. Beneficiem de macroinstructiunile definite in fisierul IO.H:
.model large include io.h .stack 1024 .data file_name db 30 dup (0) ; Spatiu nume fisier hand dw 7 ; Spatiu handler buf db 1024 dup (?); Buffer citire .code start: init_ds_es putsi <'Nume fisier: '> ; Mesaj gets file_name ; Citire nume o_read file_name, hand ; Deschidere jc eroare ; Eroare deschidere ? bucla: f_read hand, buf, 1024 ; Citire 1024 octeti jc eroare ; Eroare citire mov si, ax ; AX = cati octeti s-au mov byte ptr buf [si], 0 ; citit de fapt puts buf ; Afisare la consola cmp ax, 1024 ; S-au citit mai putin jb gata ; de 1024 ? jmp bucla ; Nu, reluare gata: f_close hand ; Inchidere jmp iesire ; Salt la iesire eroare: ; Mesaj de

42

putsi <'Eroare fisier'> ; eroare iesire: exit_dos ; Iesire n DOS end start

Cod 3.92

In zona de date se rezerva spatiul pentru numele fisierului pentru indicator (hand) si pentru un buffer de citire de 1024 de octeti. Se reaminteste ca operatiile cu periferice sunt in esenta transferuri intre periferice si memorie. Programul afiseaza un mesaj la consola dupa care citeste numele fisierului. Se face apoi opratia de deschidere a fisierului specificat. Toate functiile dos de lucru cu fisiere intorc CF=1 in caz de eroare. O eroare tipica la operatia de deschidere pentru citire este un nume eronat de fisier. Se testeaza deci CF si in caz de eroare se afiseaza un mesaj adecvat si se iese in dos. Se trece acum la o bucla de citire afisare. Functia de citire intoarce in AX numarul de octeti efectiv citiri( care este mai mic sau egal cu cel cerut). Dorim sa afisam numai ce s-a citit efectiv, asa ca punem terminatorul 0 in buffer dupa ultimul octet citit. Este posibil ca la ultima iteratie fisierul sa citeasca 0 octeti. Se afiseaza la consola buffer-ul respectiv ( cu macroinstructiunea PBTS). Daca numarul de octeti respectivi cititi este mai mic strict decar cel cerut(1024) inseamna ca s-a ajuns la sfarsitul fisierului si bucla se termina. In caz contrat se reia o noua citire din fisier. In final se include fisierul si se iese din dos. Acest exemplu ilustreaza foarte bine avantajele macroinstructiunilor. O actiune destul de laborioasa in limbaj de asamblare ( afisare fisier text) a putut fi codificata prin cateva linii de program sursa ( e drept ca toate sunt invocari de macroinstructiuni). Daca reusim sa concepem un set de macroinstructiuni, adecvat unei probleme (in cazul de fata interfata cu sistemul dos) scrierea unui program devine foarte comoda. In cazul scrieii unui program similat care sa realizeze copierea unui fisier disc in alt fisier se pot utiliza macroinstructiunile:
o_write macro fname, hand mov al, 0C1H lea dx, fname dosint 3DH mov hand, ax endm f_write macro hand, buf, nr mov bx, hand mov cx, nr lea dx, buf dosint 40H endm Cod 3.93

, care deschid un fisier pentru scriere respectiv scriu un fisier. Parametri sunt asemanatori cu cei din macroinstructiunile o-read si f-read. Bucla de citire din fisierafisare sin exemplul anterior se inlocuieste cu o bucla de citire din fisier srusa-scriere in fisier destinatie. In unele situatii substitutia parametrilor formali cu cei actuali poate ridica unele probleme. Sa presupunem ca un programator care invata in limbajul asm nu a ajuns inca la instructiunea xchg, ci are cunostinta doar de instructiunile push, pop si mov. El isi propune sa scrie o macroisntructiune, care sa interschimbe doua cantitati de 16 biti:
trans macro X, Y push ax push bx mov bx, X mov ax, Y mov X, ax

43

mov Y, bx pop bx pop ax endm trans AX, SI

Cod 3.94 ; Interschimba AX cu SI (oare ?) Cod 3.95

Aparent totul este in ordine. Totusi pot aparea situatii nedorite ca in secventa: Aceasta invocare de macroinstructiune se expandeaza in :
push ax push bx mov bx, AX mov ax, SI mov AX, ax mov SI, bx pop bx pop ax Cod 3.96

si evident ca registrul AX nu se modifica. Se poate si mai rau ca in secventa:


trans SP, DI ; Interschimba SP cu DI (oare ?) Cod 3.97

, care se expandeaza in :
push ax push bx mov bx, SP mov ax, DI mov SP, ax mov DI, bx pop bx pop ax

; Aici se modifica SP ; si POP-urile ; sunt ; compromise Cod 3.98

Pericolele apar daca in situatiile in care parametri actuali intra in conflict cu anume variabile sau registre care sunt folosite in interiosriile macroinstructiunilor. Aceste situatii trebuie ghidate . Utilizarea foarte mare a macroinstructiunilor devine evidenta la secventele de apel ale procedurilor cu parametri ( ina cest caz se vorbeste despre macroinstructiuni cu apel). apelurile de functii sistem codificate anterior sunt cazuri particulare de macroinstructiuni de apel. Procedurile cu paraetri utilizeaza diverse tehnici de transmitere a parametrilor, parametri trebuie plasati in anumite registre sau in stiva, intro ordine specificata. Aceste detalii de apel sunt greu de tinut minte si nici nu intereseaza pe cel care apeleaza procedura. Putem insa dezvolta macroinstructiuni, care sa ascunda aceste detalii. Sa consideram o procedura near cu numele puts_prog care afiseaza un sir de caractere ( terminal cu 0). Adresa sirului ( offset-ul in cadrul segmentului curent adresat prin ds) se specifica in registrul si. O macroinstructiune de apel se poate scrie in forma:
puts macro X push si lea si, X call puts_proc pop si endm Cod 3.99

44

Ca parametru actual se poate utiliza orice operand compatibil cu instructiunea lea. Astfel daca exista definitia de date :
STRING .data db "abcdefghijklmnopqrstuvwxyz", 0 Cod 3.100

,se pot utiliza formele de invocare:


.code puts STRING ; Adresare directa lea bx, STRING puts [bx] ; Adresare indirecta Cod 3.101

In al doilea caz nu putem scrie puts bx, pentru ca acest apel ar conduce la o expandare de forma lea si,bx , ceea ce este o eroare de sintaxa. forma puts[bx] se expandeaza in lea si,[bx] care este corecta.

Curs 11 09.05.2011

4.3 Controlul numarului de parametri actuali


O problema importanta este controlul coincidentei dintre numarul parametrilor formali si cel al parametrilor actuali. Se vor utiliza urmatoarele directive specifice: directiva %OUT (mesaj la consola la momentul asamblarii) are forma generala %OUT text, efectul fiind afisarea textului la consola la momentul asamblarii: esre utilizata pentru mesajele de eroare la asamblare; directiva .err ( forteaza eroare la asamblare).Aceasta directiva forteaza o eroare la asamblare, atfel incat sa nu se mai genereze fisierul obiect; este utulizata in cazul neconcordantei dintre numarul parametrilor actuali si cel al parametrilor formali; cirectiva exitm (iesire fortata din expandare).In caz de eroare, stopam expandarea macroinstructiunii curente si afisam un mesaj de eroare la consola. Pentru controlul efectiv al parametrilor actuali se mai utilizeaza directivele de asamblare conditionala ifnb ( if not blank) si ifb (is blank) care testeaza existenta sau neexistenta unui parametru actual. Pentru fortarea unei erori , definim pentru inceput macroinstructiunea:
eroare macro text %OUT text ;; Mesaj la consola .err ;; Fortare eroare la ;; asamblare endm Cod 3.102

Sa consideram macroinstructiunea puts, definita mai sus, care are un singur parametru formal.La invocare s-ar putea sa existe un parametru actual, niciunul sau mai multi. Pentru a controla toate aceste situatii, se rescrie macroinstructiunea puts si o declaram cu 2 parametri: x si IN_PLUS. Daca IN_PLUS este nevid inseamna ca sunt cel putin 2 parametri actuali. Iar daca x este vid nu exista nici un parametru actual:
puts macro X, IN_PLUS ifb <X> eroare <PUTS - lipsa parametru> exitm endif

45

ifnb <IN_PLUS> eroare exitm endif lea si, X call puts_proc endm

<PUTS - parametri in plus>

Cod 3.103

Testam explicit daca x este vid si daca IN_PLUS este nevid fortand mesaje adecvate de eroare. Scrierea cu paranteze unghiulare inseamna literalizarea textului respectiv, adica transmiterea lui ca unic parametru.Daca se considera un fisier t_macro.asm cu secventele de invocare:
.data sir db 10 dup (0) .code puts [si] puts [bx] [si] puts [bx],[si] puts puts [bx],sir puts sir end Cod 3.104

, atunci se vor obtine mesajele de eroare


PUTS - parametri in plus PUTS - parametri in plus PUTS - lipsa parametru PUTS - parametri in plus **Error** t_macro.asm(26) EROARE(2) User generated error **Error** t_macro.asm(27) EROARE(2) User generated error **Error** t_macro.asm(28) EROARE(2) User generated error **Error** t_macro.asm(29) EROARE(2) User generated error Cod 3.105

Numerele din paranteze indica liniile din fisierul sursa in care a fost fortata explicit eroarea de asamblare. Acum putem da o regula generala de scriere a unei macroinstructiuni cu controlul parametrilor.Daca macroinstructiunea are N parametri utili, declaram un al N+1 lea parametru suplimentar si testam daca al-N-lea parametru este vid ( cu directiva ifb), respectiv daca al-N+1-lea parametru este nevid (cu directiva ifnb).

4.4 Directive control al listarii. Etichete cu macroinstructiuni


Exista diverse posibilitati de control al fisierului listing al unui program ce contine macroinstructiuni: directiva .sall (supress all suprima tot). In textul sursa care urmeaza acestei directive se va suprima listarea continutului macroinstructiunii invocate.In listing apare numai invocarea(numele) macroinstructiunii, exact ca in fisierul sursa. directiva .lall (list all listeaza tot). Dupa aceasta directiva se listeaza atat invocarea macroinstructiunii cat si textul in general.

46

directiva .xall. Dupa aceasta directiva se listeaza textul generat efectiv de invocarea unei macroinstructiuni. Daca macroinstructiunile contin invocari ale altor macroinstructiuni, la al doilea nive de listeaza numai invocarea. Uneori e necesar ca macroinstructiunea sa contina etichete, de exemplu pentru inctructiuni de salt. Apare urmatoarea problema: daca eticheta se defineste in mod obisnuit, ea va fi generata la fiecare expandare macroinstructiunii, ceea ce va duce la mai multe etichete cu acelasi nume. Acest fapt va provoca o eroare la asamblare de tip simbol multiplu definit. Problema se rezolva prin directiva locala care are forma generala:
LOCAL simb_1, simb_2, ... Cod 3.106

, efectul fiind ca simbolurile ce apar in directiva vor fi expandate in asa fel incat sa nu apara doua nume identice.Practic asamblorul genereaza niste nume complicate de forma ??0000, ??0001, ??0002, etc,(care nus e repeta), pentru care exista sanse minine sa coincida cu nume definite de utilizator. Sa consideram macroinstructiunea:
test_local macro local aici jmp aici aici: endm Cod 3.107

si secventa de invocare:
.code .xall test_local test_local test_local end Cod 3.108

Se va genera urmatorul listing:


test_local jmp ??0000 ??0000: test_local jmp ??0001 ??0001: test_local jmp ??0002 ??0002: Cod 3.109

Eticheta aici a fost inlocuita la epandare cu etichetele ??0000, ??0001 si ??0002. Simbolurile variabile (definite cu operatorul de atribuire = )se dovedesc utile in macroisntructiuni, deoarece pot fi nedefinite chiar in macroinstructiune. Sa consideram definitia:
m_mesaj macro db 'Mesaj ', '0'+n, 0 n=n+1 endm Cod 3.110

si secventa de program :
n=i .data

47

m_mesaj m_mesaj m_mesaj Cod 3.111

Se va genera textul sursa :


db db db 'Mesaj ', '0' + 1, 0 'Mesaj ', '0' + 2, 0 'Mesaj ', '0' + 3, 0 db 'Mesaj 1', 0 'Mesaj 2', 0 'Mesaj 3', 0 Cod 3.113 Cod 3.112

, deci ca si cum s-ar fi scris :


db db

Daca dorim sa includem comentarii in macroinstructiune, dar acestea sa nu apara la fiecare expandare ci numai la definitia macroinstructiunii, putem utiliza secventa de doua caractere ;; (inceput de comentariu).

4.5 Macroinstructiuni repetitive


Aceste macroinstructiuni sunt predefinite,deci nu trebuie definite de utilizator. Scopul lor este de a general secvente repetate de program. macroinstructiunea rept (repete- repeta). Forma generala de invocare este:
rept n ; ; Corp macroinstructiune ; endm Cod 3.114

,in care n este o constanta intreaga. Efectul este repetarea corpului macroinstructiunii de n ori. Secventa anterioara de generare a 3 mesaje s-ar putea scrie acum:
rept 3 m_mesaj endm Cod 3.115

Iata o secventa care genereaza un sir de caractere cu litere de la A la Z:


n=0 alfabet label byte rept 26 db 'A'+ n n=n+1 endm Cod 3.116

macroinstructiunea irb (indefinite repete repeta nedefinit). Forma generala de invocare este:
irp p_formal, <lista_par_act> ; ; Corp macroinstructiune ; endm Cod 3.117

48

, in care p_formal este un parametru formal, iar lista_par_act este o lista de parametri actuali, separati prin virgula.Efectul este repetarea corpului macroinstructiunii de atatea ori cate elemente contine lista de parametri actuali.La fiecare repetare, se substituie parametrul formal cu cate un parametru actual. Invocarea :
irp x, <'a', 'b', 'c'> db x endm Cod 3.118

,se va expanda in :
db 'a' db 'b' db 'c' Cod 3.119

4.6 Operatori specifici


Exista o serie de operatori specifici macroinstructiunilor. Acestia controleaza in principal substitutia parametrilor actuali, fiind utili in special in macroinstructiuni repetitive.

4.6.1 Operatorul de substituire de concatenare (&)


Acest operator, aplicat unui parametru formal, realizeaza substitutia si ( eventual) concatenarea sa cu un text fix sau cu un parametru formal. Este necesara in contextul in care un parametru formal ar fi interpretat ca un simbol ( de exemplu intr-un sir constant de caractere sau intr-un identificator). Sa presupunem ca dorim sa definim automat liniile de program:
mesaj_1 db 'Text 1', 0 mesaj_2 db 'Text 2', 0 mesaj_3 db 'Text 3', 0 mesaj_4 db 'Text 4', 0 Cod 3.120

Vom apela evident la macroisntructiunea irp. O prima incercare ar fi :


irp x, < 1, 2, 3, 4 > mesaj_x db 'Text x', 0 endm Cod 3.121

,ceea ce este incorect deoarece se va produce aceiasi linie de program. Prima aparitie a parametrului x nu poate fi distinsa de simbolul mesaj-x, iar a doua nu poate fi distinsa de simbolul text x. Aici intervine operatorul endm, definitia corecta fiind :
irp x, < 1, 2, 3, 4 > mesaj_&x db 'Text &x', 0 endm Cod 3.122

, prin care ni primul caz se concateneaza textul fix mesaj_ cu parametrul formal x, iar al doilea se substituie parametrul formal x chiar daca apare intr-un sir constant de caractere. Sa consideram un exemplu inrudit codificat prin macroisntructiunea urmatoare:
genereaza macro fix, n X=1 rept n fix&&x db 'Text &x', 0 x=x+1

49

endm endm Cod 3.123

Aici e necesara concatenarea a 2 parametri formali ( fix si x): fiecaruia i se aplica operatorul endm, la stanga sau la dreapta, dupa locul in care are loc concatenarea. Un apel de forma :
genereaza mesaj_ , 4 Cod 3.124

,va produce acelasi text ca macroinstructiunea irp de mai sus.

4.6.2 Operatorii de literalizare sir/caracter ( < >, !)


Operatorul de literalizate sir <> se utilizeaza atunci cand se doreste ca un text in care apar eventuali separatori ( spatii albe, virgule, etc) sa fie considerat ca un unic parametru ( sa fie literalizat). Operatorul se utilizeaza atat in definitii cat si in invocari de macroinstructiuni. De exemplu in definitia :
init macro x irp y, <x> db y endm endm Cod 3.125

,dorim ca parametrul x de la nivelul exterior sa fie transmis ca atare catre macroinstructiunea irp. Invocarea se va face in forma:
init <'A', 'B', 'C', 'D'> Cod 3.126

, ce are ca efect transmiterea listei A,B,C,D ca unic parametru. Operatorul de literalizare caracter , !, se aplica unui singur caracter, efectul fiind de a trata acel caracter ca un caracter obisnuit ( fara a-l interpreta). Se utilizeaza impreuna cu caractere ce au semnificatii speciale in macroinstrutiuni.Sa consideram o macroinstructiune care defineste mesaje de eroare:
err_gen macro N, X err_&N db 'Eroare &N : &X', 0 endm Cod 3.127

O invocare de forma:
err_gen 23, <Parametru ilegal> Cod 3.128

, se va expanda in :
err_23 db 'Eroare 23 : Parametru ilegal', 0 Cod 3.129

Daca dorim insa sa generam un mesaj de forma pan_1 >pan_2, intram in conflict cu semnificatia speciala a caracterului > care intra in componenta operatorului de literalizare sir.Solutia este sa folosim operatorul ! si sa scriem :
err_gen 24, <par_1 !> par_2> Cod 3.130

, ceea ce va genera mesaju corect:


err_24 24, 'Eroare 24 : par_1 > par_2', 0 Cod 3.131

4.6.3 Operatorul de evaluare expresie %


Acest operator se aplica in expresii oarecare, efectul fiind evaluarea acelei expresii. Dintr-un anumit punct de vedere, operatorul % este inversul operatorului de literalizare. Sa consideram macroinstructiunea:

50

def macro a, b db '&a', 0 db '&b', 0 endm Cod 3.132

,care genereaza date. O invocare de forma:


alfa equ 100 beta equ 200 def <alfa + beta>, %(alfa + beta) Cod 3.133

In invocarea lui def, primul parametru este literalizat, iar al doilea evaluat, ceea ce explica textul generat.

51

S-ar putea să vă placă și