Sunteți pe pagina 1din 217

CAP.1.

STRUCTURI DE SISTEME CU MICROPROCESOR


PENTRU
CONDUCEREA PROCESELOR INDUSTRIALE

1.1. Consideraţii generale


Echipamentele numerice de conducere a proceselor industriale (regulatoarele numerice,
calculatoarele de proces), în special după introducerea în structura lor a microprocesoarelor au
constituit un pas considerabil pe calea reducerii decalajului dintre rezultatele remarcabile oferite
de teoria sistemelor automate şi tehnicile aplicate în practica conducerii proceselor industriale.
Aceste echipamente permit, fără a efectua modificări în structura sau în configuraţia lor,
implementarea celor mai diverse strategii de conducere, începând cu cele de tip convenţional,
PID, şi ajungând la cele care să determine atingerea performanţelor optime ale funcţionării
proceselor cu un minimum de energie şi materie primă.
Realizarea acestor deziderate impune specialiştilor din domeniul conducerii proceselor
cunoaşterea specificului procesului condus şi a teoriei sistemelor automate, precum şi a
calculatoarelor de proces, a funcţionării acestor elemente şi, mai ales, a programării lor pentru
asigurarea scopului propus: supravegherea şi conducerea "în timp real" a unui proces.
Definiţie: Se numeşte calculator de proces un complex de mijloace tehnice şi de programe
care sunt destinate rezolvării problemelor de supraveghere, de comandă, de diagnosticare şi de
prognozare a funcţionării instalaţiilor industriale. Un calculator de proces poate fi privit ca o
reuniune între un calculator numeric universal (de obicei un microcalculator sau un
minicalculator) înzestrat cu un executiv sau un sistem de operare corespunzător capabil să
funcţioneze în timp real şi un sistem de interfaţă (cuplorul de proces) cu procesul condus şi
operatorul tehnolog. Schema bloc a unui CP (calculator de proces) este prezentată în Fig.l.1.

Fig. 1.1

În această schemă, în categoria perifericelor generale sunt incluse: consola calculatorului


(pentru inginerul de sistem), imprimanta, unităţi de memorie externă (CD-uri, DVD-uri, bandă
magnetică, bandă perforată) etc.
Consola operatorului de proces (operatorului tehnolog) - C.O.P. - este consola specialistului
tehnolog care cunoaşte foarte bine procesul condus, dar care, în general, nu este informatician.

1-1
C.O.P.-ul este de regulă un panou cu un sistem de chei şi lămpi de semnalizare sau un tablou
sinoptic sau, mai modern, un video-display color cu schema funcţională a instalaţiei sau elemente
din schema funcţională a instalaţiei la diferite nivele de detaliere. Astfel de console (console cu
display cu facilităţi grafice) permit şi alte funcţii speciale ca, de exemplu, depanarea asistată de
calculator a instalaţiei.
Calculatorul universal este de obicei un microcalculator realizat cu microprocesor de cel
puţin 16 biţi sau un minicalculator.
Cuplorul de proces asigură dialogul bidirecţional între procesul condus şi calculatorul
universal.
Evidenţiind căile de introducere şi extragere (furnizare) a datelor de la şi respectiv către
proces putem defini următoarele moduri potenţiale de conectare dintre calculator şi proces:
- Sisteme de calcul off-line, la care legătura informaţională între calculator şi proces este
stabilită prin intermediul operatorului uman. Datele din proces pot fi culese normal, prin citire, de
către operator, sau automat într-o formă care poate fi utilizată direct de calculator (bandă
magnetică, bandă perforată etc.);
- Sisteme de calcul in-line, sunt sistemele la care operatorul poate introduce datele în mod
aleator direct de la tastatură, ele trebuind să fie "imediat" preluate şi prelucrate. Apare, în acest
caz, necesitatea "întreruptibilităţii" calculatorului în procesul de calcul;
- Sisteme de calcul on-line, care sunt cuplate direct cu procesul pe partea de culegere de
date prin intermediul cuploarelor de proces (convertoare analog-numerice).
În cazul în care datele de ieşire sunt transmise operatorului sub formă de mesaje, iar acesta
intervine în proces în urma interpretârii lor, sistemul de numeşte on-line în circuit deschis.
Calculatorul funcţionează în regim de "ghid operator" sau "consultant" al conducerii procesului.
În cazul în care, pe baza datelor culese, sistemul de calcul elaborează mărimi pe care le
aplică direct procesului, fară intervenţia operatorului, sistemul se numeşte on-line în circuit
închis. Conectarea on-line în circuit închis poate fi de urmărire, situaţie în care calculatorul
calculează (determină) şi modifică referinţele unor regulatoare convenţionale), sau directă
(calculatorul calculează şi elaborează comanda la nivelul elementelor de execuţie).
Pentru a realiza funcţiile impuse, calculatorul de proces trebuie să posede o serie de
facilităţi:
• să fie întreruptibil;
• să permită prelucrarea datelor culese direct din procesul condus prin intermediul unor
periferice specializate;
• să ofere răspunsul într-un anumit interval de timp strict corelat cu evenimentele din
proces (să funcţioneze în "timp real");
• să rezolve contradicţia între capacitatea lui de a executa la un moment dat un singur
program şi cerinţa procesului de a fi "servit" în n, n > 1, puncte simultan.
Definiţie: Sistemele de calcul care preiau suficient de rapid datele de intrare, le prelucrează
într-un interval de timp suficient de scurt şi oferă utilizatorului sau direct procesului (prin
periferice specializate) rezultatele suficient de rapid pentru a mai putea influenţa desfăşurarea
fenomenelor din procesul care a produs datele de intrare, se numesc sisteme de calcul în timp real
(SCTR).
Din definiţia dată, se observă că, calculatoarele de proces fac parte din clasa SCTR.
Dezvoltarea acestor clase de calculatoare a fost posibilă, pe de o parte datorită perfecţionărilor
tehnologice (unităţi centrale ultrarapide, specializarea echipamentelor periferice, perfecţionarea
transmisiei datelor), iar, pe de altă parte, prin dezvoltarea şi perfecţionarea sistemelor de operare
(SO). Toate aceste perfecţionări au dus la micşorarea timpului de răspuns al sistemului de calcul.

1-2
Definiţie: Se numeşte timp de răspuns al unui sistem de calcul intervalul de timp dintre
momentul generării datelor primare şi momentul obţinerii rezultatului prelucrării datelor.
Pentru un sistem de calcul on-line, timpul de răspuns este dat de intervalul de timp dintre
momentul producerii unui eveniment în procesul condus şi momentul în care se generează
comanda către proces. Se observă că acest timp înglobează timpul necesar achiziţiei datelor,
prelucrării datelor şi generării comenzii către proces.
Indiferent de modul de conectare cu procesul, calculatorul de proces a format cel de-al
doilea nivel de conducere a proceselor industriale, primul nivel fiind reprezentat de elemente de
automatizare convenţionale realizate de regulă cu regulatoare de tip PID.
Creşterea complexităţii proceselor de conducere, impunerea unor cerinţe superioare de
fiabilitate, a avut drept efect imposibilitatea îndeplinirii întregului volum de sarcini legate de
conducerea acestora cu un singur calculator de proces. Din aceste considerente a apărut
necesitatea distribuirii funcţiilor de conducere între mai multe unităţi de calcul, care, la rândul lor,
au fost subordonate unui calculator "universal" de mare capacitate, care să rezolve rapid o serie
de probleme complexe cum ar fi: identificarea procesului, conducerea optimală sau adaptivă a
procesului etc.
Se obţine astfel o ierarhizare funcţională clasică pe trei nivele a unei structuri de conducere
numită structură distribuită de conducere caracterizată prin fiabilitate, flexibilitate şi
potenţialitate ridicată. Prin intermediul unei astfel de structuri se poate asigura conducerea
proceselor de medie sau de mare complexitate după strategii de la cele mai simple (de tipul PID)
la cele mai evoluate care vizează conducerea adaptivă şi cea optimală. O structură distribuita de
conducere, frecvent întâlnită în prezent este prezentată în Fig.1.2.

Fig. 1.2

La nivelul 1 sunt plasate elementele de automatizare convenţională care primesc


informaţiile despre proces prin intermediul traductoarelor şi elaborează comenzi pentru reglarea
acestuia utilizând algoritmi simpli de reglare de tip PID.
Elementele de la nivelul 2, regulatoare numerice monocanal sau multicanal specializate sau
microcalculatoare pentru conducerea proceselor, au sarcini cvasi-identice şi cvasi-independente,
schimbul de informaţii între elemente realizându-se prin intermediul magistralei sistemului sub

1-3
controlul directorului de trafic. Funcţiile ce trebuie realizate la acest nivel sunt: achiziţia şi
validarea datelor culese din proces, calculul şi elaborarea comenzilor către procesul condus prin
intermediul cuploarelor de proces, comunicarea cu operatorul tehnolog (COP) şi cu nivelul
ierarhic superior (minicalculatorul universal). În mod curent, la acest nivel se utilizează
microcalculatoare realizate cu microprocesoare pe cel puţin 16 biţi sau regulatoare numerice
realizate tot cu astfel de elemente. Puterea de calcul a acestor microcalculatoare acoperă
necesităţile de rulare a programelor care asigură funcţiile de reglare pentru 8-16 bucle de reglare.
Dacă numărul buclelor de reglare este mai mare (peste 20) se recomandă folosirea unui
microcalculator industrial de uz larg.
La cel de-al treilea nivel de automatizare se introduce un minicalculator de capacitate mare
destinat conducerii după strategii evoluate a întregului proces. În cazul proceselor mai simple se
poate utiliza chiar un microcalculator de proces de uz larg. Tot la acest nivel este plasată consola
operatorului de proces cu funcţii complexe de comunicare cu toate echipamentele de calcul din
cadrul structurii, având rolul de a permite supravegherea şi conducerea operativă a procesului.
Dinamica elaborării rezultatelor la nivelul 3 este relativ lentă. Minicalculatorul primeşte
date sintetice despre evoluţia procesului de la nivelul inferior (nivelul 2), iar mărimile rezultate în
urma calculelor nu intervin direct în proces, deci la acest nivel nu sunt necesare cuploare de
proces.
O problemă importantă a acestei structuri de conducere este aceea a asigurării
compatibilităţii între structurile de date vehiculate între diferitele nivele pentru a permite un
dialog corect între acestea.
Unul din principalele avantaje ale unei astfel de structuri distribuite de conducere este acela
că ea poate fi dezvoltată în timp şi spaţiu, pe orizontală şi pe verticală, de la simplu la complex,
putându-se începe cu un singur echipament cu microprocesor plasat la nivelul 2 de automatizare,
dotat cu o consolă operator proprie (display, tastatură, imprimantă), Fig.1.3, având implementaţi
algoritmi de: achiziţie şi validare a datelor din proces, semnalizare şi protecţie la depăşirea
limitelor, calcul şi elaborare a comenzilor către proces, comunicare cu operatorul în vederea
realizarii configurării şi urmăririi evoluţiei mărimilor din proces, posibilităţi de comunicare cu
NIS (nivelul ierarhic superior).

Acest echipament poate fi, aşa cum am arătat, fie un regulator numeric specializat având
aceşti algoritmi implementaţi sub forma unei biblioteci de programe organizată după o arhitectură
bine pusă la punct, corespunzătoare unei anumite clase de procese, sau poate fi un calculator
destinat conducerii proceselor industriale (microcalculator de proces) capabil de a fi dotat cu
astfel de algoritmi la momentul dorit.

1-4
Fără a face o analiză detaliată a avantajelor şi dezavantajelor celor două moduri de
rezolvare a problemei conducerii, precizăm că vom insista asupra celei de-a doua variante, şi
anume, utilizarea în conducerea directă a proceselor a unui microcalculator de proces. Aceste
echipamente permit elaborarea şi implementarea unor algoritmi strict necesari orientaţi către
aplicaţie şi sunt mult mai flexibile.
Efortul de programare devine minim dacă este pusă la punct tehnica şi tehnologia de
elaborare a unor astfel de programe şi dacă organizarea hardware a echipamentului este capabilă
să suporte un software după aceste principii.

1.2. Schema de principiu a unei structuri de microcalculator de proces destinat


conducerii proceselor industriale
În cele ce urmează va fi prezentată o structură de echipament cu microprocesor
(microcalculator de proces) destinată conducerii proceselor industriale, amplasabilă la nivelul 2
de automatizare în cadrul structurii ierarhizate de conducere prezentate în Fig.1.2. Structura este
destinată să îndeplinească funcţiile de supraveghere automată (culegere, validare şi protocolare de
date) şi de conducere numerică directă prin intermediul unor algoritmi bipoziţionali,
tripoziţionali, de tip PID sau evoluaţi a unei întregi clase de procese, în special, din categoria
celor numite "lente". De asemenea, structura trebuie să asigure comunicarea cu consola
operatorului de proces şi cu nivelul ierarhic superior.
Schema bloc a unei astfel de structuri, la nivel de black-box, este prezentată în Fig.1.4. Ea
trebuie să permită o funcţionare permanentă, lipsită de blocaje, iar legăturile dintre modulele de
program utilizator şi resursele hardware să se realizeze uşor şi eficient.

Fig. 1.4.

Mergând pe linia dezvoltării arborescente, se poate obţine o detaliere a schemei din Fig.1.4,
detaliere prezentată în Fig.1.5. O asemenea configuraţie permite din punct de vedere software
următoarele:
 achiziţia şi prelucrarea primară (validare, filtrare, liniarizare) a unui număr de mărimi
analogice din proces;
 primirea unui număr de comenzi (intrări numerice) din proces prin intermediul unor
contacte de releu;
 reglarea unor bucle simple sau în cascadă cu algoritmi de tip PID cu ieşire analogică
constantă pe porţiuni, pe durata intervalului de discretizare;
 comanda unui număr de relee (ieşiri numerice) destinate realizării atât a comenzilor
automate (ieşiri numerice), cât şi a algoritmilor de reglare bipoziţionli sau tripoziţionali
sau de tip PI sau PID cu ieşire în impulsuri modulate în durată;
 memorarea datelor curente în memoria RAM;
 înscrierea şi memorarea programelor de bază (MONITOR, EXECUTIV) şi utilizator în
memoria EPROM;

1-5
 memorarea datelor strict necesare (din proces, sau cele configurabile) în memoria RAM
nevolatilă în vederea reluării funcţionării sistemului exact din punctul unde a rămas la o
eventuală cădere intempestivă a tensiunii de alimentare a calculatorului;

Fig. 1.5

 comunicarea cu consola operator proprie, formată din:


• display, pentru afişarea mărimilor curente şi a celor configurabile;
• tastatură, pentru configurarea sistemului şi pentru conducerea manuală a procesului
sau a nivelului 1 de automatizare;
• imprimantă, pentru protocolare de date şi pentru înregistrarea evoluţiei unor mărimi
de interes din proces;
 comunicarea cu nivelul ierarhic superior.
Numărul de intrări/ieşiri analogice şi/sau numerice depinde de configuraţia aleasă pentru
echipament, adică de numărul de plachete de interfaţă prezente în sistem.
Menţionăm că numărul de intrări/ieşiri al unei plachete specifice (IA-intrări analogice, EA-
ieşiri analogice, IN-intrări numerice, EN-ieşiri numerice) variază de la echipament la echipament.
Indiferent de tipul echipamentului, unitatea centrală trebuie să conţină pe lângă
microprocesor şi un ceas pentru măsurarea timpului şi în funcţie de care se desfăşoară toate
operaţiile din sistem, precum şi un puternic sistem de întreruperi prin intermediul căruia se va
lansa în execuţie, la un moment dat, acel program care va avea prioritate maximă.

1-6
1.3. Particularităţile programării sistemelor de calcul în timp real
Particularităţile programării sistemelor de calcul cu microprocesoare destinate
supravegherii şi/sau conducerii în timp real a proceselor industriale rezultă din următoarele
condiţii care trebuie îndeplinite:
 posibilitatea sistemului de calcul de a răspunde instantaneu la semnale emise din proces
în mod aleator;
 capacitatea sistemului de calcul de a primi datele direct din proces sau/şi de a le
transmite direct în proces prin intermediul unor periferice nestandard (convertoare analog-
numerice, convertoare numeric-analogice etc.);
 cerinţa ca "timpul real" în care sistemul de calcul este ocupat cu o anumită operaţie
corespunzătoare unui anumit eveniment, să fie strict corelat cu timpul în care se produc şi alte
evenimente în procesul industrial condus;
 rezolvarea contradicţiei între capacitatea sistemului de calcul de a executa la un moment
dat un singur program şi cerinţa procesului de a fi "servit" în n puncte simultan; altfel spus,
sistemul trebuie să facă faţă desfăşurării simultane a diferitelor părţi specifice ale procesului;
 posibilitatea programării tuturor categoriilor de procese (continue sau discrete);
 existenţa elementelor pentru testarea şi depanarea eficientă a programelor.
Din cele de mai sus, rezultă că, pentru programarea unei aplicaţii în timp real, limbajul de
programare utilizat trebuie sa conţină trei categorii de instrucţiuni:
 instrucţiuni care să permită programarea modului în care se desfăşoară evenimentele în
proces;
 instrucţiuni care să precizeze locul în care se desfăşoară evenimentele în proces;
 instrucţiuni care se referă la momentul sau intervalul de timp în care au loc evenimentele
în proces.
Instrucţiunile din prima categorie formează un set de bază care poate fi utilizat fără opţiuni
de timp real din partea sistemului de calcul. Instrucţiunile din celelalte categorii sunt specifice
lucrului în timp real şi formează o extensie a limbajului de bază. Ele pot fi obţinute prin
intermediul sistemului de întreruperi (locul desfăşurării evenimentelor) şi a ceasului de timp real
(timpul sau intervalul de timp în care au loc evenimentele în proces) existente obligatoriu în orice
configuraţie de conducere sau supraveghere a unui proces.
Un sistem de calcul pentru conducerea unui proces reprezintă o unitate dialectică între
componenta hardware a sa, cea care defineşte configuraţia sistemului şi componenta sa software,
care constituie totalitatea programelor sistemului.
Programele implementate pe un astfel de sistem de calcul se împart în două mari categorii:
a) programe de sistem;
b) programe de utilizator sau de aplicaţie.
Programele de sistem sunt programe care au un caracter universal şi sunt parte
componentă a unui anumit tip de calculator, independent de procesul pe care acesta îl va conduce.
Acest ansamblu de programe formează ceea ce se numeşte sistemul de operare al calculatorului şi
are rolul de a asigura executarea corectă a sarcinilor sale.
Programele de utilizator (programele de aplicaţie sau de conducere), în opoziţie cu
programele de sistem, au un caracter specific, funcţie de proces, ele fiind o imagine a ceea ce se
întâmplă în proces.

1-7
CAP.2. PROGRAMAREA ÎN LIMBAJ DE ASAMBLARE A
MICROPROCESORULUI I8086

Arhitectura internă a microprocesorului I8086


Microprocesorul I8086, una dintre primele unităţi centrale monolitice pe 16 biţi, este
elementul de bază al unei întregi familii de circuite VLSI, ce permit realizarea de sisteme
programabile complexe. UCP (unitatea centrală de prelucrare) I8086, realizată în tehnologie N-
MOS şi împachetată într-o capsulă cu 40 pini, funcţionează la o frecvenţă de tact de 5÷8 MHz,
realizează transfer de date pe 8 sau 16 biţi şi adresează direct o memorie cu dimensiunea maximă
de 1 Moctet, având o magistrală de adresare de 20 biţi.

Segmentarea memoriei
Pentru a simplifica gestiunea memoriei şi protecţia datelor, la microprocesoarele la care
dimensiunea memoriei principale creşte (μp: I8086, IAPX186, IAPX286 etc. cu dimensiunea
memoriei ≥ 1 Moctet) se poate utiliza segmentarea memoriei.
Un segment este o unitate logică de memorie formată din locaţii adiacente de memorie
fizică, cu dimensiunea maximă precizată, de regulă, 64 Kocteţi.
Segmentarea memoriei implică formarea adresei unei locaţii fizice de memorie din 2
componente:
¾ componenta de SEGMENT, se mai numeşte şi adresă de segment (adresă de bază) a
segmentului logic, notată "ssss", unde s este o cifră hexazecimală;
¾ componenta de OFFSET, se mai numeşte şi adresă relativă a locaţiei faţă de adresa de
bază a segmentului, notată "oooo", unde o este o cifră hexazecimală.
Dacă în interiorul unui segment toate adresele de referire (pentru program şi pentru date)
sunt relative la adresa de bază a segmentului, atunci un segment poate fi plasat la orice adresă în
memoria fizică principală, conducând astfel la proprietatea de relocabilitate a segmentelor şi
implicit a programelor.
La μp I8086, memoria fizică este divizată în segmente cu dimensiunea de 64 Kocteţi. La un
moment dat pot fi active: un segment de cod (program), un segment de date, un segment de stivă
şi un extra-segment (pentru date suplimentare). Adresa de bază a fiecărui segment activ este
păstrată în câte un registru de 16 biţi numit, respectiv:
ƒ Code Segment (CS), pentru segmentul de cod;
ƒ Data Segment (DS), pentru segmentul de date;
ƒ Stack Segment (SS), pentru segmentul de stivă;
ƒ Extra Segment (ES), pentru segmentul de date auxiliare (extrasegment).
Deoarece toate registrele μp I8086 sunt pe 16 biţi (inclusiv cele segment), adresa fizică FA
(physique address) corespunzătoare unei perechi (SEGMENT, OFFSET) sau (ssss, oooo) se
calculează cu relaţia:
FA = ssss * 16 + EA = ssss * 16 + oooo,
unde EA = oooo este adresa efectivă (effective address). Se obţine astfel o adresă pe 20 biţi,
numită pointer. Un pointer se mai notează şi sub forma ssss:oooo şi înseamnă că operandul se
găseşte la adresa oooo în segmentul ssss.
Exemplu: Dacă DS = 1300h, iar EA = 0125h, atunci adresa absolută a datei (aflată în
segmentul de date) este:
FA = 1300h * 16 + 0125h = 13125h (adresă pe 20 biţi)

2-1
Deci, valoarea ssss pe 16 biţi, conţinută într-un registru-segment, reprezintă adresa de
început a segmentului respectiv. Modul de reprezentare ales impune restricţia ca un segment să
înceapă la o adresă absolută multiplu de 16.
În memoria principală segmentele pot fi disjuncte, parţial suprapuse sau total suprapuse:

Rezultă că, o locaţie de memorie de adresă fizică dată poate aparţine mai multor segmente
şi poate fi referită în mod corespunzător prin registrul-segment respectiv şi deplasamentul în
cadrul segmentului. În cel mai simplu caz, în care conţinutul registrului CS = DS = SS = ES,
revenim, de fapt, la cazul cel mai simplu al UCP fără segmentarea memoriei.

Registrele interne ale μp I8086


Din punct de vedere al programatorului, cea mai simplă arhitectură internă a μp I8086 arată
astfel:

2-2
Deosebim:
1. Registre de date: AX, BX, CX, DX sunt registre generale de 16 biţi utilizate în
instrucţiuni aritmetice şi logice. Sunt adresabile atât la nivel de octet prin AH, AL, BH, BL, CH,
CL, DH, DL cât şi direct ca registre de 16 biţi AX = (AH, AL), ... , DX = (DH, DL). Majoritatea
instrucţiunilor aritmetice utilizează în acelaşi mod toate aceste registre. Există însă şi instrucţiuni
aritmetice pentru care anumite registre generale au semnificaţii speciale (implicite), astfel:
ƒ AX este utilizat pentru efectuarea instrucţiunilor aritmetice de înmulţire şi împărţire pe
16 biţi precum şi pentru operaţii de intrare-ieşire (I/O) pe 16 biţi;
ƒ AL, AH sunt utilizate pentru efectuarea instrucţiunilor aritmetice de înmulţire şi
împărţire pe 8 biţi;
ƒ AL este utilizat în operaţiile aritmetice efectuate cu operanzi BCD şi în cele de
conversie;
ƒ BX este utilizat ca registru de bază în operaţiile de adresare;
ƒ CX este utilizat în operaţiile cu şiruri şi are rol de contor în operaţiile de buclare;
ƒ DX este utilizat pentru efectuarea instrucţiunilor aritmetice de înmulţire şi împărţire pe
16 biţi şi ca registru de adresare indirectă în operaţiile de I/O.

2. Registre indicatoare de adresă


2a) Registrele pointer:
¾ IP (Instruction Pointer) este contorul de program reprezentat printr-un registru de 16
biţi a cărui valoare conţine adresa relativă (offsetul) a instrucţiunii curente (instrucţiunea ce
urmează a fi executată) în cadrul segmentului de cod curent. Adresa completă a instrucţiunii
curente este precizată prin pointerul CS:IP. În cazul unei instrucţiuni de salt inter-segment,
conţinutul lui IP împreună cu conţinutul lui CS este salvat în vârful stivei, după care CS este
încărcat cu adresa de bază a segmentului, iar IP-ul cu adresa relativă din segmentul de cod,
corespunzătoare instrucţiunii ţintă.
¾ SP (Stack Pointer) - registru pe 16 biţi care conţine adresa relativă a vârfului stivei în
cadrul segmentului de stivă. SP-ul este utilizat implicit în toate operaţiile cu stiva. Adresa
completă a vârfului stivei este dată de pointerul SS:SP.
¾ BP (Base Pointer) - registru pe 16 biţi folosit pentru adresarea operanzilor plasaţi în
stivă.
Observaţie: Registrele SP şi BP pot fi utilizate în anumite instrucţiuni aritmetice şi logice
ca registre pe 16 biţi.
2b) Registrele index SI şi DI sunt utilizate, în general, pentru adresarea indexată a
operanzilor, conţinând adresele relative ale acestora în cadrul segmentului de date curent.
Segmentul implicit utilizat în adresare poate fi modificat prin folosirea în instrucţiuni a unor
prefixe speciale.
Registrele index sunt utilizate ca registre implicite în instrucţiunile efectuate pe şiruri de
caractere. În acest ultim caz, registrul SI conţine adresa relativă curentă a elementelor şirului
sursă plasat în segmentul de date curent, iar DI conţine adresa relativă curentă a elementelor
şirului destinaţie plasat în segmentul de date suplimentare. §i registrele index pot fi utilizate în
instrucţiunile de transfer de date şi în instrucţiunile aritmetice şi logice ca registre de 16 biţi.
2c) Registrele segment CS, DS, SS, ES conţin respectiv:
ƒ CS : adresa segmentului de cod (program) curent;
ƒ DS : adresa segmentului de date curent;
ƒ SS : adresa segmentului de stivă curent;
ƒ ES : adresa segmentului de date suplimentare curent.
Instrucţiunea ce urmează a fi executată se găseşte în segmentul a cărui adresă de început se
află în registrul CS, la adresa relativă în segment conţinută în IP.

2-3
Conţinutul registrului DS defineşte adresa de început a segmentului de date curent. Toate
referirile la datele din memorie, cu excepţia celor care utilizează registrele BP, SP sau DI,
utilizează implicit segmentul referit de registrul DS.
Conţinutul registrului SS defineşte adresa de început a segmentului de stivă curent. Toate
referirile la datele din memorie care utilizează implicit registrele SP şi BP sunt considerate ca
implicând registrul SS.
Conţinutul registrului ES defineşte adresa de început a segmentului de date suplimentare.
Operaţiile pe şiruri de caractere ce utilizează registrul DI sunt considerate ca implicând segmentul
referit de registrul ES.
Selectarea registrului-segment care se va utiliza în calculul adresei fizice depinde atât de
modul de adresare utilizat, cât şi de tipul ciclului maşină curent. În acest sens, există următoarele
reguli:
a) în ciclurilre de FETCH se utilizează întotdeauna registrul CS;
b) în operaţiile cu stiva se utilizează întotdeauna registrul SS;
b) în operaţiile cu şiruri de caractere, pentru adresarea operandului destinaţie, se utilizează
întotdeauna registrul ES;
d) când la calculul offsetului participă conţinutul lui BP se utilizează implicit SS, dar se
poate reindica folosirea oricăruia dintre celelalte 3 registre;
e) în rest se utilizează DS, dar se poate reindica folosirea oricăruia dintre celălalte 3
registre.
Deoarece există 4 registre segment, înseamnă că simultan pot fi adresabile 4 segmente: CS
curent, DS curent, SS curent şi ES curent.

3. Registrul indicatorilor de condiţii PSW


Asamblarea biţilor din registrul PSW este prezentată în figura următoare:

Biţii din PSW se numesc flaguri şi se împart în două categorii:


3a) Flagurile de stare (de condiţie) - Status Flags - memorează informaţii referitoare la
rezultatul unor operaţii aritmetice şi logice executate de ALU (Arithmetic and Logic Unity): AF,
CF, OF, PF, SF, ZF.
• Indicatorul AF (Auxiliary Carry Flag) este setat (devine 1) dacă, în execuţia unei
instrucţiuni care poziţionează acest indicator, a apărut un transport de la rangul (bitul) 3 la rangul
4 al rezultatului sau a fost efectuat un împrumut de la rangul 4 la rangul 3, altfel AF = 0. Este
utilizat de procesor pentru corectaea rezultatelor efectuate cu operanzi BCD.
• Indicatorul CF (Carry Flag) este setat dacă a apărut un transport din, sau s-a făcut un
împrumut în, rangul cel mai semnificativ (c.m.s.) al rezultatului, altfel CF = 0.
• Indicatorul OF (Overflow Flag) se setează dacă în execuţia unei instrucţiuni aritmetice
cu semn, care poziţionează acest indicator, a apărut o depăşire, adică s-a obţinut un rezultat care
nu poate fi memorat corect în destinaţia stabilită de către instrucţiune.
• Indicatorul SF (Sign Flag) ≡ bitul c.m.s. al rezultatului: SF = 1 semnifică rezultat
negativ, iar SF = 0 semnifică rezultat pozitiv sau nul.
• Indicatorul PF (Parity Flag) se setează dacă, în urma execuţiei unei instrucţiuni care
poziţionează acest indicator, octetul cel mai puţin semnificativ (c.m.p.s.) al rezultatului are un
număr par de cifre 1, altfel PF = 0.

2-4
• Indicatorul ZF (Zero Flag) devine 1 dacă, în urma execuţiei unei instrucţiuni care
poziţionează acest indicator, s-a obţinut un rezultat nul, altfel ZF = 0.
3b) Flaguri de control (Control Flags) al procesorului - memorează informaţii referitoare
la controlul procesorului: DF, IF, TF.
• Indicatorul DF (Direction Flag) indică direcţia de parcurgere a şirurilor de caractere
(octeţi sau cuvinte) în cadrul instrucţiunilor pe şiruri de caractere: DF = 1 înseamnă
autodecrementarea, iar DF = 0 înseamnă autoincrementarea registrelor index SI şi DI (de la
adrese mari la adrese mici, respectiv de la adrese mici la adrese mari).
• Indicatorul IF (Interrupt-Enable Flag) controlează acceptarea întreruperilor mascabile
externe: dacă IF = 1, sistemul de întreruperi este validat (este validată acceptarea întreruperilor
mascabile externe); dacă IF = 0, sistemul de întreruperi este invalidat. Indicatorul IF nu are
influenţă asupra întreruperilor nemascabile.
• Indicatorul TF (Trap Flag) este utilizat pentru controlul execuţiei instrucţiunilor în regim
pas cu pas. Dacă TF = 1, atunci UCP lucrează pas cu pas (single step) caz în care, după fiecare
execuţie a instrucţiunii, se generează o întrerupere internă pe nivelul 1. Execuţia secvenţei de
tratare a acestei întreruperi se face cu indicatorul TF având valoarea 0.
Tipurile de date elementare manevrate de μp I8086 sunt:
¾ Octetul cu dimensiunea de 8 biţi, poate fi plasat în memorie la orice adrese, pare sau
impare.
¾ Cuvântul cu dimensiunea de 16 biţi, poate fi plasat în memorie atât la adrese pare cât şi
impare.
¾ Pointerul (cuvântul dublu) are dimensiunea de 32 biţi şi are 2 componente:
ƒ componenta de segment (se memorează la adrese mai mari);
ƒ componenta de offset (se memorează la adrese mai mici).
Convenţia de reprezentare a datelor multioctet în memorie este cea standard pentru
microprocesoarele Intel: octeţii mai puţin semnificativi sunt plasaţi la adrese mai mici, iar octeţii
mai semnificativi, la adrese mai mari. Exemple:

Moduri de adresare
Prin mod de adresare se înţelege acea modalitate de determinare a adresei unui operand
specificat într-o instrucţiune. Pentru μp I8086 deosebim două categorii de moduri de adresare:
- moduri de adrersare a datelor;
- moduri de adresare a instrucţiunilor.
Moduri de adresare a datelor
1. Adresarea imediată este adresarea în care operandul (data) este specificat în instrucţiune,
imediat după codul operaţiei. Operandul poate fi pe 1, 2 sau 4 octeţi.
Exemplu:
data_segment SEGMENT

2-5
aw DW 'AB'
data_segment ENDS
mov al, 5 ; Registrul AL se încarcă cu valoarea 5
mov ax, 5 ; Registrul AX se încarcă cu valoarea 5
mov ax, OFFSET aw ; Registrul AX se încarcă cu adresa
; relativă a operandului aw din
; segmentul data_segment
mov ax, data_segment ; Registrul AX se încarcă cu adresa
; segmentului de date data_segment
mov ds, ax ; DS <--- AX
2. Adresarea directă la registru este adresarea în care operandul este conţinutul unui
registru specificat în instrucţiune. Pentru operanzi reprezentaţi pe cuvânt, registrul poate fi: AX,
BX, CX, DX, SI, DI, SP, BP. Pentru operanzi reprezentaţi pe octet, registrul poate fi: AL, AH,
BL, BH, CL, CH, DL, DH.
Exemplu: mov bx, ax ;
mov al, cl ;
mov ds, ax ;
mov bp, bx;
3. Adresarea directă la memorie. În instrucţiune apare adresa efectivă a operandului (datei).
Exemplu: mov ax, aw ; AX <--- operandul de la adresa relativă aw
mov aw+2, ax ; La adresa relativă a operandului aw+2
; se transferă valoarea registrului AX
4. Adresarea indirectă prin registru. Adresa efectivă a operandului se află într-unul din
registrele BX, BP, SI, DI, registru specificat în cadrul instrucţiunii.
Exemplu:
mov ax, [bx] ; AX <---- conţinutul locaţiei de memorie a cărei
; adresă relativă se află în BX
mov bl, [si] ;
mov ah, [di] ;
;
mov bx, OFFSET aw ; Încarcă BX cu adresa de offset
; a parametrului aw
mov ax, [bx] ; Aceste 2 instrucţiuni sunt echivalente cu ultimele 2
mov [bx+2], ax ; instrucţiuni din exemplul de la punctul 3
5. Adresarea bazată este similară adresării indirecte prin registru, cu excepţia faptului că în
această situaţie, se pot utiliza numai registrele de bază BX şi BP, iar la conţinutul acestora se
poate aduna un deplasament pe 8 sau 16 biţi.
Dacă drept registru de bază se utilizează registrul BX, atunci se consideră implicit, ca
registru de segment, registrul DS, iar dacă drept registru de bază se utilizează registrul BP, atunci
se consideră implicit, ca registru de segment, registrul SS.
De obicei, adresarea bazată se utilizează pentru a referi elementele unei structuri pentru
care adresa de început este conţinută în registrul de bază, iar adresa relativă în cadrul structurii
apare explicit în instrucţiune.
Exemplu:
mov bx, OFFSET structura ; Încarcă BX cu adresa de
; început a operandului structura
mov al, [bx+5] ; Încarcă AL cu conţinutul de la adresa BX+5
; (al şaselea octet al structurii)
5. Adresarea indexată utilizează registrele index SI şi DI împreună cu un nume de variabilă
pentru a adresa date de tip tablou (vectori). Aceste registre sunt folosite ca un index faţă de adresa

2-6
de offset reprezentată prin numele variabilei. Conţinutul registrului utilizat ca index specifică un
deplasament pe un octet/cuvânt faţă de adresa de offset a variabilei. Registrul de segment
considerat implicit este registrul DS.
Exemplu:
mov si, 0 ; Încarcă indexul sursei cu 0
mov di, 0 ; Încarcă indexul destinaţiei cu 0
mov ax, sir_sursă[si] ; Încarcă AX cu primul element al şirului sursă
mov sir_dest[di], ax ; Memorează AX în primul element al
; şirului destinaţie
Dacă elementele şirului sunt cuvinte, atunci acestea au adresele de offset 0, 2, 4, 6, 8, ...,
atunci:
mov si, 6 ; Încarcă indexul sursei cu 6
mov di, 6 ; Încarcă indexul destinaţiei cu 6
mov ax, sir_sursă[si] ; Încarcă AX cu al patrulea element
; al şirului sursă
mov sir_dest[di], ax ; Memorează AX în al patrulea element
; al şirului dest.
5. Adresarea bazată-indexată. În instrucţiune apare atât registrul de bază (BX sau BP), cât
şi registrul index (SI sau DI) utilizate şi, opţional, un deplasament. Adresa fizică rezultă pe baza
adresei de segment implicat în instrucţiune, adresa efectivă a operandului în cadrul segmentului
fiind suma dintre conţinutul registrului de bază, conţinutul registrului index şi deplasamentul
conţinut în instrucţiune.
Registrul de bază este cel care dictează registrul-segment considerat implicit.
Acest tip de adresare este util pentru a realiza accesul la structurile de date create în stivă,
sau accesul la elementele unui vector de înregistrări. În acest ultim caz, în registrul de bază se
încarcă adresa de început a vectorului, în registrul index se încarcă adresa relativă a înregistrării
referite în vector, iar în instrucţiune apare adresa relativă a elementului referit din înregistrare.
Exemple:
array DB 100 DUP (55h) ;
mov bx, OFFSETarray ;
mov si, 2 ;
mov ax, WORD PTR [bx][si] ; Încarcă AX cu conţinutul
; de la adresa BX+SI
mov ax, WORD PTR [bx+si] ; Încarcă AX cu conţinutul
; de la adresa BX+SI
mov al, [bx][si+50] ;
mov al, [bx+si+50] ;

Moduri de adresare a instrucţiunilor


Adresarea instrucţiunilor este asemănătoare cu adresarea datelor. Adresa efectivă a
instrucţiunii curente, calculată ca şi în cazul adresei efective a unui operand, se încarcă în
registrul contor de program IP. Pentru adresarea instrucţiunii curente se utilizează un subset al
modurilor de adresare prezentate mai sus. Astfel, deosebim:
1. Adresarea secvenţială: IP <--- IP+n, unde n ≥ 1 este un deplasament până la adresa
instrucţiunii imediat următoare (lungimea, în octeţi a instrucţiunii). Această adresare este utilizată
implicit pentru adresarea tuturor instrucţiunilor cu excepţia celor de salt, pentru care se disting:
2a. Adresarea directă: IP <--- adresa, unde adresa este un număr ce reprezintă adresa
instrucţiunii unde se face saltul.

2-7
2b. Adresarea relativă: IP <--- IP+d, unde d este un deplasament ce corespunde etichetei la
care se face saltul, provocând deplasarea execuţiei "înainte" sau "înapoi" relativ la valoarea
curentă a registrului IP. Acest tip de adresare are marele avantaj de a produce coduri (programe)
relocabile, deoarece adresa de salt fiind indicată în instrucţiune prin valoarea sa relativă, nu
depinde de adresa absolută la care este plasată instrucţiunea în memorie. Un program în care
instrucţiunile de salt sunt numai de tip relativ produce, prin asamblare, un cod obiect care poate fi
plasat oriunde în memorie şi executat fără nici o modificare. Acest lucru nu se întâmplă la
adresarea directă.
2c. Adresarea indirectă: IP <--- Registru sau IP <--- (EA), unde Registru este conţinutul
unui registru pe 16 biţi (cu exceptia lui CS), iar (EA) indică cuvântul din memorie plasat la adresa
efectivă EA.

2-8
Formatul general (extern) al instrucţiunilor
Instrucţiunile microprocesoarelor I8086/I8088, scrise în limbaj de asamblare, au formatul
tipic acestor limbaje, constituit din mai multe câmpuri:

unde parantezele drepte [ ] arată că elementele incluse pot apărea sau nu în mod facultativ, iar
acoladele { } indică faptul că numai un element din cele scrise pe verticală poate apărea într-o
instrucţiune dată.
Câmpul Eticheta este opţional, iar când apare este un identificator căruia i se asociază
adresa primului octet al instrucţiunii respective.
Mnemonica codului de operaţie este numele simbolic al instrucţiunii sau al unui grup de
instrucţiuni; apare obligatoriu în orice instrucţiune.
Câmpul operanzi poate conţine doi operanzi, unul sau niciunul, în funcţie de tipul
instrucţiunii. Când există doi operanzi, primul este operandul destinaţie, iar cel de-al doilea,
operandul sursă. Operanzii identifică datele asupra cărora acţionează instrucţiunea, modul de
adresare şi alte informaţii auxiliare.
Câmpul Comentariu este opţional. Acesta serveşte pentru creşterea inteligibilităţii
programului. La asamblare, textul comentariului este ignorat de către asamblor.
Exemple:
mov bx, 7a2h ; Încarcă registrul BX cu valoarea 7a2h
alfa: mov beta [bx][di], al ; Transferă octetul din AL la adresa OFFSET
; beta + BX +DI în segmentul de date
; asociat variabilei beta
xchg bl, cl ; Interschimbă conţinutul registrelor BL şi CL
gama: popf ; Reface din stivă conţinutul registrului de flaguri F
Menţionăm că pentru realizarea programelor scrise în limbaj de asamblare, se pot utiliza
mediile de dezvoltare MASM şi TASM, care pun la dispoziţia utilizatorului o serie de directive
din care, aici, menţionăm numai directivele pentru definirea tipurilor de date asupra cărora
acţionează instrucţiunile.
Macroasamblorul MASM, respectiv TASM operează cu următoarele tipuri de date: BYTE
(1 octet), WORD (2 octeţi), DWORD (4 octeţi), QWORD (8 octeţi) şi TBYTE (10 octeţi). De
asemenea se utilizează tipurile NEAR pentru etichete din segmentul curent şi FAR pentru
etichete din alte segmente.
¾ Pentru definirea constantelor se utilizează directiva EQU (EQUate) al cărei format este:
nume EQU operand
unde nume este numele ce se atribuie operandului operand care poate fi o constantă, un nume
simbolic definit anterior, o expresie sau un şir constant.
Expresia este o concatenare de simboluri (operatori şi operanzi) care pot fi:
ƒ Constante numerice - încep întotdeauna cu o cifră şi pot fi întregi sau reale. În cazul
constantelor întregi, reprezentarea se poate face în baza 2, 8, 10 sau 16, indicarea bazei
realizându-se respectiv prin sufixele B, Q, D, H (sau literele mici corespunzătoare). Dacă
indicarea bazei lipseşte, atunci se consideră în mod implicit că baza este 10.
ƒ Constante alfanumerice - şiruri de caractere scrise între ghilimele sau între apostrofuri.
Pentru fiecare caracter dintr-un şir alfanumeric de caractere, valoarea corespunzătoare este codul
ASCII al caracterului respectiv.

2-9
Exemple: ANA EQU 0c2h ;
ANY EQU ANA ;
char EQU ' A' ; char are valoarea 2041h
char1 EQU 'a125' ; char1 are valoarea 61313235h
Este permisă în continuare scrierea unor instrucţiuni care să folosească aceste nume:
mov al, ANA
and al, ANY
mov cx, char
Observaţie: Numele utilizate în EQU nu pot fi redefinite.
ƒ Operatori aritmetici: +, -, *, /, MOD;
ƒ Operatori de deplasare: SHR, SHL;
ƒ Operatori logici: NOT, AND, OR, XOR:
ƒ Operatori relaţionali: EQ, NE, LT, LE, GT, GE;
ƒ Operatori de conversie de tip: PTR, SHORT, LOW, HIGH, SEG, OFFSET, LENGTH,
SIZE, MASK.
Expresiile utilizate pentru iniţializarea datelor sunt expresii care pot fi evaluate în
momentul asamblării programului.
¾ Pentru definirea şi îniţializarea variabilelor, directivele utilizate sunt: DB (Define
Byte), DW (Define Word), DD (Define Doubleword), DQ (Define Quadword), DT (Define
Tenbytes). La asamblare, pentru o variabilă, se alocă una sau mai multe locaţii de memorie
conform tipului variabilei. În cadrul definirii se poate face, în mod facultativ, şi iniţializarea
variabilei. Formatul general al directivei este:

unde:
nume_variabila este numele prin care pot fi referite datele definite. Acest nume are asociat
un tip şi o valoare. Tipul rezultă din tipul datei, iar valoarea este adresa la care se va găsi în
memorie, în timpul execuţiei programului, primul octet rezervat pentru data referită cu numele
respectiv. Limbajul de asamblare utilizează nume rezervate care nu pot fi utilizate ca etichete sau
variabile. Numele rezervate sunt: mnemonicele instrucţiunilor şi pseudoinstrucţiunilor, numele
operatorilor, numele registrelor şi caracterele $ şi ?.
listă operanzi reprezintă lista unor constante, simboluri sau expresii separate prin virgulă,
cu ale căror valori se vor iniţializa zonele de date rezervate pentru declaraţia respectivă.
factor este un număr care indică de câte ori se repetă lista de operanzi care urmează în
paranteze. În particular, drept operand poate fi folosit şi caracterul ? care indică faptul că zona de
date corespunzătoare este rezervată, dar nu şi iniţializată.
Operatorul DUP indică generarea repetată de factor ori a listei de operanzi ce apare între
parantezele de după cuvântul DUP.
Precizăm că datele de tip adresă ce pot fi definite şi prin directivele DW (adresa relativă) şi
DD (pointer) sunt memorate inversat, adică la adresa mai mică - octetul mai puţin semnificativ al
valorii, respectiv la adresa mai mare - octetul mai semnificativ al valorii.
Exemple:
Nume_var Dir Listă operanzi Rezultat (în cod hexazecimal)
DATA_B DB 10, 5, 13h, -5, 'A' ; 0A 05 13 FB 41
DATA_W DW 100, 100h, -5, 'AB' ; 64 00 00 01 FB FF 42 41
DATA_D DD 5*20, 0FCFBh, 'BA' ; 64 00 00 00 FB FC 00 00
; 41 42 00 00

2-10
DB 200 DUP (1) ; Defineşte 200 octeţi iniţializaţi cu 1
DB 50 DUP (1, 0) ; Defineşte 100 octeţi iniţializaţi cu
; 1, 0, 1, 0, . . .
ARRAY1 DB 2 DUP (0, 1, 2, ?) ; Defineşte 8 octeţi iniţializaţi cu
; 0, 1, 2, _, 0, 1, 2, _
ƒ Rezervarea de spaţiu fără iniţializare se face cu caracterul ?, ca în exemplul următor:
ALFA DB ?, ?, ? ; Se rezervă 3 octeţi începând cu adresa ALFA
ARRAY2 DB 100 DUP (?) ; Se rezervă 100 octeţi neiniţializaţi începând
; cu adresa ARRAY2
BETA DW ?, 0AAh ;
ƒ Operatorul DUP poate fi utilizat şi imbricat ca în exemplele:
DB 2 DUP (3 DUP (1)) ; Defineşte 6 octeţi iniţializaţi cu 1
ARRAY3 DB 2 DUP (0, 2 DUP (1, 2), 0, 3) ; Se va genera de 2 ori
; secvenţa 0,1,2,1,2,0,3
Observaţii:
a) Există instrucţiuni care operează atât pe cuvânt, cât şi pe octet. Acest lucru rezultă fie din
modul de adresare, ca în instrucţiunile următoare:
mov ax, [bx] ; Se încarcă registrul AX cu cuvântul de la adresa
; DS*16+BX
mov al, [bx] ; Se încarcă registrul AL cu octetul de la adresa
; DS*16+BX
fie din modul de definire al datei, ca în instrucţiunile următoare:
VAR DB 55h ; Se defineste VAR detip octet
inc VAR ; Se incrementează octetul de la adresa
; DS*16+OFFSET VAR
În cazul instrucţiunii inc [bx], asamblorul nu poate deduce dacă instrucţiunea operează pe
octet sau pe cuvânt. Pentru aceasta trebuie explicitat tipul datei, astfel:
inc BYTE PTR [bx] ; Se incrementează octetul de la adresa [bx]
inc WORD PTR [bx] ; Se incrementează cuvântul de la adresa [bx]
unde s-a utilizat operatorul PTR pentru a preciza tipul datei. De fapt, operatorul PTR se utilizează
pentru a specifica tipul unei date (variabile) sau pentru a modifica temporar tipul unei date
(variabile) sau distanţa unei etichete.

b) Pentru a deosebi modul de adresare intrasegment direct de intersegment direct se


utilizează construcţiile:
jmp FAR PTR etich_indep ; Salt intersegment la instrucţiunea cu
; eticheta etich_indep
jmp NEAR PTR etich_aprop ; Salt intrasegment la instrucţiunea cu
; eticheta etich_aprop
Distincţia între modurile de salt intrasegment indirect şi intersegment indirect se face în
funcţie de tipul operandului ce apare în instrucţiunea de salt şi anume: operand tip cuvânt
însemnează salt intrasegment, iar operand pointer (cuvânt dublu) însemnează salt intersegment.
Exemplu:
jmp WORD PTR [bx] ; Salt intrasegment la instrucţiunea
; cu adresa dată de DS*16+BX
jmp DWORD PTR [bx] ; Salt intersegment la instrucţiunea cu
; adresa dată de pointerul (dublul
; cuvânt) aflat la adresa DS*16+BX

2-11
Descrierea setului de instrucţiuni ale microprocesoarelor I8086/I8088
Pentru prezentarea setului de instrucţiuni ale microprocesoarelor I8086/I8088 utilizăm
următoarele notaţii:
Numele registrelor din UCP I8086/I8088:
¾ AX, BX, CX, DX - registre generale de 16 biţi;
¾ AH, AL, BH, BL, CH, CL, DH, DL - registre generale de 8 biţi;
¾ SP, BP, SI, DI - registre de 16 biţi;
¾ CS, DS, SS, ES - registre de segment;
¾ F (PSW) = x x x x OF DF IF TF | SF ZF x AF x PF x CF - registrul de flaguri.
Referiri generale:
¾ A - acumulator (AX sau AL sau AH, funcţie de context);
¾ R - registru oarecare de uz general: R8 - registru de 8 biţi, R16 - registru de 16 biţi;
¾ M - operand din memorie: M8, M16, M32, unde indicele 8, 16, 32 precizează lungimea în biţi
pentru operanzi cu 1, 2, respectiv 4 octeţi;
¾ SR - registru segment oarecare: CS, DS, SS, ES;
¾ nume_reg - conţinutul numeric al registrului indicat de nume (sursă sau destinaţie);
¾ DATA - operand numeric imediat: DATA8, DATA16 - operand numeric pe 8, respectiv 16
biţi;
¾ DEPL - deplasament (offset) de adresă: DEPL8, DEPL16 - deplasament pe 8, respevtiv 16
biţi;
¾ (EA) - octetul cu adresa de offset egală cu EA;
¾ (EA + 1, EA) - cuvântul cu adresa de offset egală cu EA;
¾ [nume_reg ] - octetul sau cuvântul adresat indirect prin registrul de 16 biţi indicat;
¾ (nume_reg + 1, nume_reg ) - cuvântul adresat indirect prin registrul indicat;
¾ SRC - notaţie generală pentru o sursă de date: DATA8, DATA16, M8, M16, (EA), (EA+1,
EA), nume_reg, [nume_reg ], (nume_reg + 1, nume_reg );
¾ DST - notaţie generală pentru o destinaţie a datelor: M8, M16, (EA), (EA+1, EA), nume_reg,
[nume_reg ], (nume_reg + 1, nume_reg );
¾ EA - adresa efectivă;
¾ FA - adresa fizică.

1. Instrucţiuni pentru transferul datelor


În această categorie se încadrează următoarele tipuri de instrucţiuni: instrucţiuni de transfer
de tip "clasic", instrucţiuni pentru încărcarea adreselor şi instrucţiuni pentru transferul valorilor
indicatorilor de condiţie.
1o. Instrucţiuni de transfer de tip "clasic"
În categoria instrucţiunilor de transfer de tip "clasic" se încadrează următoarele instrucţiuni:
mov DST, SRC
push SRC
pop DST
xchg DST, SRC
xlat
a) Efectul instrucţiunii MOV DST, SRC este de a transfera valoarea desemnată de sursa SRC la
destinaţia DST. Operanzii instrucţiunii MOV pot avea lungimea de 8 sau 16 biţi şi aceştia pot fi:

2-12
registre generale, registre segment, registre pointer şi index, conţinutul unor locaţii de memorie
sau date imediate. În urma execuţiei operaţiei MOV DST, SRC se modifică numai conţinutul
operandului destinaţie, conţinutul operandului sursă rămânând nemodificat. De asemenea,
instrucţiunea MOV nu afectează indicatorii de condiţie. Formele admise de instrucţiunea MOV
sunt:
mov R8, R8 ; R8 <--- R8
mov R16, R16 ; R16 <--- R16
mov SR, R16 ; Conţinutul unui registru de 16 biţi
; se transferă într-un registru segment
; (SR nu poate fi CS)
mov R16, SR ; R16 <--- SR
mov R8, DATA8 ; R8 <--- DATA8
mov M8, DATA8 ; M8 <--- DATA8
mov R16, DATA16 ; R16 <--- DATA16
mov M16, DATA16 ; M16 <--- DATA16
mov R8, M8 ; R8 <--- M8
mov M8, R8 ; M8 <--- R8
mov R16, M16 ; R16 <--- M16
mov M16, R16 ; M16 <--- R16
mov SR, M16 ; SR <--- M16 ; (SR nu poate fi CS)
mov M16, SR ; M16 <---SR
Observaţii:
a. Nu este permisă execuţia unei instrucţiuni MOV de forma:
mov SR, DATA16 ; Încarcă un registru segment cu un
; operand imediat.
; Registrele segment se încarcă numai prin
; intermediul unor registre de 16 biţi
b. Nu se pot transfera direct date între două locaţii de memorie sau între două registre segment.

Exemple de utilizare a instrucţiunilor MOV


t_data SEGMENT ; Segmentul de date
cuvint1 dw 0ffffh
cuvint2 dw 0f0fh
octet1 db 55h
t_data ENDS ; Sfârşitul segmentului de date
stiva SEGMENT STACK ; Segmentul de stivă
DB 256 DUP (?) ; Defineşte spaţiul stivă
s_data EQU $ ; Defineşte vârful stivei
stiva ENDS ; Sfârşitul segmentului de stivă
code SEGMENT ; Numele segmentului de cod
ASSUME cs: code, ds: t_data, ss: stiva ; Asignarea segmentelor
START: ; Modulul principal începe de la locaţia START
mov ax, t_data ; Adresa lui t_data în AX
mov ds, ax
mov ax, stiva ; Adresa lui stack în AX
mov ss, ax
mov sp, OFFSET s_data ; Stabileşte SP
; Transfer imediat de date in registre
mov ax, 0ffffh
mov bl, '0' ; Codul ASCII pe 8 biţi al lui 0 trece în reg. BL

2-13
; Transfer registru - registru (16 biti)
mov bx, ax
mov cx, bx
mov dx, cx
; Transfer registru - registru (8 biti)
mov al, 0 ; Data 0 trece în registrul AL
mov bl, al
mov cl, bl
mov dl, cl
; Transfer registru - memorie
mov ax, cuvint1 ; Conţinutul locaţiei cuvânt1 trece în reg. AX
mov dl, BYTE PTR cuvint2
; Transfer din memorie cu adresare indirecta
mov bx, OFFSET octet1 ; Adresa de offset a variabilei octet1
; trece în reg. BX
mov al, [bx]
; Transfer memorie - memorie (trebuie utilizat un registru in doua etape)
mov bx, cuvint2 ; Următoarele 4 instrucţiuni interschimbă
; între ele conţinutul celor două cuvinte
mov ax, cuvint1 ; din memorie
mov cuvint2, ax
mov cuvint1, bx
mov cx, SIZE cuvint1 ; Mărimea operandului (CX = 2)
mov ah, 4ch ; Revenire în MS-DOS
int 21h
code ENDS ; Sfârşitul segmentului de cod
end START ; Sfârşitul programului
b) Instrucţiunile PUSH şi POP sunt instrucţiuni de lucru cu stiva. Stiva este o zonă specială de
memorie în care se memorează date în ordinea inversă folosirii acestora (este o memorie de tip
LIFO). O astfel de situaţie apare, de exemplu, în cazul salvării şi refacerii contorillor din buclele
incuibate.

Accesul la această zonă se face printr-un registru special numit indicator (pointer) de stivă
SP care este gestionat de procesor prin mecanisme hardware-software. În lucrul cu stiva sunt
permise două operaţii: operaţia de depunere în stivă, PUSH şi operaţia de extragere din stivă,
POP.

2-14
Adresa ultimului element depus în stivă se află totdeauna memorată în SP şi se numeşte
vârful stivei. La microprocesoarele I8086/I8088, adresa fizică a vârfului stivei este dată de
perechea SS:SP.
Conţinutul lui SS dă limita inferioară a stivei, numindu-se baza stivei. Stiva poate fi
considerată ca ocupând zona de memorie limitată inferior de SS*1610 şi superior de SS*1610 +
valoarea iniţială a registrului SP.

¾ Instrucţiunea:
PUSH SRC ; SP <--- SP - 2, (SP + 1, SP) <--- SRC
transferă în vârful stivei cuvântul precizat prin operandul SRC. Se poate utiliza sub forma:
push R16 ; Salvează pe stivă conţinutul unui registru
; de 16 biţi, R16
push M16 ; Salvează pe stivă conţinutul locaţiei
; de memorie având adresa relativă
; precizată în instrucţiune
push SR ; Salvează pe stivă conţinutul
; unui registru segment
La fiecare salvare pe stivă, indicatorul SP se decrementează cu 2.

¾ Instrucţiunea:
POP DST ; DST <--- (SP + 1, SP), SP <--- SP + 2
reface din vârful stivei cuvântul precizat în operandul DST. Se poate utiliza sub forma:
pop R16 ; Reface din stivă conţinutul unui registru
; de 16 biţi, R16
pop M16 ; Reface din stivă conţinutul locaţiei de
; memorie având adresa relativă precizată
; în instrucţiune
pop SR ; Reface din stivă conţinutul unui registru segment
; (SR nu poate fi CS)
La fiecare extragere din stivă, indicatorul SP se incrementează cu 2.
Observaţie: Se poate executa o instrucţiune

2-15
push cs ; Salvare registru segment de cod în stivâ
dar nu se poate executa o instrucţiune
pop cs.
Încărcarea registrului CS prin intermediul stivei se poate face numai executând o
instrucţiune de reîntoarcere dintr-o procedură în context FAR.
ƒ Accesul la informaţiile memorate în stivă se poate face şi fără descărcarea stivei,
utilizând adresarea bazată în felul următor:
; Secvenţă de memorare informaţii în stivă
mov bp, sp ; Se precizează "baza stivei"
push ax ; SP = SP - 2
push bx ; SP = SP - 4
push cx ; SP = SP - 6
; Secvenţă de acces la informaţiile memorate în stivă
mov ax, [bp-2] ; Prima informaţie introdusă în stivă
mov bx, [bp-4] ; A doua informaţie introdusă în stivă
mov cx, [bp-6] ; Ultima informaţie introdusă în stivă
.................................
add sp, 6 ; Se descarcă stiva

c) Instrucţiunea XCHG DST, SRC are ca efect interschimbarea conţinutului sursei cu cel al
destinaţiei. Instrucţiunea poate fi folosită sub forma:
XCHG R8, R8 ; R8 <----> R8
XCHG R8, M8 ; R8 <----> M8
XCHG R16, R16 ; R16 <----> R16
XCHG R16, M16 ; R16 <----> M16
Observaţie: Nu se pot utiliza drept operatori registrele de segment.
Exemplu: Interschimbarea conţinutului a doi operanzi din memorie op1 şi op2 se poate
face prin secvenţa:
mov R, op1
xchg R, op2
mov op1, R
unde R este un registru pe 8 sau 16 biţi, funcţie de lungimea operanzilor.

d) Instrucţiunea XLAT (Translate Byte to AL) translatează (converteşte) valoarea registrului AL,
adică o înlocuieşte cu un octet dintr-un tabel a cărui adresă de început se află în registrul BX.
Indexul în acest tabel este tocmai valoarea lui AL
(AL <--- [BX + AL]).
Exemple:
1. Să considerăm următoarea codificare pentru cifrele zecimale de la 0 la 9 (codul 2 din 5
folosit în telefonie):
0 --> 1 1000 5 --> 0 1010
1 --> 0 0011 6 --> 0 1100
2 --> 0 0101 7 --> 1 0001
3 --> 0 0110 8 --> 1 0010
4 --> 0 1001 9 --> 1 0100
Să presupunem că dorim să convertim cifra 6 într-un cod "2 din 5". Programul trebuie să
conţină instrucţiunile:

2-16
mov bx, OFFSET TABEL ; Se plasează în BX adresa de început a
; tabelei cu codurile "2 din 5"
mov al, 6 ;
xlat ; În AL se va găsi codul cifrei 6, adică 00001100b
Observaţie: Pentru ca instrucţiunile să fie executate este necesar ca tabelul de conversie TABEL
să se afle în segmentul de date curent.
2. Conversia unei valori numerice cuprinsă între 0 şi 15 în cifrele hexazecimale
corespunzătoare, se poate face prin:
tabel DB '0123456789abcdef'
...............
mov bx, OFFSET tabel
mov al, 11
xlat ; În registrul AL se va depune cifra hexazecimală B

2o. Instrucţiuni pentru încărcarea adreselor


Există patru instrucţiuni pentru încărcarea adresei unui operand (nume, variabilă, expresie):
MOV R16, OFFSET operand
LEA R16, operand ; LEA- Load Effective Address
LDS R16, operand ; LDS - Load Data Segment register
LES R16, operand ; LES - Load Extra Segment register
a) Ca efect al execuţiei instrucţiunii:
lea R16, operand
se încarcă în registrul R16, adresa relativă (efectivă) a operandului plasat în segmentul curent de
date care apare în instrucţiune. Această instrucţiune este mai puternică decât instrucţiunea
mov R16, OFFSET operand
deoarece permite şi utilizarea unor registre de bază şi index în formarea adresei.
Exemple:
nume DB 100
lea bx, nume ; Încarcă BX cu adresa de offset a operandului nume
Această instrucţiune este echivalentă cu instrucţiunea:
mov bx, OFFSET nume;
Instrucţiunea:
mov ax, OFFSET table[si];
nu conduce la un rezultat corect, pe când instrucţiunea:
lea ax, table[si]
are ca efect încărcarea în AX a offsetului operandului table + SI
b) Ca efect al execuţiei instrucţiunilor:
lds R16, operand ; R16 <-- (EA+1, EA); DS <-- (EA+3, EA+2)
les R16, operand ; R16 <-- (EA+1, EA); ES <-- (EA+3, EA+2)
se încarcă în registrul DS, respectiv ES şi în registrul R16 specificat în instrucţiune, adresa aflată
în memorie la adresa efectivă EA a operandului referit în instrucţiune. Cei patru octeţi aflaţi în
memorie la această adresă sunt interpretaţi ca o adresă de tip pointer. Astfel, valoarea conţinută în
primii doi octeţi (componenta de offset) se încarcă în registrul R16, iar valoarea conţinută în
următorii doi octeţi (componenta de segment) se încarcă în registrul DS, respectiv ES.

2-17
3o. Instrucţiuni pentru transferul valorilor indicatorilor de condiţie
a) LAHF ; Load AH from Flags
Încarcă în registrul AH octetul inferior al registrului F = (Fhigh, Flow),

astfel:

b) SAHF ; Store AH in Flags


Încarcă în octetul inferior al registrului F, registrul AH , astfel:

c) Instrucţiunea PUSHF (PUSH Flags) salvează în stivă valorile indicatorilor de condiţie:


SP <--- SP - 2; (SP + 1) <--- Fhigh, (SP ) <--- Flow.

d) Instrucţiunea POPF (POP Flags) reface din stivă valorile indicatorilor de condiţie:
Flow <--- (SP), Fhigh <--- (SP + 1); SP <--- SP + 2.
Observaţie: Instrucţiunile LAHF şi PUSHF nu afectează indicatorii de condiţie, iar instrucţiunea
SAHF nu afecteaza flagurile TF, IF, DF şi OF.

2. Instrucţiuni pentru poziţionarea indicatorilor de condiţie


În această categorie se încadrează instrucţiunile:
CLC ; Clear Carry Flag (CF = 0)
STC ; Set Carry Flag (CF = 1)
___
CMC ; Complement Carry Flag (CF = CF )
STD ; Set Direction Flag (DF = 1)
CLD ; Clear Direction Flag (DF = 0)
STI ; Set Interrupt Flag (IF = 1)
; Activează sistemul de întreruperi
CLI ; Clear Interrupt Flag (IF = 0)
; Dezactivează sistemul de întreruperi

2-18
3. Grupul instrucţiunilor aritmetice
3.1. Aritmetica binară
3.1.1. Adunarea şi scăderea binară
Instrucţiunile pentru adunarea şi scăderea binară sunt următoarele:
ADD DST, SRC ; (DST) <--- (DST) + (SRC)
ADC DST, SRC ; (DST) <--- (DST) + (SRC) + (CF)
SUB DST, SRC ; (DST) <--- (DST) - (SRC)
SBB DST, SRC ; (DST) <--- (DST) - (SRC) - (CF)
Pentru instrucţiunile ADD şi ADC sunt permise următoarele tipuri de operanzi:
add | adc R8, R8 ; R8 <--- R8 + R8 | + CF
add | adc R8, M8 ; R8 <--- R8 + M8 | + CF
add | adc M8, R8 ; M8 <--- M8 + R8 | + CF
add | adc R16, R16 ; R16 <--- R16 + R16 | + CF
add | adc R16, M16 ; R16 <--- R16 + M16 | + CF
add | adc M16, R16 ; M16 <--- M16 + R16 | + CF
add | adc R8, DATA8 ; R8 <--- R8 + DATA8 | + CF
add | adc M8, DATA8 ; M8 <--- M8 + DATA8 | + CF
add | adc R16, DATA16 ; R16 <--- R16 + DATA16 | + CF
add | adc M16, DATA16 ; M16 <--- M16 + DATA16 | + CF
Indicatorii afectaţi sunt: AF, CF, PF, SF, ZF, OF
Observaţii:
a. Pentru instrucţiunile SUB (SUBtract) şi SBB SuBtract with Borrow) sunt permise
aceleaşi tipuri de operanzi ca şi la instrucţiunile ADD şi ADC (ADd with Carry);
b. Operaţiile se execută cu operanzi pe 8 sau 16 biţi, cu sau fără semn. Cei doi operanzi
trebuie să aibă aceeaşi dimensiune (acelaşi tip). Numerele fără semn sunt interpretate în notaţie
binară directă, iar numerele cu semn, în complement faţă de 2.
c. Instrucţiunile ADD şi SUB se utilizează pentru efectuarea calculelor cu operanzi în
simplă precizie, adică cu operanzi reprezentaţi pe câte un cuvânt.
Exemplu: Dacă operanzii x, y, z sunt în simplă precizie, următoarea secvenţă de
instrucţiuni calculează valoarea x+y+100-z şi depune rezultatul în w:
mov ax, x
add ax, y
add ax, 100
sub ax, z
mov w, ax
ƒ Dacă pentru reprezentarea operanzilor se utilizează mai multe cuvinte spunem că avem o
reprezentare multiplă precizie. Pentru efectuarea de calcule multiplă precizie se utilizează
instrucţiunile ADC şi SBB.
Exemplu: Secvenţa de instrucţiuni corespunzătoare adunării a două numere scrise în dublă
precizie, plasate la adresele n1_dp şi n2_dp, cu depunerea rezultatului la adresa n3_dp este:
n1_dp DD 12345678h
n2_dp DD 98765432h
rez DD ?
...............
clc
mov ax, WORD PTR n1_dp ; AX <--- c.m.p.s. cuvânt al lui n1_dp

2-19
add ax, WORD PTR n2_dp ; AX <--- AX + c.m.p.s. cuvânt
; al lui n2_dp
mov WORD PTR rez, ax ; c.m.p.s. cuvânt al rezultatului se
; depune la adresa rez
mov ax, WORD PTR n1_dp+2 ; AX <--- c.m.s. cuvânt al lui DP1
adc ax, WORD PTR n2_dp+2 ; AX <--- AX + c.m.s. cuvânt
; al lui DP2
mov rez+2, ax ; c.m.s. cuvânt al rezultatului
; se depune la adresa rez
ƒ În cazul operanzilor cu semn, se pot efectua şi operaţii aritmetice mixte cu numere de
precizii diferite. Pentru aceasta se vor utiliza instrucţiuni pentru extinderea semnului operandului.

3.1.2. Instrucţiuni pentru extinderea semnului operandului


Pentru "ajustarea" lungimii operanzilor cu semn se utilizează două instrucţiuni pentru
extinderea semnului operandului, astfel:
a) CBW ; Convert Byte to Word
Realizează conversia octetului cu semn conţinut în registrul AL, în cuvântul cu semn
conţinut în registrul AX prin extinderea bitului de semn al registrului AL la toţi biţii registrului
AH, astfel: dacă AL7 = 0, atunci AH = 00h, iar dacă AL7 = 1, atunci AH = ffh.
Exemplu: Se doreşte adunarea unui număr reprezentat pe 8 biţi plasat la adresa n1 cu un
număr reprezentat pe 16 biţi plasat la adresa n2, cu depunerea rezultatului la adresa rez. Se poate
utiliza următorul set de instrucţiuni:
n1 DB -45
n2 DW 150
rez DW ?
..............
mov al, n1
cbw ; Se converteşte octetul la cuvânt
add ax, n2
mov rez, ax
b) CWD ; Convert Word to Double word
Realizează conversia cuvântului cu semn conţinut în registrul AX, în dublul-cuvânt cu
semn conţinut în registrele (DX, AX) prin extinderea bitului de semn al registrului AX la toţi biţii
registrului DX, astfel: dacă AX15 = 0, atunci DX = 0000h, iar dacă AX15 = 1, atunci DX = ffffh.
Observaţie: Instrucţiunile CBW şi CWD nu afectează indicatorii de condiţie.
Exemplu: Următoarea secvenţă de program adună un număr plasat în registrul BX
reprezentat în simplă precizie cu un număr în dublă precizie plasat la adresa d_p. Rezultatul se
depune la adresa rez:
d_p DD 12345678h
rez DD ?
...............
clc ; CF = 0
mov bx, 0ABCDh
mov ax, bx ;
cwd ; Se converteşte cuvântul la dublu_cuvânt
add ax, WORD PTR d_p ;
mov WORD PTR rez, ax ;
adc dx, WORD PTR d_p+2 ;
mov WORD PTR rez+2, dx ;

2-20
3.1.3. Alte instrucţiuni ce au legatură cu adunarea şi scăderea binară
3.1.3.1. Instrucţiuni de incrementare şi decrementare
INC DST ; INCrement
(DST) <---- (DST) + 1
Se adună 1 la conţinutul singurului operand, rezultatul depunându-se înapoi în operand.
DEC DST ; DECrement
(DST) <---- (DST) - 1
Se scade 1 din conţinutul singurului operand, rezultatul depunându-se înapoi în operand.
Forme de utilizare:
inc | dec R ; Se incrementează | decrementează conţinutul
; registrului general R unde R poate fi R8 sau R16
inc | dec M ; Se incrementează | decrementează conţinutul locaţiei
; de memorie adresată prin M, unde M poate fi M8
; sau M16.
Indicatorii afectaţi sunt: AF, PF, SF, ZF, OF.
Exemple: inc cx
inc mem_byte[bx]
inc alpha[bx][si]
dec cx
dec al
dec BYTE PTR VAR
dec WORD PTR VAR
Observaţii:
a) Instrucţiunile INC şi DEC nu afectează flagul CF;
b) Instrucţiunile INC şi DEC se execută modulo valoarea lui R sau M. De exemplu, dacă
AL = 0ffh şi se execută inc AL, atunci după execuţia instrucţiunii, AL = 00h. Dacă BX = 0000h
şi se execută dec BX, atunci după execuţia instrucţiunii, BX = 0ffffh.
3.1.3.2. Instrucţiuni de negare
NEG DST ; NEGate
DST <--- - (DST) = (DST)2
Schimbă semnul operandului DST, sau, altfel spus realizează complementarea aritmetică a
acestuia. Forme de utilizare:
neg R ; Se schimbă semnul conţinutului registrului general R,
; unde R poate fi R8 sau R16
neg M ; Se schimbă semnul conţinutului locaţiei de memorie
; adresată prin M, unde M poate fi M8 sau M16.
Exemple:
neg al ; Presupunând că AL = -1 adică 11111111b, instrucţiunea
; neg al, va înscrie în AL valoarea +1, adică 00000001b
neg BYTE PTR VAR
3.1.3.3. Instrucţiuni de comparare
CMP DST, SRC ; CoMPare
(DST) - (SRC)
Se compară, prin scădere, conţinutul operandului sursă cu conţinutul operandului destinaţie,
fără modificarea operanzilor şi fără depunerea rezultatului, dar cu poziţionarea corectă a
indicatorilor de condiţie. Sunt posibile următoarele forme de utilizare:

2-21
cmp R8, R8 ; Se compară conţinutul a două registre generale
; de 8 biţi
cmp R16, R16 ; Se compară conţinutul a două registre generale
; de 16 biţi
cmp R8, M8 ; Se compară conţinutul unui registru general
; de 8 biţi cu conţinutul unei locaţii de memorie
; adresată prin M8
cmp R16, M16 ; Se compară conţinutul unui registru general
; de 16 biţi cu conţinutul unei locaţii de memorie
cmp R8, DATA8 ; Se compară conţinutul unui registru
; de 8 biţi cu un operad imediat pe 8 biţi
cmp R16, DATA16 ;
cmp M8, DATA8 ;
cmp M16, DATA16 ;
Indicatorii afectaţi sunt: AF, CF, PF, SF, ZF, OF.
Observaţie: Instrucţiunnea CMP este urmată, de obicei, de o instrucţiune de salt
condiţionat, care testează bistabilii de condiţie pentru a verifica dacă relaţia din condiţia testată a
fost satisfăcută.
Starea bistabililor de condiţie trebuie interpretată diferit, după cum ceea ce se compară sunt
numere fără semn, sau numere cu semn. Astfel, dacă numerele sunt fără semn:
CF = 0 şi ZF = 0, dacă (DST) > (SRC)
CF = 0 şi ZF = 1, dacă (DST) = (SRC)
CF = 1 şi ZF = 0, dacă (DST) < (SRC)
Pentru numere cu semn:
SF = OF, dacă (DST) > (SRC)
ZF = 1, dacă (DST) = (SRC)
SF OF, ≠ dacă (DST) < (SRC)
Exemple: cmp bx, cx ;
cmp dh, ALPHA ;
cmp [bp+2], si ;
cmp cx, 100h ;
3.1.4. Inmulţirea şi împărţirea binară
Există următoarele instrucţiuni de înmulţire şi împărţire binară:
a) MUL SRC ; MULtiply accumulator by register or memory, unsigned
Conţinutul operandului sursă SRC pe 8 sau 16 biţi este înmulţit cu conţinutul registrului AL
respectiv AX, rezultatul pe 16, respectiv 32 biţi fiind depus în AX, respectiv în perechea (DX,
AX). Operanzii sunt consideraţi numere fără semn. Forme de utilizare:
mul R8 ; (AH, AL) <--- AL * R8
mul M8 ; (AH, AL) <--- AL * M8
mul R16 ; (DX, AX) <--- AX * R16
mul M16 ; (DX, AX) <--- AX * M16
Exemple:
mul bl ; AX <--- AL*BL
mul BYTE PTR ALPHA[si] ; AX <--- AL*(ALPHA[SI])
mul bx ; (DX, AX) <--- AX*BX
mul WORD PTR ALPHA[si] ; (DX, AX) <--- AX*(ALPHA[SI])

2-22
b) IMUL SRC ; Integer MULtiply accumulator by register or memory
Instrucţiunea IMUL are aceleaşi forme ca şi instrucţiunea MUL, deosebirea dintre cele
două instrucţiuni constând în faptul că IMUL operează asupra unor operanzi cu semn.
Exemple:
imul cl ; AX <--- AL*CL
imul BYTE PTR BETA[si] ; AX <--- AL*(BETA[SI])
imul bx ; (DX,AX) <--- AX*BX
imul WORD PTR BETA[si] ; (DX, AX) <--- AX*(BETA[SI])
Observaţie: Pentru o instrucţiune de înmulţire cu semn, dacă octetul (cuvâtul) cel mai
semnificativ al rezultatului nu este extensia de semn al octetului (cuvâtului) cel mai puţin
semnificativ al rezultatului, atunci atât CF cât şi OF vor fi poziţionaţi pe 1, altfel sunt poziţionaţi
pe 0.
Exemplul 1:
n1 DB 20h
n2 DW 200h
rez1 DW ?
rez2 DD ?
...............
mov al, 10h
mul n1 ; Înmulţire pe octet, (AX) <---- (AL)*(n1)
mov rez1, ax
mov ax, 10h
mul n2 ; Înmulţire pe cuvânt, (DX,AX) <---- (AX)*(n2)
mov WORD PTR rez2, ax ;
mov WORD PTR rez2+2, dx ;
Exemplul 2:
⎧18010 in reprezentarea fara semn
Fie: AL = 0B4h = ⎨
⎩− 7610 in reprezentarea cu semn
BL = 11h = 1710 în ambele reprezentări
După execuţia instrucţiunii MUL BL se obţine
AX = (AH,AL) = 0BF4h = 306010 = 180 × 17.
După execuţia instrucţiunii IMUL BL se obţine
AX = (AH,AL) = 0FAF4h = -129210 = -76 ×17.
Cum AH = 0FAh ≠ 0FFh rezultă că CF = OF = 1.
Menţionăm că operaţiile pentru numere cu semn se fac în complement faţă de doi. Astfel,
se calculează mai întâi complementul faţă de doi al numărului 0B4h şi se obţine 4Ch. Se execută
4Ch ×11h şi se obţine 50Ch. Se calculează complementul faţă de 2 al lui 50Ch şi rezultă 0FAF4h
= -129210.
După execuţia instrucţiunilor MUL şi IMUL, valorile flagurilor SF, ZF, AF şi PF sunt
nedefinite.
Instrucţiunilor MUL şi IMUL se pot utiliza şi pentru a efectua calcule în multiplă precizie.
c) DIV SRC ; DIVide, unsigned
Operandul deîmpărţit, adică conţinutul registrului AX pe 16 biţi sau al perechii (DX, AX)
pe 32 biţi se împarte la conţinutul operandului sursă SRC pe 8, respectiv 16 biţi, câtul depunându-
se în registrului AL pe 8 biţi, respectiv în AX pe 16 biţi, iar restul în registrul AH pe 8 biţi,
respectiv în DX pe 16 biţi. Operanzii sunt consideraţi numere fără semn. Forme de utilizare:
div R8 ; AL <--- AX / R8 = cât
; AH <--- (AX) MOD (R8) = rest

2-23
div M8 ; AL <--- AX / M8 = cât
; AH <--- (AX) MOD (M8) = rest
div R16 ; AX <--- (DX, AX) / R16 = cât
; DX <--- (DX, AX) MOD (R16) = rest
div M16 ; AX <--- (DX, AX) / M16 = cât
; DX <--- (DX, AX) MOD (M16) = rest
b) IDIV SRC ; Integer DIVide, signed
Instrucţiunea IDIV are aceleaşi forme ca şi instrucţiunea DIV, deosebirea dintre cele două
instrucţiuni constând în faptul că IDIV operează asupra unor operanzi cu semn. Restul are acelaşi
semn ca şi deîmpărţitul.
Observaţii:
1. După efectuarea operaţiilor de împărţire, indicatorii AF, CF, OF, PF, SF, ZF sunt
nedefiniţi.
2. La obţinerea unui cât care nu încape în destinaţie, eroarea de depăşire conduce la o
întrerupere pe nivel 0 şi rezultat nedefinit:
- Pentru instrucţiunea DIV SRC, depăşirea apare când:
- câtul > 0FFh, dacă împărţirea se face pe octet;
- câtul > 0FFFFh, dacă împărţirea se face pe cuvânt.
- Pentru instrucţiunea IDIV SRC, depăşirea apare când:
- câtul > 07Fh, dacă împărţirea se face pe octet;
- câtul > 07FFFh, dacă împărţirea se face pe cuvânt.
Exemplu: Fie: AX = 400h = 102410 în ambele reprezentări (cu semn şi fără semn)
⎧18010 in reprezentarea fara semn
BL = 0B4h = ⎨
⎩− 7610 in reprezentarea cu semn
Instrucţiunea DIV BL ne conduce la: AL = 05h (câtul); AH = 7Ch = 12410 (restul);
Instrucţiunea IDIV BL ne conduce la: AL = 0F3h = -1310 (câtul); AH = 24h = 3610 (restul).
Observaţie. Instrucţiunile de înmulţire şi împărţire sunt cele mai lente instrucţiuni executate
de microprocesoarele I8086/I8088. Din acest motiv, ori de câte ori este posibil, este de preferat
înlocuirea acestor operaţii prin secvenţe echivalente care să folosească numai operaţii de adunare
şi de deplasare.

3.2. Aritmetica BCD


3.2.1. Aritmetica BCD împachetată
Reprezentarea în cod BCD a numerelor întregi presupune utilizarea unei codificări pe 4 biţi
a fiecărei cifre zecimale. Reprezentarea BCD împachetată realizează depunerea a două cifre
zecimale într-un acelaşi octet, fiecare grup de 4 biţi ce codifică o cifră numindu-se tetradă. Cum
toate operaţiile realizate de ALU-procesor se fac în binar, obţinerea unui rezultat BCD corect se
face efectuând anumite ajustări asupra rezultatului. Ajustările se fac după efectuarea operaţiilor
respective. Instrucţiunile de ajustare sunt următoarele:
a) DAA ; Decimal Adjust after Addition
Instrucţiunea realizează corecţia zecimală a rezultatului obţinut, în registrul AL, după
adunarea a doi operanzi în format BCD împachetat. Rezultatul corect (în format BCD
împachetat) rămâne în AL. Corecţia rezultatului se face în funcţie de valoarea bistabilelor de
condiţie AF şi CF, astfel:
Dacă (AL0-3) > 9 sau AF = 1, atunci
{ (AL) <--- (AL) + 6

2-24
AF <--- 1
}
Dacă (AL4-7) > 9 sau CF = 1, atunci
{ (AL) <--- (AL) + 60h
CF <--- 1
}
b) DAS ; Decimal Adjust after Subtraction
Instrucţiunea realizează corecţia zecimală a rezultatului obţinut, în registrul AL, după
scăderea a doi operanzi în format BCD împachetat. Rezultatul corect (în format BCD împachetat)
rămâne în AL. Corecţia rezultatului se face în funcţie de valoarea bistabilelor de condiţie AF şi
CF, astfel:
Dacă (AL0-3) > 9 sau AF = 1, atunci
{ (AL) <--- (AL) - 6
AF <--- 1
}
Dacă (AL4-7) > 9 sau CF = 1, atunci
{ (AL) <--- (AL) - 60h
CF <--- 1
}
Observaţie. În aritmetica BCD împachetată nu se pot executa direct operaţii de înmulţire şi
împărţire.
Exemple:
- Reprezentare în cod BCD
⎧0001 1010 in binar
Numărul 2610 = ⎨
⎩0010 0110 in cod BCD
a) Adunare în format BCD
a1) 34 = 0011 | 0100 +
25 = 0010 | 0101
--------------------
59 = 0101 | 1001 +
6 = 0000 | 0110 (corecţia)
--------------------
65 = 0101 | 1111 (AF = 0)
Rezultatul 59 este cel corect deoarece după adunarea cifrei 6, indicatorul AF = 0.
a2) 34 = 0011 | 0100 +
29 = 0010 | 1001
--------------------
5? 0101 | 1101 +
6 = 0000 | 0110 (corecţia)
--------------------
63 = 0110 | 0011 (AF = 1)
Rezultatul 63 este corect deoarece după adunarea cifrei 6, indicatorul AF = 1.
b) Scădere în format BCD
b1) 34 = 0011 | 0100 -
29 = 0010 | 1001
--------------------
0? = 0000 | 1011 - (AF = 1)
6 = 0000 | 0110 (corecţia)

2-25
--------------------
5 = 0000 | 0101 (AF = 0)
Rezultatul 5 este corect deoarece după scăderea cifrei 6, indicatorul AF = 0.
b2) 34 = 0011 | 0100 -
30 = 0011 | 0000
--------------------
4 = 0000 | 0100 (AF = 0)
Rezultatul 4 obţinut anterior este corect deoarece după scăderea cifrei 6, indicatorul AF = 1.
c) Fie BCD1 şi BCD2 două numere ce conţin câte 4 cifre zecimale reprezentate în cod
BCD. Următoarea secvenţă calculează BCD1 + BCD2 şi depune rezultatul în BCD3. (Reamintim
că cifra zecimală m.p.s. se memorează la adresa cea mai mică).
...........
clc ; CF = 0
mov al, BYTE PTR BCD1
add al, BYTE PTR BCD2
daa
mov BYTE PTR BCD3, al
mov al, BYTE PTR BCD1+1
adc al, BYTE PTR BCD2+1
daa
mov BYTE PTR BCD3+1, al

3.2.2. Aritmetica BCD neîmpachetată


O altă reprezentare a numerelor decât cea binară şi în cod BCD împachetat este
reprezentarea în cod BCD neîmpachetat (despachetat), conţinând numai o cifră pe octet. Cifră
este conţinută în cei mai puţin semnificativi 4 biţi ai octetului, restul biţilor neinfluenţând
valoarea numărului reprezentat. Cel mai uzual exemplu de reprezentare în cod BCD neîmpachetat
este codul ASCII în care, pentru reprezentarea cifrelor, cei mai semnificativi 4 biţi au valoarea
0011b = 310. La efectuarea operaţiilor de adunare, scădere, înmulţire şi împărţire cu operanzi în
format BCD despachetat (în cod ASCII) sunt necesare următoarele corecţii, astfel:
a) AAA ; ASCII Adjust after Addition
Instrucţiunea realizează corecţia zecimală a rezultatului obţinut, în registrul AL, după
adunarea a doi operanzi în format BCD neîmpachetat. Rezultatul corect, în format BCD
neîmpachetat este depus în registrele AH şi AL, astfel:
Dacă (AL0-3) > 9 sau AF = 1, atunci
{ (AL) <--- (AL) + 6
(AH) <--- (AH) + 1
AF <--- 1
CF <--- 1
(AL) <--- (AL) AND 0Fh
}
b) AAS ; ASCII Adjust after Subtraction
Instrucţiunea realizează corecţia zecimală a rezultatului obţinut, în registrul AL, după
scăderea a doi operanzi în format BCD neîmpachetat. Rezultatul corect, în format BCD
neîmpachetat este depus în registrele AH şi AL, astfel:
Dacă (AL0-3) > 9 sau AF = 1, atunci
{ (AL) <--- (AL) - 6
(AH) <--- (AH) - 1

2-26
AF <--- 1
CF <--- 1
(AL) <--- (AL) AND 0Fh
}
c) AAM ; ASCII Adjust after Multiplication
Instrucţiunea realizează corecţia zecimală a rezultatului obţinut, în registrul AL, după
înmulţirea a doi operanzi în format BCD neîmpachetat. Înmulţirea se face cu MUL, iar rezultatul
corect, în format BCD neîmpachetat este depus în registrele AH şi AL, astfel:
(AH) <--- (AL) / 10
(AL) <--- (AL) MOD 10
Exemplu: mov al, 7
mov bl, 9
mul bl ; În AX se va obţine valoare 003Fh
aam ; În AX se va obţine valoare 0603 (rezultat corect)
d) AAD ; ASCII Adjust before Division
Instrucţiunea realizează corecţia zecimală a deîmpărţitului înaintea împărţirii a doi operanzi
în format BCD neîmpachetat. Împărţirea se face cu DIV, rezultatul din AL corectat, în format
BCD neîmpachetat fiind depus în registrele AH şi AL, astfel:
(AL) <--- (AH) * 10 +(AL)
(AH) <--- 0
Exemplu: Următoarea secvenţă de program calculează expresia UP1+UP2-UP3, numerele
fiind reprezentate pe câte 2 cifre zecimale în aritmetica BCD neîmpachetată, rezultatul
depunându-se în registrul DX:
mov al, BYTE PTR UP1 ; C.m.p.s. cifră a lui UP1 în AL
add al, BYTE PTR UP2 ; C.m.p.s. cifră a lui UP1+UP2 în AL
aaa ; Corecţie BCD
mov dl, al ; C.m.p.s. cifră a lui UP1+UP2 în DL
mov al, BYTE PTR UP1+1 ; C.m.s. cifră a lui UP1 în AL
adc al, BYTE PTR UP2+1 ; C.m.s. cifră a lui UP1+UP2 în AL
aaa ; Corecţie BCD
xchg al, dl ; C.m.p.s. cifră a lui UP1+UP2 în AL
; C.m.s. cifră a lui UP1+UP2 în DL
sub al, BYTE PTR UP3 ;
aas ; C.m.p.s. cifră a lui UP1+UP2-UP3 în AL
xchg al,dl ; C.m.s. cifră a lui UP1+UP2 în AL
; C.m.p.s. cifră a lui UP1+UP2-UP3 în DL
sbb al, BYTE PTR UP3+1 ;
aas ; C.m.s. cifră a lui UP1+UP2-UP3 în AL
mov dh, al ; C.m.s. cifră a lui UP1+UP2-UP3 în DH
Observaţie. Deoarece se lucrează implicit cu registrul AL, se observă că la fiecare pas se tratează
câte o singură cifră.

2-27
4. Grupul instrucţiunilor de salt
Instrucţiunile de salt se împart în două categorii: instrucţiuni de salt necondiţionat şi
instrucţiuni de salt condiţionat.
4.1. Instrucţiuni de salt necondiţionat
Există următoarele instrucţiuni de salt necondiţionat:
a) Intra-segment
1. JMP SHORT [PTR] etichetă ; Salt direct scurt intra-segment
2. JMP etichetă ; Salt direct intra-segment apropiat (etichetă este
; definită în interiorul segmentului curent ca NEAR)
JMP NEAR PTR etichetă ; Salt direct apropiat intra-segment
3. JMP R16 ; Salt indirect intra-segment la adresa de offset
; conţinută în registrul R16
4. JMP WORD PTR operand ; Salt indirect intra-segment la adresa de
; offset specificată prin contextul lui operand
Exemplu: jmp WORD PTR [bx] [di] ;
jmp TABLE [bx] ;
Observaţie: Dacă eticheta la care se face referirea se găseşte textual înainte de instrucţiunea de
salt, atunci asamblorul "ştie" să genereze corect o instrucţiune scurtă. În cazul în care eticheta la
care se face referirea se găseşte textual după instrucţiunea de salt este necesară specificarea
explicită a formei scurte de salt:
alfa: mov ax, 5
---------------
jmp alfa
---------------
jmp SHORT beta
beta: add ax, cx
b) Inter-segment
1. JMP etichetă ; Salt direct îndepărtat (în alt segment) la
; operatorul etichetă
; (eticheta a fost definită ca FAR (instrucţiunea ocupă 5 octeţi))
2. JMP FAR PTR etichetă ; Salt direct inter-segment la operatorul
; etichetă
; (etichetă a fost definită ca NEAR în segmentul în
; care se face saltul)
3. JMP DWORD PTR operand ; Salt indirect inter-segment,
; adresa de salt (SEGMENT:OFFSET), fiind specificată
; prin conţinutul lui operand
Exemplu: jmp DWORD PTR [bx] ;
Semnificaţii:
Jmp de tip SHORT ; (IP) <--- (IP) + distanţa dintre offsetul
; instrucţiunii curente şi cel al operandului
Jmp de tip NEAR ; (IP) <--- Offsetul adresei operandului
Jmp de tip FAR ; (IP) <--- Offsetul adresei operandului
; (CS) <--- Segmentul adresei operandului

2-28
4.2. Instrucţiuni de salt condiţionat
Instrucţiunile de salt condiţionat se folosesc, de obicei, împreună cu instrucţiunile de
comparare (CMP DST, SRC), care determină relaţia dintre două numere.
În prima etapă, instrucţiunea CMP execută o scădere a celor două numere (DST)-(SRC),
fără depunerea rezultatului, dar cu modificarea corespunzătoare a fanioanelor de condiţie
conform operaţiei efectuate.
În a doua etapă, instrucţiunea de salt condiţionat, testează condiţia specificată (bistabilul de
condiţie), vezi Fig. 4.1, efectuând saltul numai în situaţia în care condiţia este adevărată, în caz
contrar trecând la instrucţiunea următoare.

Observaţie: Toate instrucţiunile de salt condiţionat au lungimea de 2 octeţi, primul octet


fiind codul operaţiei, iar cel de-al doilea, un deplasament de 8 biţi reprezentat în complement faţă
de 2.
Dacă se execută saltul, adresa efectivă de salt se determină efectuând suma dintre
conţinutul actual al registrului IP şi un deplasament cu semn pe 8 biţi, care prin extindere de semn
devine un deplasament pe 16 biţi. Deoarece instrucţiunile de salt au o distanţă de salt limitată de
intervalul [-128, +127], saltul la o instrucţiune din afara acestui domeniu se poate realiza prin
efectuarea unui salt condiţionat urmat de un salt necondiţionat la instrucţiunea dorită.
Observaţie: Trebuie făcută distincţia între "mai mare" şi "mai mic" în cazul numerelor cu semn şi
fără semn. Astfel, dacă se compară două numere cu semn, se folosesc termenii "less than" (mai
mic decât) şi "greater than" (mai mare decât), iar dacă se compară două numere fără semn, se
folosesc termenii "below" (inferior, sub) şi "above" (deasupra, peste, superior).
Există următoarele instrucţiuni de salt condiţionat:
a) Pentru numere cu semn:
1. JL / JNGE etichetă ; Jump if less / not greater nor equal ; (SF ⊕ OF) = 1
Salt dacă DST < SRC
2. JLE / JNG etichetă ; Jump if less or equal / not greater ; ((SF ⊕ OF) ∪ ZF) = 1
Salt dacă DST ≤ SRC
3. JNL / JGE etichetă ; Jump if not less / greater or equal ; (SF ⊕ OF) = 0
Salt dacă DST ≥ SRC
4. JNLE / JG etichetă ; Jump if not less nor equal / greater ; ((SF ⊕ OF) ∪ ZF) = 0
Salt dacă DST > SRC
5. JNO etichetă ; Jump if no overflow (OF = 0)
Salt dacă nu există depăşire
6. JO etichetă ; Jump if overflow (OF = 1)
Salt dacă există depăşire

2-29
7. JS etichetă ; Jump if sign (SF = 1)
Salt dacă numărul este negativ
8. JNS etichetă ; Jump if not sign (SF = 0)
Salt dacă numărul este pozitiv
b) Pentru numere fără semn
9. JB / JNAE / JC etichetă ; Jump if below / not above nor equal / carry (CF = 1)
Salt dacă DST < SRC
10. JBE / JNA etichetă ; Jump if below or equal / not above (CF ∪ ZF) = 1
Salt dacă DST ≤ SRC
11. JNB / JAE / JNC etichetă ; Jump if not below / above or equal / not carry (CF = 0)
Salt dacă DST ≥ SRC
12. JNBE / JA etichetă ; Jump if not below nor equal / above (CF ∪ ZF) = 0
Salt dacă DST > SRC
c) Alte categorii
13. JC etichetă ; Jump if carry set (CF = 1)
Salt dacă flagul CF a fost setat
14. JNC etichetă ; Jump if no carry (CF = 0)
Salt dacă flagul CF nu a fost setat
15. JZ / JE etichetă ; Jump if zero / equal (ZF = 1)
Salt dacă DST = SRC
16. JNZ / JNE etichetă ; Jump if not zero / not equal (ZF = 0)
Salt dacă DST ≠ SRC
17. JP / JPE etichetă ; Jump if parity / parity even (PF = 1)
Salt dacă paritate pară
18. JNP / JPO etichetă ; Jump if no parity / parity odd (PF = 0)
Salt dacă paritate impară
19. JCXZ etichetă ; Jump if CX = 0
Salt la etichetă dacă CX = 0, unde etichetă ∈ [-128, 127] faţa de (IP).
Exemplu: Dacă se lucrează cu numere fără semn, atunci după execuţia instrucţiunilor:
mov ax, 0FFFFh
mov bx, 2
cmp ax, bx
ja Etic
se va produce saltul la eticheta Etic, deoarece 0FFFFh > 2.
Dacă se lucrează cu numere cu semn, atunci după execuţia instrucţiunilor
mov ax, 0FFFFh
mov bx, 2
cmp ax, bx
jg Etic
nu se va produce saltul la eticheta Etic, deoarece 0FFFFh < 2.

2-30
4.3. Instrucţiuni pentru controlul ciclurilor (Bucle)
Schema de construcţie a buclelor cu test final este următoarea:

Dacă drept numărător se utilizează registrul CX, iar variabila N conţine numărul de repetiţii
(iteraţii) schema devine:

Instrucţiunea LOOP a fost gândită pentru a simplifica această scriere. Astfel rescrierea
secvenţei anterioare cu instrucţiunea LOOP este următoarea:

Există următoarele instrucţiuni de buclare:


1. LOOP etichetă ; Loop until count complete
Se execută salt repetat la operandul etichetă atât timp cât conţinutul registrului CX este
nenul. Instrucţiunea funcţionează după structura din Fig. 4.2.

CX <--- CX -1

Execută instrucţiunea DA NU Salt la etichetă


următoare CX = 0 IP < --- IP + DEPL8

Figura 4.2.

2-31
2. LOOPZ/LOOPE etichetă ; Conditional LOOP
Se execută salt repetat la operandul etichetă atât timp cât conţinutul registrului CX este
nenul şi indicatorul de condiţie ZF = 1. Instrucţiunea funcţionează după structura din Fig. 4.3.

CX <--- CX -1

DA NU
CX = 0

Execută instrucţiunea DA
ZF = 1
următoare NU
Salt la etichetă
IP < --- IP + DEPL8

Figura 4.3.
3. LOOPNZ/LOOPNE etichetă
Se execută salt repetat la operandul etichetă atât timp conţinutul registrului CX este nenul
şi indicatorul de condiţie ZF = 0. Instrucţiunea funcţionează după o structură identică cu cea din
Fig. 4.3, singura diferenţă fiind că se testează ZF = 0 în loc de ZF = 1.
În continuare sunt prezentate câteva exemple de utilizare a instrucţiunilor prezentate.
Exemplul 1. Următoarea secvenţă de program adună conţinutul a M cuvinte din memorie
plasate începând de la adresa ARRAY şi depune rezultatul în variabila TOTAL.
mov cx, M ; În CX se introduce numărul
; cuvintelor de adunat
mov ax, 0
mov si, ax
START_LOOP: add ax, ARRAY[si]
add si, 2
loop START_LOOP
mov TOTAL, ax
Exemplul 2. Suma a n octeţi plasaţi în memorie la adresa sir
sir DB 3, 5, 9, -10, 7, -11, 20
n EQU ($ - sir) / TYPE sir ; TYPE operand - precizează
; numărul de octeţi ai tipului variabilei operand
suma DB ?
.....................
xor al, al ; AL = 0
mov cx, n ; CX <--- n
xor si, si ; SI = 0
repeta:
add al, sir[si]
inc si
LOOP repeta
mov suma, al
Exemplul 3. Un exemplu în care apare necesitatea testării a 2 condiţii înaintea repetării buclei îl
reprezintă căutarea unui element într-un vector.

2-32
Presupunem că ASCII_SIR reprezintă un şir de caractere. Se pune problema căutării unui
blanc (spaţiu) în acest şir. Dacă nu se găseşte nici un blanc, se execută salt la eticheta
NU_GASIT. Lungimea şirului este dată prin variabila L. Secvenţa de program este următoarea:
ASCII_SIR DB 'Acesta este un sir'
L EQU $ - sir
contor1 DB 0
contor2 DB ?
........................
mov cx, L
mov si, -1
mov al, ' ' ; În AL se introduce codul ASCII al blancului
NEXT: inc si
cmp al, ASCII_SIR[si]
loopne NEXT
jcxz NU_GASIT
GASIT: inc contor1
jmp NEXT
NU_GASIT: mov contor2, 0

5. Grupul instrucţiunilor logice


5.1. Instrucţiuni logice
Microprocesorul I8086/I8088 poate realiza cinci instrucţiuni logice: NOT, AND, OR, XOR
şi TEST.
a) Instrucţiunea:
NOT DST ; Logical NOT
_____
realizează negarea logică (complementul faţă de 1) al operandului DST (DST <--- DST ). Forme
de utilizare:
not R ; R <--- R unde R poate fi R8 sau R16
not M ; M <--- M unde M poate fi M8 sau M16
Instrucţiunea nu afectează fanioanele de condiţie.
b) Instrucţiunile
AND DST, SRC ; (DST) <--- (DST) ∩ (SRC) ; Logical AND
OR DST, SRC ; (DST) <--- (DST) ∪ (SRC) ; Logical OR
XOR DST, SRC ; (DST) <--- (DST) ∀ (SRC) ; Exclusive OR
realizează operaţiile logice SI, SAU şi SAU EXCLUSIV, bit cu bit, între conţinutul operandului
sursă SRC şi conţinutul operandului destinaţie DST, rezultatul depunându-se în destinaţia DST,
sursa nefiind afectată. Pentru aceste instrucţiuni sunt permise următoarele tipuri de operanzi:
and | or | xor R8, R8 ; R8 <--- R8 ∩ | ∪ | ∀ R8
and | or | xor R8, M8 ; R8 <--- R8 ∩ | ∪ | ∀ M8
and | or | xor M8, R8 ; M8 <--- M8 ∩ | ∪ | ∀ R8
and | or | xor R16, R16 ; R16 <--- R16 ∩ | ∪ | ∀ R16
and | or | xor R16, M16 ; R16 <--- R16 ∩ | ∪ | ∀ M16
and | or | xor M16, R16 ; M16 <--- M16 ∩ | ∪ | ∀ R16
and | or | xor R8, DATA8 ; R8 <--- R8 ∩ | ∪ | ∀ DATA8
and | or | xor M8, DATA8 ; M8 <--- M8 ∩ | ∪ | ∀ DATA8

2-33
and | or | xor R16, DATA16 ; R16 <--- R16 ∩ | ∪ | ∀ DATA16
and | or | xor M16, DATA16 ; M16 <--- M16 ∩ | ∪ | ∀ DATA16
Observaţie: După execuţia instrucţiunilor AND, OR, XOR, întotdeauna: CF = 0 , OF = 0. Alţi
indicatori afectaţi: SF, ZF, PF. Indicatorul AF este nedefinit.
c) Instrucţiunea:
TEST DST, SRC ; DST ∩SRC; TEST
combină proprietăţile instrucţiunilor AND şi CMP, astfel: ca şi o instrucţiune AND, TEST
realizează operaţia logică SI între biţii corespunzători ai sursei SRC şi destinaţiei DST, fără
înscrierea rezultatului; ca şi o instrucţiune CMP, TEST poziţionează în mod corespunzător
rezultatului obţinut bistabilii de condiţie, cu excepţia flagurilor CF şi OF care se poziţionează pe
0.
Cel mai des, instrucţiunile logice se utilizează pentru setarea, resetarea (ştergerea),
complementarea sau testarea selectivă ai unor biţi ai operandului destinaţie în funcţie de forma
operandului sursă. În astfel de operaţii, operandul sursă se numeşte mască, iar operaţia se
numeşte operaţie de mascare.
Setarea (punerea pe 1) selectivă a unor biţi se face cu instrucţiunea OR, resetarea (punerea
pe 0) selectivă a unor biţi se face cu instrucţiunea AND, iar complementarea selectivă se
realizează cu XOR.
Testarea selectivă a unor biţi se realizează cu instrucţiunea TEST.
Exemplu: Următoarea secvenţă de program realizează un salt la etichetele TASK1, respectiv
TASK2 sau TASK3, funcţie de valoarea biţilor registrului AX, în următoarele condiţii:
a) Dacă biţii 1 şi 14 sau 7 şi 9 sunt setaţi, salt la TASK1;
b) Dacă nu se face saltul la TASK1 şi biţii 3 sau 4 sunt setaţi, salt la TASK3;
c) Altfel, salt la TASK2.

Secvenţa de program este următoarea:


not ax ; Se neagă AX, deci şi biţii 1 şi 14 şi 7 şi 9
test ax, 4002h ; Se testează dacă biţii 1 şi 14 au valoarea 1
jz TASK1 ; Dacă da, salt La TASK1
test ax, 0280h ; Se testează dacă biţii 7 şi 9 au valoarea 1
jz TASK1 ; Dacă da, salt La TASK1
not ax ; Se revine la valoarea iniţială a lui AX
test ax, 0018h ; Se testează dacă biţii 3 sau 4 au valoarea 1
jnz TASK3 ; Dacă da, salt La TASK3
TASK2: ------------------
------------------
------------------
TASK1: ------------------
------------------
------------------
TASK3: ------------------
------------------

2-34
------------------
Instrucţiunile logice pot fi utilizate şi pentru simularea unor scheme logice combinaţionale.

5.2. Instrucţiuni logice pentru deplasare şi rotaţie


Instrucţiunile de deplasare şi rotaţie lucrează pe octeţi sau cuvinte. Deplasarea (logică sau
aritmetică) sau rotaţia spre stânga sau spre dreapta se poate efectua cu o singură poziţie (un bit)
sau cu un număr de poziţii (biţi) specificat în registrul CL.
Există următoarele instrucţiuni de deplasare şi de rotaţie:
a) SHL DST, 1 ; Deplasare logică stânga a operandului DST cu 1 poziţii
SHL DST, CL ; Deplasare logică stânga a operandului DST cu (CL) poziţii
Observaţie: Pentru toate instrucţiunile din acest paragraf, DST poate fi conţinutul unui registru
general pe 8 sau 16 biţi, R8 respectiv R16 sau conţinutul unei locaţii de memorie de 8 sau 16 biţi,
M8 respectiv M16 .
Forme de utilizare:
SHL R, 1 ; R <---- R*2
SHL M, 1 ; M <---- M*2
După execuţia instrucţiunii, flagul CF va conţine bitul c.m.s. al registrului R sau locaţiei de
memorie M.
SHL R, CL ; R <---- R*2(CL)
SHL M, CL ; M <---- M*2(CL)
După execuţia instrucţiunii, flagul CF va conţine ultimul bit deplasat spre stânga alregistrului R
sau locaţiei de memorie M.
b) SHR DST, 1 ; Deplasare logică dreapta a operandului DST cu 1 poziţii
SHR DST, CL ; Deplasare logică dreapta a operandului DST cu (CL) poziţii
Forme de utilizare:
SHR R, 1 ; R <---- R/2
SHR M, 1 ; M <---- M/2
După execuţia instrucţiunii, flagul CF va conţine bitul c.m.p.s. al registrului R sau locaţiei de
memorie M.
Exemplu: Dacă AL = 00001011b = 11, după execuţia execuţiei shr al,1 flagul CF = 1, iar AL =
00000101b.
SHR R, CL ; R <---- R/2(CL)
SHR M, CL ; M <---- M/2(CL)
După execuţia instrucţiunii, flagul CF va conţine ultimul bit deplasat spre dreapta al registrului R
sau locaţiei de memorie M.
c) SAL DST, 1 ; Deplasare aritmetică stânga a operandului DST cu 1 poziţii
SAL DST, CL ; Deplasare aritmetică stânga a operandului DST cu (CL) poziţii
Observaţie: Instrucţiunea SAL DST, 1 (CL) este analoagă instrucţiunii SHL DST, 1 (CL).
d) SAR DST, 1 ; Deplasare aritmetică dreapta a operandului DST cu 1 poziţii
SAR DST, CL ; Deplasare aritmetică dreapta a operandului DST cu (CL) poziţii
Observaţie: Instrucţiunea SAR DST, 1 (CL) este analoagă instrucţiunii SHR DST, 1 (CL) cu
precizarea că aceasta din urmă se aplică operanzilor cu semn (din această cauză, semnul
operandului se păstrează).
e) ROL DST, 1 ; Rotire la stânga (cu carry) a operandului DST cu 1 poziţii
ROL DST, CL ; Rotire la stânga (cu carry) a operandului DST cu (CL) poziţii

2-35
Forme de utilizare:
ROL R, 1 ;
ROL M, 1 ;
Bitul c.m.s. al registrului R sau a locaţiei de memorie M se deplasează în flagul CF şi în poziţia
bitului c.m.p.s. al registrului R sau a locaţiei de memorie M.
ROL R, CL ;
ROL M, CL ;
După execuţia instrucţiunii, flagul CF precum şi bitul c.m.p.s. al registrului R sau a locaţiei de
memorie M va conţine ultimul bit deplasat spre stânga al registrului R sau locaţiei de memorie M.
f) ROR DST, 1 ; Rotire la dreapta (cu carry) a operandului DST cu 1 poziţii
ROR DST, CL ; Rotire la dreapta (cu carry) a operandului DST cu (CL) poziţii
Forme de utilizare:
ROR R, 1 ;
ROR M, 1 ;
Bitul c.m.p.s. al registrului R sau a locaţiei de memorie M se deplasează în flagul CF şi în poziţia
bitului c.m.s. al registrului R sau a locaţiei de memorie M.
ROR R, CL ;
ROR M, CL ;
După execuţia instrucţiunii, flagul CF precum şi bitul c.m.s. al registrului R sau a locaţiei de
memorie M va conţine ultimul bit deplasat spre dreapta al registrului R sau a locaţiei de memorie
M.
g) RCL DST, 1 ; Rotire la stânga prin carry a operandului DST cu 1 poziţii
RCL DST, CL ; Rotire la stânga prin carry a operandului DST cu (CL) poziţii
Forme de utilizare:
RCL R, 1 ;
RCL M, 1 ;
Bitul c.m.s. al registrului R sau a locaţiei de memorie M se deplasează în flagul CF, iar vechiul
conţinut al lui CF se deplasează în poziţia bitului c.m.p.s. al registrului R sau a locaţiei de
memorie M.
RCL R, CL ;
RCL M, CL ;
După execuţia instrucţiunii, flagul CF va conţine ultimul bit deplasat spre stânga al registrului R
sau locaţiei de memorie M, iar CF se deplasează în poziţia bitului c.m.p.s. al registrului R sau a
locaţiei de memorie M.
h) RCR DST, 1 ; Rotire la dreapta prin carry a operandului DST cu 1 poziţii
RCR DST, CL ; Rotire la dreapta prin carry a operandului DST cu (CL) poziţii
Forme de utilizare:
RCR R, 1 ;
RCR M, 1 ;
Bitul c.m.p.s. al registrului R sau a locaţiei de memorie M se deplasează în flagul CF, iar vechiul
conţinut al lui CF se deplasează în poziţia bitului c.m.s. al registrului R sau a locaţiei de memorie
M.
ROR R, CL ;
ROR M, CL ;
După execuţia instrucţiunii, flagul CF va conţine ultimul bit deplasat spre dreapta al registrului R
sau a locaţiei de memorie M, iar CF se deplasează în poziţia bitului c.m.s. al registrului R sau a
locaţiei de memorie M.

2-36
Observaţii:
a. Instrucţiunile de deplasare logică şi aritmetică afectează toţi indicatorii de condiţie;
b. Instrucţiunile de rotire afectează numai fanioanele CF şi OF.
Cei opt operatori de mai sus sunt sugestiv prezentaţi în Fig. 5.1.

Figura 5.1.

Exemplul 1: Următoarea secvenţă de program realizează conversia unui număr reprezentat în


format BCD neîmpachetat, având 16 cifre zecimale, în format împachetat. Precizăm că numărul
neîmpachetat se află memorat începând de la adresa UNPCK, iar cel împachetat, începând de la
adresa PCK.
UNPCK DB 1,2,4,0,7,8,9,0,6,7,9,1,2,5,8,3
PCK DB 8 DUP (?)
...........................

2-37
mov dx, 8 ; DX conţine numărul cuvintelor cu
; numere neîmpachetate
mov cl, 4
mov si, 0 ; SI = 0
mov di, si ; DI = 0
CONVERT: mov ax, WORD PTR UNPCK[si] ; În AX se încarcă câte
; două cifre zecimale neîmpachetate
shl al, cl ; Cifra zecimală mai puţin semnificativă se
; deplasează în tetrada superioară a registrului AL
shr ax, cl ; În registrul AL se împachetează 2 cifre zecimale
mov PCK[di], al ; Se memorează, pe un singur octet,
; 2 cifre zecimale
add si, 2 ; Se trece la cifrele următoare
inc di, 1 ;
dec dx
jnz CONVERT

6. Grupul instrucţiunilor pe şiruri de caractere


Pentru toate instrucţiunile pe şiruri de caractere, se consideră că şirul sursă este conţinut în
segmentul curent de date (a cărui adresă de început este conţinută în registrul DS), iar adresa
relativă a şirului în segment este conţinută în registrul SI.
Şirul destinaţie este conţinut în segmentul de date suplimentare (a cărui adresă de început
este conţinută în registrul ES), iar adresa relativă a şirului în segment este conţinută în registrul
DI. Pentru şirul sursă se poate considera şi alt registru de segment utilizând un prefix de registru
adecvat (ES, CS sau SS).
Flagul DF indică sensul de parcurgere în memorie al şirurilor sau, altfel spus, modul în care
se actualizează registrele SI şi DI după execuţia operaţiei. Astfel, dacă flagul DF are valoarea
zero, atunci se consideră că şirurile se vor parcurge de la adrese mici către adrese mari.
Actualizarea registrelor SI şi DI se face prin incrementarea acestora cu 1 sau cu 2 după cum se
execută o operaţie care implică un octet sau un cuvânt. Dacă flagul DF are valoarea unu, atunci se
consideră că şirurile se vor parcurge de la adrese mari către adrese mici. Actualizarea registrelor
SI şi DI se face prin decrementarea acestora cu 1 sau cu 2 după cum se execută o operaţie care
implică un octet sau un cuvânt.
Operaţiile elementare pe şiruri de caractere sunt:
1. LODS SRC ; Load String
LODSB (LODSW) SRC
Instrucţiunea încarcă fiecare octet (cuvânt) din şirul sursă SRC adresat prin DS:SI în registrul AL
(AX), cu actualizarea corespunzătoare a registrului SI. Conţinutului şirului sursă nu se modifică.
2. STOS DST ; Store String
STOSB (STOSW) DST
Instrucţiunea memorează conţinutul registrului AL (AX) în octetul (cuvântul) din şirul destinaţie
DST adresat prin ES:DI, cu actualizarea corespunzătoare a registrului DI. Conţinutul registrului
AL (AX) nu se modifică.
Exemplu: STOSB ; Memorează conţinutul registrului AL la adresa
; ES:DI şi incrementează conţinutul lui DI cu 1
STOSW ; Memorează conţinutul registrului AX la adresa
; ES:DI şi incrementează conţinutul lui DI cu 2

2-38
3. MOVS DST, SRC ; Move String
MOVSB (MOVSW) DST, SRC
Transferă un octet (o pereche de octeţi) din şirul sursă SRC adresat prin DS:SI în octetul
(perechea de octeţi) din şirul destinaţie DST adresat prin ES:DI, cu actualizarea corespunzătoare
a registrelor index SI şi DI. Conţinutului şirului sursă nu se modifică.
Observaţie: Este clar că înaintea operaţiei de transfer trebuie încărcate în registrele SI şi DI
adresele de început ale celor două şiruri (sursă, respectiv destinaţie), iar în CX numărul
elementelor ce trebuie transferate. Pentru claritate prezentăm următoarele exemple:
Exemplul 1. Mutarea unui bloc de memorie de la o adresă sursă la o adresă destinaţie. Vom
prezenta o primă variantă a acestei probleme care nu utilizează primitivele pentru şiruri.
DATA SEGMENT
sir1 DB 100 DUP(7)
sir2 DB 100 DUP(?)
DATA ENDS
CODE SEGMENT
ASSUME cs: CODE, ds: DATA
start: mov ax, DATA
mov ds, ax ; Atenţie ! Când nu se utilizează primitivele
; MOVSB sau MOVSW, ambele şiruri (sursă şi
; destinaţie) se pot găsi în acelaşi segment (de
; exemplu, segmentul de date)
mov si, OFFSET sir1
mov di, OFFSET sir2
mov cx, LENGTH sir1
cld ; Sterge DF (DF = 0)
muta: mov al, [si]
mov [di], al
inc si
inc di
loop muta
SF: mov ax, 4c00h
int 21h
CODE ENDS
END start
Exemplul 2. Varianta care utilizeaza primitiva movs este urmatoarea:
DATA SEGMENT
sir1 DB 100 DUP(7)
sir2 DB 100 DUP(?)
DATA ENDS
CODE SEGMENT
ASSUME cs: CODE, ds: DATA
start: mov ax, DATA
mov ds, ax
mov es, ax ; Atenţie ! Când se utilizează MOVSB sau
; MOVSW, registrul DI se foloseşte numai cu
; segmentul adresat prin ES
mov si, OFFSET sir1
mov di, OFFSET sir2

2-39
mov cx, LENGTH sir1
cld ; Sterge DF (DF = 0)
muta: movs sir2, sir1 ; sau movsb ; Se recomandă utilizarea
; lui MOVSB
loop muta
SF: mov ax, 4c00h
int 21h
CODE ENDS
END start
Exemplul 3. În general, transferul unui bloc de date de la o adresă la alta se face astfel:
................
mov ax, extra_sgm ; Se încarcă registrul ES cu adresa de bază
mov es, ax ; a segmentului de date suplimentare
mov si, OFFSET SRC
mov di, OFFSET DST
mov cx, numar_elemente
cld ; DF = 0 - şirurile se vor parcurge în sens crescător
MUTA: movsb ; Transferul octeţilor de la sursa SRC la destinaţia
loop MUTA ; DST se execută până când CX = 0
...............

4. CMPS DST, SRC ; Compare Strings


CMPSB (CMPSW) DST, SRC
Compară un octet (o pereche de octeţi) din şirul destinaţie DST adresat prin ES:DI cu octetul
(perechea de octeţi) din şirul sursă SRC adresat prin DS:SI, cu actualizarea corespunzătoare a
registrelor SI şi DI. Comparaţia se realizează prin scăderea octetului (cuvântului) sursă din octetul
(cuvântul) destinaţie, fără înscrierea rezultatului, dar cu poziţionarea indicatorilor de condiţie
conform rezultatului obţinut. Conţinutul celor două şiruri nu se modifică.
Exemplul 4.
DATA SEGMENT
sir1 DB 'AAAABC'
lsir1 EQU $-sir1
sir2 DB 'AAAACB'
DATA ENDS
CODE SEGMENT
ASSUME cs:CODE, ds:DATA, es:DATA
start: mov ax, DATA
mov ds, ax
mov es, ax
mov si, OFFSET sir1
mov di, OFFSET sir2
mov cx, lsir1/TYPE sir1
comp: cmpsb
jne exit
loop comp
exit: nop
CODE ENDS
END start

2-40
4. SCAS DST ; Scan String
SCASB (SCASW) DST
Scanează şirul destinaţie DST adresat prin ES:DI. Instrucţiunea poziţionează indicatorii de
condiţie conform rezultatului diferenţei dintre conţinutul registrului AL (AX) şi octetul (perechea
de octeţi) din şirul destinaţie DST fără înscrierea rezultatului şi fără modificarea conţinutului
registrului AL (AX) şi a conţinutului şirului. Se actualizează corespunzător registrul DI.
Pentru repetarea operaţiile elementare pe şiruri de caractere se pot utiliza următoarele
prefixe (obţinând astfel o instrucţiune cu opcod-ul pe 2 octeţi):
1. REP - Se repetă operaţia care urmează până când conţinutul registrului CX devine zero
(nu mai este nevoie de instrucţiunea LOOP ca în exemplul anterior). Precizăm că după fiecare
execuţie a operaţiei elementare conţinutul registrului CX este decrementat cu 1.
Exemplu: Dorim să transferăm 100 octeţi de la adresa DS:0200h la adresa DS:0300h.
Secvenţa de instrucţiuni va fi următoarea:
mov ax, ds
mov es, ax
mov si, 200h
mov di, 300h
mov cx, 100
cld
rep movsb
2. REPZ, REPE - Se repetă operaţia care urmează până când conţinutul registrului CX
devine zero sau până când indicatorul ZF devine zero. Indicatorul ZF este setat numai de către
instrucţiunile SCASB (SCASW) şi CMPSB (CMPSW) la egalitatea a două elemente. Menţionăm
că după fiecare execuţie a operaţiei elementare conţinutul registrului CX este decrementat cu 1.
3. REPNZ, REPNE - Se repetă operaţia care urmează până când conţinutul registrului CX
devine zero sau până când indicatorul ZF devine unu. Indicatorul ZF este setat numai de către
instrucţiunile SCASB (SCASW) şi CMPSB (CMPSW) la egalitatea a două elemente. Menţionăm
că după fiecare execuţie a operaţiei elementare conţinutul registrului CX este decrementat cu 1.
Observaţie: Tipul prefixului este semnificativ numai pentru operaţiile SCASB (SCASW) şi
CMPSB (CMPSW). Pentru toate celelalte instrucţiuni pe şiruri de elemente, toate prefixele au
aceeaşi semnificaţie ca şi prefixul REP.
Prezentăm în continuare câteva exemple de utilizare a instrucţiunilor pe şiruri de caractere.
Exemplul 5. Utilizând prefixul REP, bucla
muta: movs sir2, sir1 ; sau MOVSB
loop muta
din Exemplul 2 se poate rescrie astfel:
rep movs sir2, sir1
sau
rep movsb ; Se recomandă această utilizare
Exemplul 6. În varianta cu prefix REP, bucla din Exemplul 4
comp: cmpsb
jne exit
loop comp
exit: nop
se înlocuieşte cu
repe cmpsb
jne exit

2-41
exit: nop
Exemplul 7.
; TRANSFB - transferă un bloc de date dintr-o zonă de memorie în altă
; zonă de memorie
DOSSEG
.MODEL SMALL
.STACK 100h
lung_bloc EQU 10h
.DATA
bloc_sursa db 20 DUP (0Ah)
bloc_dest db 20 DUP (0)
.CODE
START:
mov ax, @DATA ; Încarcă în AX adresa de bază a segmentului de date
mov ds, ax
cld ; Sterge DF (DF = 0)
mov cx, lung_bloc ; Se încarcă CX cu lungimea blocului de date
mov si, OFFSET bloc_sursa ; Se încarcă SI cu adresa de început a blocului sursă
mov ax, SEG bloc_sursa ; Se încarcă AX cu adresa de segment a
mov ds, ax ; blocului sursă, care se înscrie apoi în DS
mov di, OFFSET bloc_dest ; Se încarcă DI cu adresa de început a blocului dest
mov ax, SEG bloc_dest ; Se încarcă AX cu adresa de segment a
mov es, ax ; blocului destinaţie, care se înscrie apoi în ES
trans: movsb ; Se realizează transferul octet cu octet
loop trans
mov ax, 4c00h ; Ieşire în sistem
int 21h
END START
Exemplul 8.
; COMPAS - compara doua siruri de octeti, numarul locatiilor diferite
; fiind contorizat in registrul DX
DOSSEG
.MODEL SMALL
.STACK 100h
.DATA
lungs EQU 20h ; lungs - lungimea sirurilor de comparat
bloc_sursa db lungs DUP (0)
bloc_dest db lungs/4 DUP (1)
db lungs/4 DUP (0)
db lungs/4 DUP (5)
db lungs/4 DUP (0)
.CODE
START:
mov ax, @DATA
mov ds, ax
mov ax, SEG bloc_sursa
mov ds, ax
mov si, OFFSET bloc_sursa
mov ax, SEG bloc_dest
mov es, ax

2-42
mov di, OFFSET bloc_dest
cld ; Sterge DF
mov cx, lungs ; Incarca CX cu lungimea sirurilor de comparat
xor dx, dx
compb: cmpsb ; Bucla pentru compararea sirurilor, octet cu octet
loope compb
jcxz SF1 ; Daca CX = 0, operatia de comparare s-a terminat
inc dx ; In DX se contorizeaza numarul locatiilor
; diferite dintre cele doua siruri
inc cx ;
loop compb
SF1: jz SF
inc dx
SF: mov ax, 4c00h ; Iesire in sistem
int 21h
END START

7. Instrucţiuni de intrare/ieşire (I/O)


Accesul la interfeţele corespunzătoare echipamentelor periferice se realizează prin
intermediul unor instrucţiuni speciale. Fiecare interfaţă are asociate un număr de coduri specifice
numite porturi. Atribuirea codurilor pentru fiecare interfaţă se face la proiectarea sistemului de
calcul. Comunicaţia între microprocesor şi mediul exterior reprezentat de interfeţele de I/O se
face prin execuţia unor instrucţiuni care adresează aceste porturi. Un port este o valoare întreagă
reprezentată pe 8 sau 16 biţi.
Citirea unor date sau informaţii de stare se face prin intermediul unor instrucţiuni de forma:
a) IN AL (AX), PORT ; Input byte or word
b) IN AL (AX), DX
Forma a) poate fi utilizată numai dacă portul de intrare PORT are un cod mai mic decât 256
(PORT ∈ {0, 1, ..., 255} ) şi este specificat direct printr-un octet în cadrul instrucţiunii. Efectul
acestei instrucţiuni constă în încărcarea valorii citite din PORT-ul specificat în registrul AL (AX).
Exemplu: in al, 14 ; Citeşte octetul din portul cu numărul 14
in ax, 5 ; Citeşte cuvântul din portul cu numărul 5
Efectul execuţiei unei instrucţiuni de forma b) constă în încărcarea valorii citite de la portul
adresat indirect prin conţinutul registrului DX, în registrul AL (AX).
Exemplu: mov dx, 14 ;
in al, dx ; Citeşte octetul din portul cu numărul 14
mov dx, 5 ;
in ax, dx ; Citeşte cuvântul din portul cu numărul 5
Observaţii:
1. Numai primele 256 porturi pot fi specificate direct în instrucţiune, în timp ce oricare din
cele 2**16 porturi pot fi specificate indirect prin registrul DX.
2. Avantajul specificării directe a portului constă în aceea că nu mai este necesară
executarea unei instrucţiuni suplimentare de încărcare prealabilă a numărului portului în registrul
DX.
3. Avantajul specificării indirecte a portului constă în aceea că se pot adresa (prin bucle)
porturi cu adrese consecutive.
Transmiterea unor date sau a unor comenzi se face prin intermediul unor instrucţiuni de
forma:
a) OUT PORT, AL (AX) ; Output byte or word

2-43
b) OUT DX, AL (AX)
Efectul acestor instrucţiuni constă în:
a) Scrierea conţinutului registrului AL (AX) în portul de adresă (cod) PORT specificat în
instrucţiune (PORT ∈ {0, 1, ..., 255}).
b) Scrierea conţinutului registrului AL (AX) în portul adresat indirect prin conţinutul
registrului DX.
Exemple: out 49, al ; Se înscrie octetul din AL în portul 49
out 15, ax ; Se înscrie cuvântul din AX în portul 15
Echivalentul acestor instrucţiuni, utilizând însă registrul DX este următorul:
mov dx, 49 ;
out dx, al ; Se înscrie octetul din AL în portul 49
mov dx, 15 ;
out dx, ax ; Se înscrie cuvântul din AX în portul 15
Observaţie: Comentariile de la instrucţiunea IN sunt valabile şi pentru instructiunea OUT.

8. Instrucţiuni pentru controlul întreruperilor


Acţiunea provocată de îndeplinirea unei condiţii (interne sau externe în raport cu programul
aflat în execuţie) prin care se realizează automat transferul controlului unei rutine speciale de
tratare se numeste întrerupere, iar rutina respectivă se numeşte rutină de întrerupere. Există
două clase de întreruperi:
Întreruperi interne: acestea sunt iniţiate de starea programului aflat în execuţie sau prin
executarea unor instrucţiuni speciale de întrerupere. Ele se caracterizează prin faptul că sunt
sincrone în raport cu programul aflat în execuţie. Se mai numesc întreruperi software.
Întreruperi externe: acestea sunt iniţiate de partea hardware prin intermediul semnalelor de
întrerupere trimise către procesor. Declanşarea lor semnifică îndeplinirea unor evenimente
externe procesorului. Ele se caracterizează prin faptul că sunt asincrone în raport cu programul
aflat în execuţie. Se mai numesc întreruperi hardware.
O rutină de întrerupere este asemănătoare unei proceduri în sensul că după execuţia ei se
revine în programul întrerupt la instrucţiunea imediat următoare celei întrerupte. Modalitatea de
declanşare a unei rutine de întrerupere este în general diferită de apelul unei proceduri, existând
însă, pentru anumite clase de întreruperi şi similitudini (la microprocesoarele 8086/88 există
aproape o similitudine perfectă între apelul procedurilor îndepărtate şi instrucţiunile de
întrerupere). Ca element comun notăm necesitatea salvării contextului programului întrerupt
(cuvânt de stare program - PSW, numărător de program, registre generale) la intrarea în rutina de
întrerupere. Deoarece anumite întreruperi sunt iniţiate de evenimente externe procesorului,
asincrone în raport cu programul aflat în execuţie, acesta nu le poate transmite nici un fel de
parametri, comunicaţiile de date putând avea loc numai utilizând variabile direct accesibile
ambelor secvenţe de program: secvenţa curent executabilă şi rutina de întrerupere.
Acţiunile ce rezultă în urma apariţiei unei întreruperi şi care determină transferul
controlului rutinei de întrerupere poartă numele de secvenţă de întrerupere.
Secvenţa de întrerupere specifică microprocesoarelor 8086/88 este următoarea:
1. Se salvează valorile curente ale PSW, CS şi IP în stivă;
2. Se încarcă perechea de registre CS:IP dintr-un pointer determinat pe baza unei valori
calculată folosind tipul întreruperii, şi anume, dacă n este tipul întreruperii, valoarea calculată
este 4*n. Pointerul ce conţine noile valori ale registrelor CS şi IP se numeşte vector de
întrerupere;
3. Se şterg flagurile IF si TF.

2-44
Noile conţinuturi ale registrelor CS şi IP determină adresa de început a rutinei de
întrerupere.
Tipul întreruperii este un număr întreg în gama 0...255. Adresa vectorului de întrerupere
rezultă prin înmulţirea tipului întreruperii cu 4. Primele 5 tipuri de întrerupere, şi anume 0, 1, 2, 3
şi 4, au semnificaţii speciale predefinite:
a. tipul 0 este utilizat pentru tratarea erorii de împărţire la zero. Dacă se realizează o
împărţire la zero se declanşează automat o întrerupere cu tipul 0. O astfel de situaţie poate apare
ori de cîte ori, după executarea unei instrucţiuni idiv sau div, câtul are o depăşire de format,
indiferent de valoarea flagului IF;
b. tipul 1 este utilizat pentru executarea programelor în regim "pas cu pas". Dacă flagul TF
este setat se va declanşa automat o întrerupere de tipul 1 la sfârşitul fiecărei instrucţiuni executate
de procesor;
c. tipul 2 este utilizat de către întreruperea nemascabilă. Întreruperea nemascabilă este o
întrerupere externă care poate apare indiferent de starea flagului IF.
d. tipul 3 este rezervat unei instrucţiuni speciale de întrerupere cu lungimea de un octet cu
codul 0CC16. Această instrucţiune este utilizată pentru implementarea facilităţii de executare a
unui program cu puncte de oprire (breakpoint) din cadrul programelor depanatoare (debugger).
e. tipul 4 este utilizat pentru tratarea depăşirilor. Dacă se execută o instrucţiune into când
flagul OF este setat, se va declanşa o întrerupere cu tipul 4.

Instrucţiunile prin care se pot provoca prin program întreruperi se numesc instrucţiuni de
întrerupere. Aceste instrucţiuni sunt următoarele:
• Instrucţiunea
INT n
unde n este un număr întreg permite generarea unor întreruperi software. Numărul n din
instrucţiune reprezintă numărul nivelului de întrerupere asociat semnalului de întrerupere generat.
Sunt posibile 256 nivele de întrerupere cuprinse între 0 şi 255.
Pentru fiecare întrerupere există o procedură specială de tratare a acesteia. Efectul
instrucţiunii INT n constă în salvarea în stivă a registrului indicatorilor de condiţie F, a
conţinutului registrelor CS şi IP, resetarea indicatorilor TF şi IF şi efectuarea saltului la adresa
procedurii de tratare a întreruperii, adresă memorată pe 4 octeţi la adresa corespunzătoare
nivelului de întrerupere. Adresa asociată unui nivel de întrerupere se obţine înmulţind cu 4
numărul n al nivelului de întrerupere. Adresa de segment pentru adresa asociată unui nivel de
întrerupere este zero. Simbolic, cele spuse mai sus se scriu sub următoarea formă:
SP <----- SP - 2
(SP +1, SP) <----- F ; IF, TF <--- 0
SP <----- SP - 2
(SP +1, SP) <----- CS
SP <----- SP - 2
(SP +1, SP) <----- IP
IP <----- (4 * n)
CS <----- (4 * n +2)
Adresele procedurilor de tratare a întreruerilor sunt continute într-un tabel cu 256 de intrări,
fiecare intrare fiind pe 4 octeţi. Tabelul începe la adresa de memorie 0000:0000h, conform Fig.
8.1.

2-45
Fig. 8.1.

În general, legătura cu sistemul de operare (BIOS, DOS) de realizează utilizând instrucţiuni


de tip INT.
Reîntoarcerea din procedurile de tratare a întreruperilor se face cu ajutorul instrucţiunii
IRET, plasată la sfârşitul unei astfel de proceduri şi care are ca efect refacerea valorilor
registrelor IP şi CS salvate anterior în stivă, precum şi starea indicatorilor de condiţie salvaţi de
asemenea în stivă, astfel:
IP <----- (SP +1, SP)
SP <----- SP + 2
CS <----- (SP +1, SP)
SP <----- SP + 2
F <----- (SP +1, SP)
SP <----- SP + 2
Instrucţiunea INTO (Interrupt on Overflow) este o instrucţiune pe un octet care generează o
întrerupere de tipul 4, dacă bistabilul de condiţie OF = 1. O astfel de instrucţiune ar trebui să
urmeze după fiecare instrucţiune aritmetică aplicată unor operanzi cu semn ori de câte ori există
posibilitatea apariţiei unei depăşiri.
• În afara întreruperilor software INT n prezentate, activitatea procesorului poate fi
întreruptă şi de un semnal extern ce se aplică pe pinul INTR al procesorului. Dacă indicatorul IF
= 1, după terminarea execuţiei instrucţiunii curente, procesorul se opreşte din taskul său obişnuit
şi se pregăteşte să treacă la subrutina de tratare a întreruperii recepţionate. Pentru început,
procesorul salvează în stivă toate informaţiile importante despre taskul său (valorile curente ale
indicatorilor de condiţie şi ale indicatorilor de stare, valorile curente ale registrelor CS şi IP), apoi
va prelua de la dispozitivul (elementul) extern tipul întreruperii şi va trece la subrutina de tratare a
acesteia. Orice subrutină de tratare a unei întreruperi se termină cu instrucţiunea IRET.
Dacă procesorul primeşte o întrerupere pe pinul NMI atunci, indiferent de valoarea lui IF,
procesorul va executa aceleaşi operaţii ca şi la o întrerupere pe pinul INTR, cu singura deosebire
că nu mai este nevoie să se precizeze tipul întreruperii deoarece, în această situaţie, se generează
o întrerupere de tipul 2.

8.1. Interfaţa limbaj de asamblare - Sistem de operare DOS


Rutinele pe care sistemul de operare DOS le utilizează pentru gestiunea resurselor
calculatorului pot fi apelate din programele scrise în limbaj de asamblare.

2-46
Aceste rutine se mai numesc apeluri sistem (system calls). Utilizarea apelurilor sistem de
către programele de aplicaţie permite obţinerea de programe independente de maşina fizică,
garantându-se compatibilitatea acestora cu versiunile superioare ale sistemului de operare DOS.
Instrucţiunile de întrerupere cu tipurile 20h, ..., 3Fh sunt rezervate apelurilor sistem.
Majoritatea apelurilor sistem sunt grupate la întreruperea cu tipul 21h. Aceste apeluri sunt
cunoscute sub numele de funcţii sistem. Pentru executarea unui apel sistem se procedează astfel:
- se transferă parametrii apelului în registrele procesorului. Parametrii (împreună cu
registrele corespunzătoare) sunt specifici fiecărui apel în parte;
- se execută instrucţiunea int cu tipul corespunzător apelului respectiv.
Pentru executarea unei funcţii sistem se procedează astfel:
- se transferă parametrii funcţiei în registre;
- se transferă numărul funcţiei în registrul ah;
- se transferă un cod suplimentar, dacă acest lucru este cerut de funcţia respectivă, în
registrul al;
- se execută instrucţiunea int 21h.
Majoritatea funcţiilor sistem setează flagul CF dacă a apărut o eroare, codul de eroare fiind
returnat în registrul AX.
Principalele funcţii sistem pot fi grupate în următoarele categorii:
a. Funcţii pentru operaţiile de I/E standard, specifice următoarelor dispozitive de I/E:
consolă, imprimantă, interfaţă serială. Dacă un program foloseşte pentru implementarea
operaţiilor de I/E aceste funcţii, intrarea, respectiv ieşirea sa pot fi redirectate. Dintre aceste
funcţii ne referim la următoarele:
- Funcţia 01h: această funcţie citeşte un caracter de la intrarea standard, pe care îl trimite în
ecou la ieşirea standard. Dacă caracterul citit este CTRL-C, se execută int 23h. La apel (AH) =
01h, şi după execuţie (AL) = codul ASCII al caracterului citit.
- Funcţia 02h: această funcţie scrie un caracter la ieşirea standard. Dacă se tastează CTRL-
C, se execută int 23h. La apel (AH) = 02h, (DL) = codul ASCII al caracterului care trebuie scris.
- Funcţia 07h: această funcţie citeşte un caracter de la intrarea standard. Caracterul citit nu
este trimis în ecou la ieşirea standard, şi nu se efectuează nici un test pentru CTRL-C. La apel
(AH) = 07h şi după execuţie (AL) = codul ASCII al caracterului citit.
- Funcţia 09h: această funcţie realizează afişarea unui şir de caractere la ieşirea standard,
şirul de caractere fiind terminat cu '$'. Caracterul '$' nu se afişează. La apel (AH) = 09h, DS:DX =
adresa de început a şirului de caractere respectiv.
- Functia 0Ah: aceasta funcţie realizează citirea unui şir de caractere de la intrarea standard.
La apel (AH) = 0Ah, DS:DX = adresa unei zone tampon cu următoarea structură:
- primul octet al zonei va conţine, la apel, numărul maxim (fie acesta n) de caractere care
vor fi citite, inclusiv un caracter CR;
- al doilea octet al zonei va conţine, după execuţia funcţiei, numărul de caractere efectiv
citite, caracterul CR nefiind contorizat;
- restul zonei va trebui să conţină cel puţin atâţia octeţi câţi au fost specificaţi în primul
octet. După execuţia funcţiei aici va fi depus şirul citit, primul caracter din şir fiind plasat la
adresa cea mai mică.
Caracterele citite sunt plasate în zona tampon specificată, începând cu al treilea octet al
zonei. Citirea se termină când se tastează CR. Dacă se încearcă introducerea mai multor caractere
decât numărul specificat, adică n-1, caracterele în plus se ignoră, la ieşirea standard fiind trimis
caracterul BEL (07h). Ultimul caracter din zona tampon este întotdeauna CR. Dacă se tastează
CTRL-C, se execută int 23h.
Exemplu. Următorul program citeşte o tastă, determină dacă este o tastă obişnuită sau
funcţională şi apoi afişează codul tastei. Citirea tastei se face cu funcţia 07h.

2-47
Dacă la primul apel se întoarce codul 0 în registrul AL, înseamnă că tasta apasată este o
tastă funcţională, codul extins al tastei fiind determinat cu un al doilea apel al funcţiei.
DATA SEGMENT
cerere DB 'Tastati o tasta', 0ah, 0dh, '$'
sir DB 3 DUP (?), 0ah, 0dh, '$'
mesaj1 DB 'Codul tastei este:', 0ah, 0dh, '$'
mesaj2 DB 'Codul extins al tastei este:', 0ah, 0dh, '$'
DATA ENDS
STIVA SEGMENT STACK 'STACK'
DW 30 DUP(?)
virf LABEL WORD
STIVA ENDS
COD SEGMENT
ASSUME cs:COD, ds:DATA, ss:STIVA
start: jmp incep
conv PROC NEAR
; Primeşte în registrul AL un număr întreg şi în registrul BX adresa unei zone de 3 octeţi.
; Întoarce în această zonă şirul de caractere corespunzător scrierii zecimale a numărului
push dx
xor ah, ah ; AH = 0
mov dl, 10
div dl ; AL = AX/10, AH = AX MOD 10
add ah, '0' ; Se formează codul ASCII al cifrei din AH
mov [bx+2], ah
xor ah, ah
div dl
add ah, '0'
mov [bx+1], ah
add al, '0'
mov [bx], al
pop dx
ret
conv ENDP
incep: mov ax, DATA
mov ds, ax
mov ax, STIVA
mov ss, ax
mov sp, OFFSET virf
lea dx, cerere ; Se afişează mesajul care cere tastarea
mov ah,09h ; unei taste
int 21h
mov ah, 07h ; Se citeşte o tasta
int 21h
cmp al, 0 ; Se testează dacă este tastă funcţională
jz cod_extins
lea bx, sir ; Se determină codul tastei
call conv
lea dx, mesaj1 ; Se afişază mesaj1
mov ah, 09h
int 21h
jmp afis

2-48
cod_extins: mov ah, 07h ; Se citeşte codul extins
int 21h
lea bx, sir ; Se determină codul extins
call conv
lea dx, mesaj2 ; Se afişază mesaj2
mov ah, 09h
int 21h
afis: lea dx, sir ; Se afişază codul tastei
mov ah, 09h
int 21h
mov ax, 4c00h
int 21h
COD ENDS
END start

b. Funcţii pentru gestiunea memoriei


Sistemul de operare DOS ţine evidenţa blocurilor de memorie alocate prin scrierea la
începutul fiecăruia a unei înregistrări, numită bloc de control al memoriei (Memory Control
Block, MCB) ce conţine informaţii referitoare la dimensiunea blocului, în număr de paragrafe (1
paragraf = 16 octeţi) şi un pointer la următorul bloc, dacă există. Dintre funcţiile pentru gestiunea
memoriei prezentăm pe următoarele:
- Funcţia 48h: prin această funcţie, programul aflat în execuţie poate cere alocarea unei
cantităţi de memorie specificată în număr de paragrafe. La apel AH = 48h, BX = numărul de
paragrafe cerute. Dacă la retur CF = 1, înseamnă ca a apărut o eroare, codul de eroare fiind
specificat în registrul AX, astfel: dacă AX = 7 înseamnă că s-a alterat un MCB, iar dacă AX = 8
înseamnă că nu există suficientă memorie pentru alocare. În registrul BX se obţine numărul de
paragrafe disponibile. Dacă la retur CF = 0, înseamnă că alocarea s-a efectuat cu succes, în
registrul AX întorcîndu-se adresa de segment a zonei de memorie alocată.
- Funcţia 49h: această funcţie eliberează un bloc de memorie alocat anterior cu functia 48h.
La apel AH = 49h, ES = adresa de segment a blocului respectiv. Dacă la retur CF = 1 înseamnă
că a apărut o eroare, codul de eroare fiind specificat în registrul AX, astfel: dacă AX = 7
înseamnă alterarea MCB-ului, iar dacă AX = 9 înseamnă că se doreşte eliberarea unui bloc ce nu
a fost alocat corect (cu funcţia 48h). Dacă la retur CF = 0 înseamnă că eliberarea s-a făcut cu
succes.
- Funcţia 4Ah: Această funcţie modifică dimensiunea unui bloc de memorie alocat anterior.
La apel AH = 4Ah, BX = noua dimensiune a blocului, în număr de paragrafe. Dacă la retur CF =
1, înseamnă că a apărut o eroare, codul de eroare fiind specificat în registrul AX, astfel: AX = 7
înseamnă alterarea MCB-ului, AX = 8 înseamnă memorie insuficientă (în situaţia în care s-a dorit
mărirea dimensiunii blocului), dacă AX = 9 înseamnă că se doreşte modificarea dimensiunii unui
bloc de memorie ce nu a fost alocat corect. Dacă AX = 8, registrul BX va conţine numărul de
paragrafe disponibile. Dacă la retur CF = 0 înseamnă că modificarea dimensiunii blocului s-a
făcut cu succes.
Exemplu. Următorul program alocă un bloc de memorie suficient de mare pentru a
memora n octeţi, realizează umplerea zonei de n octeţi cu o valoare constantă, după care dezalocă
zona alocată. La încărcarea unui program în memorie, sistemul de operare DOS îi alocă toată
memoria disponibilă. Programul va trebui să ajusteze blocul de memorie care i se alocă la
dimensiunea efectiv necesară.

2-49
DATA SEGMENT
a1 DB 'Alocare efectuata cu succes', 0ah, 0dh, '$'
a2 DB 'Alocare esuata', 0ah, 0dh, '$'
d DB 'Dezalocare efectuata cu succes', 0ah, 0dh, '$'
n DW 7000h ; dimensiunea blocului
const DB 88h
segm DW ?
DATA ENDS
STIVA SEGMENT STACK 'STACK'
DW 150 DUP (?)
virf LABEL WORD
STIVA ENDS
COD SEGMENT
ASSUME cs:COD, ds:DATA
start: mov ax, DATA
mov ds, ax
mov ax, STIVA
mov ss, ax
mov sp, OFFSET virf
; Calculează numărul de paragrafe alocate programului în AX
mov ax, cs
mov bx, es
sub ax, bx
mov cl, 4
shl ax, cl
add ax, OFFSET ultima_instr
xor dx, dx ; DX = 0
mov cx, 10h
div cx ; După împărţire, AX va conţine numărul
; de paragrafe alocate programului
inc ax
; Se reduce dimensiunea blocului de memorie alocat programului
mov bx, ax
mov ah, 4ah ; Se modifică dimensiunea unui bloc de
; memorie alocat anterior
int 21h
; Se calculează numărul de paragrafe necesare pentru a fi alocate
xor dx, dx
mov ax, n ; AX = 7000h
mov cx, 10h
div cx ; După împărţire, AX va conţine numărul
; de paragrafe al zonei de memorie
cmp ax, 0
jz aloc
inc ax
aloc: mov bx, ax ; Se efectuează alocarea
mov ah, 48h
int 21h
jnc ok
mov ah, 09h ; Alocare eşuată
lea dx, a2

2-50
int 21h
jmp gata
ok: mov segm, ax ; Alocare efectuată cu succes
mov ah, 09h
lea dx, a1
int 21h
cont: mov es, segm ; Se umple blocul alocat
xor bx, bx
mov cx, n
mov dl, const ; DL = 88h
trans: mov es:[bx], dl
inc bx
loop trans
; Se dezalocă blocul alocat anterior
mov ah, 49h
int 21h
mov ah, 09h
lea dx, d
int 21h
gata: mov ax, 4c00h
int 21h
ultima_instr:
COD ENDS
END start

c. Funcţii BIOS pentru controlul ceasului de timp real (INT 1AH)


Pentru ceasul de timp real, BIOS-ul conţine două proceduri: una pentru tratarea
întreruperilor provenite de la ceasul de timp real şi alta accesibilă utilizatorilor pentru controlul
ceasului de timp real.
Procedura de tratare a întreruperilor provenite de la ceasul de timp real este apelată de
aproximativ 18,21 ori pe secundă. La fiecare apel al procedurii se incrementează un contor format
din 4 octeţi a cărui adresa este 40H:6CH. Contorul memorează numărul de treceri prin procedură
de la ora 00:00:00. De asemenea, această procedură verifică dacă contorul a ajuns la echivalentul
a 24 ore. În acest ultim caz, contorul este reiniţializat la 0 şi la adresa 40H:70H se memorează
valoarea 1 (în mod normal, valoarea acestui octet este 0). Pentru fiecare apel al acestei proceduri
se va apela întreruperea software INT 1Ch.
Procedura pentru controlul ceasului de timp real permite citirea, respectiv iniţializarea
contorului de treceri prin procedura de tratare a întreruperilor provenite de la ceasul de timp real.
Pentru controlul ceasului de timp real se pot selecta următoarele funcţii:
Funcţia 0 - Citire contor.
Ca rezultat al apelului acestei funcţii, registrul CX va conţine partea cea mai semnificativă,
iar registrul DX va conţine partea mai puţin semnificativă a contorului. Registrul AL va conţine
valoarea indicatorului de depăşire a 24 de ore.
Funcţia 1 - Iniţializare contor:
Contorul se poate iniţializa în modul următor: cei mai semnificativi 2 octeţi vor primi
valoarea conţinută în registrul CX, iar cei mai puţin semnificativi 2 octeţi vor primi valoarea
conţinută în registrul DX.

2-51
Observaţie: Funcţiile 2 ÷ 7 sunt funcţii specifice sistemelor de tip AT, astfel:
Funcţia 2 - Citeşte timpul din contorul nevolatil (CMOS) al ceasului de timp real.
La ieşire: Registrul CH - ora în BCD;
Registrul CL - minutul în BCD;
Registrul DH - secunda în BCD;
Flagul CF = 1 dacă ceasul nu este operaţional.
Funcţia 3 - Setează timpul în contorul nevolatil (CMOS) al ceasului de timp real.
La intrare: Registrul CH, CL - ora şi minutul în BCD;
Registrul DH - secunde în BCD;
Registrul DL = 1 pentru salvarea opţiunii.
Funcţia 4 - Citeşte data din contorul nevolatil (CMOS) al ceasului de timp real.
La ieşire: Registrul CH - secolul în BCD;
Registrul CL - anul în BCD;
Registrul DH - luna în BCD;
Registrul DL - ziua în BCD;
Flagul CF = 1 dacă ceasul nu este operaţional.
Funcţia 5 - Setează data în contorul nevolatil (CMOS) al ceasului de timp real.
La intrare: Registrul CH, CL - secolul şi anul în BCD;
Registrul DH, DL - luna şi ziua în BCD.

9. Instrucţiuni pentru sincronizare externă


Pentru sincronizarea cu evenimentele externe, microprocesoarele I8086/I8088 admit
instrucţiunea
HLT ; Halt
Prin execuţia acestei instrucţiuni, UCP-procesor intră în starea HALT. Efectul acestei
instrucţiuni constă în aceea că oferă posibilitatea procesorului să aştepte sosirea unei întreruperi
care ar reprezenta realizarea unui eveniment în proces.
Ieşirea din starea HALT se poate face prin întreruperi de tip NMI, întreruperi pe pinul
INTR când IF = 1, precum şi prin semnalul hardware RESET = 1.
a). La apariţia unei întreruperi, valorile curente ale indicatorilor de condiţie şi ale
indicatorilor de stare, precum şi valorile curente ale registrelor CS şi IP sunt salvate în stivă şi
procesorul trece şi execută subrutina de tratare a întreruperii respective. Când, în această
subrutină, procesorul întâlneşte instrucţiunea IRET, valorile lui IP, CS şi registrului F sunt
refăcute din stivă, după care se va executa instrucţiunea care urmează imediat după HLT.
b). Dacă din HALT se iese cu RESET = 1, atunci întregul sistem se iniţializează.

2-52
Definirea şi utilizarea segmentelor logice
Segmentul logic (numit pe scurt segment) este cea mai mică unitate relocabilă a unui
program. Relocabilitatea este proprietatea unui program obiect de a putea fi link-editat şi făcut
executabil prin plasarea sa la orice adresă de început în memoria principală.
Un segment fizic (numit şi cadru) în memoria lui I8086/I8088 constă dintr-un grup de
locaţii adiacente de dimensiune 64 Kocteţi, cu adresa absolută de început multiplu de 16.
La un moment dat microprocesorul poate sa facă acces la patru segmente logice:
- segmentul de cod, curent - accesibil prin CS;
- segmentul de date, curent - accesibil prin DS;
- segmentul de date, suplimentar - accesibil prin ES;
- segmentul de stivă - accesibil prin SS.
Aceste segmente logice pot să corespundă la patru segmente fizice distincte, dar pot să
existe şi coincidenţe şi/sau suprapuneri parţiale între aceste segmente.
Definirea unui segment se face sub forma:
nume_segment SEGMENT
Corpul segmentului
nume_segment ENDS
unde nume_segment este numele asociat segmentului, care nu poate fi utilizat în program cu o
altă semnificaţie. Acestui nume i se asociază o valoare şi anume adresa de segment (16 biţi)
corespunzătoare poziţiei segmentului în memorie.
Structura unui segment de date este următoarea:
nume_segment SEGMENT
Directive de alocare memorie
nume_segment ENDS
Structura unui segment de cod este următoarea:
nume_segment SEGMENT
Instrucţiuni şi directive
nume_segment ENDS
Directivele şi instrucţiunile cuprinse între directivele SEGMENT şi ENDS se consideră că
fac parte din segmentul respectiv.
Structura unui program format din două segmente de date şi un segment de cod este
următoarea:
data_seg1 SEGMENT ; Începutul segmentului de date data_seg1
. . . . Directive
data_seg1 ENDS ; Sfârşitul segmentului data_seg1
data_seg2 SEGMENT ; Începutul segmentului de date data_seg2
. . . . Directive
data_seg2 ENDS ; Sfârşitul segmentului data_seg2
code_seg SEGMENT ; Începutul segmentului de cod code_seg
. . . . Directive
start:
. . . . . Instrucţiuni
code_seg ENDS ; Sfârşitul segmentului code_seg
END start
Având în vedere că într-un program pot să existe mai multe segmente este necesar ca
asamblorul să "ştie" în fiecare moment care sunt cele patru segmente logice curente pentru a

2-53
putea să genereze corect codurile instrucţiunilor. De asemenea, asamblorul trebuie să "ştie" ce
registre de segment se pot utiliza pentru a realiza accesul la datele referite. Această informaţie
este transmisă asamblorului cu ajutorul pseudoinstrucţiunii ASSUME a cărei formă generală este:
ASSUME reg_segment : nume_segment [, . . . . . .]
unde:
reg_segment = CS | DS | SS | ES;
nume_segment = numele segmentului logic sau numele unui grup de segmente definit
anterior printr-o directivă GROUP sau cuvântul cheie NOTHING care anulează selecţia
precedentă a segmentului.
Precizăm că nume_segment va fi adresat prin reg_segment corespunzător.
Încărcarea registrului segment reg_segment cu adresa de bază este sarcina programatorului
(cu excepţia registrului CS).
Trebuie remarcat că ASSUME este o pseudoinstrucţiune pentru care nu se generează cod,
rolul ei fiind numai de a informa asamblorul de intenţia programatorului.
Exemplu:
ASSUME CS : code_seg, DS : data_seg1, ES : data_seg2
Această directivă va informa asamblorul că adresa de segment a segmentului code_seg se va găsi
în CS, adresa de segment a segmentului data_seg1 se va găsi în DS şi adresa de segment a
segmentului data_seg2 se va găsi în ES. Asupra lui SS nu s-a făcut nici o presupunere.
Observaţie: Deoarece directiva ASSUME nu încarcă adresele de segment în registrele de
segment corespunzătoare, pentru toate registrele de segment, cu excepţia lui CS, acest lucru se
face în mod explicit de către programator, ca în exemplul următor:
code_seg SEGMENT
ASSUME CS : code_seg, DS : data_seg1, ES : data_seg2
start: mov ax, data_seg1 ; Încărcarea registrului DS cu
mov ds, ax ; adresa de bază a segmentului data_seg1
mov ax, data_seg2 ; Încărcarea registrului ES cu
mov es, ax ; adresa de bază a segmentuluidata_seg2
code_seg ENDS
END start
Vom prezenta în continuare un exemplu de referire la date în segmentul de cod:
data1 SEGMENT ; Începutul segmentului de date data1
alfa dw 0
beta dw 0
data1 ENDS ; Sfârşitul segmentului data1
data2 SEGMENT ; Începutul segmentului de date data2
gama dw 0
delta dw 0
data2 ENDS ; Sfârşitul segmentului data2
code SEGMENT ; Începutul segmentului de cod code
ASSUME CS : code, DS : data1, ES : data2
; Iniţilaizare registre segment conform directivei ASSUME
start: mov ax, data1 ; Încărcarea registrului DS cu
mov ds, ax ; adresa de bază a segmentului data1
mov ax, data2 ; Încărcarea registrului ES cu
mov es, ax ; adresa de bază a segmentului data2

2-54
; Referire la date
mov ax, alfa ; Utilizare registru DS
mov gama, ax ; Utilizare registru ES
mov es : gama, ax ; Utilizare registru ES
; Schimbare conţinut registru DS
mov ax, cs ; Segmentul de date coincide cu cel de cod
mov ds, ax ;
; Referire la date în segmentul de cod code
mov ds : psi, ax ; Utilizare registru DS
mov es : psi, ax ; Utilizare registru ES
mov cs : psi, ax ; Utilizare registru CS
psi dw 0 ; Definirea variabilei psi
mov ax, 4c00h
int 21h
code ENDS ; Sfârşitul segmentului de cod code
END start

Combinarea segmentelor
Într-un program se pot defini oricâte segmente; în mod uzual, se definesc segmente pentru:
date globale, date locale, stivă, program principal, proceduri comune, vectori de întrerupere,
rutine pentru servirea întreruperilor.
Forma sintactică completă a directivei SEGMENT introduce o serie de atribute, aşa cum
reiese din definiţia următoare:
nume_seg SEGMENT [tip aliniere] [combinare] [utilizare] ['clasa']
Corpul segmentului
nume_seg ENDS
unde nume_seg este numele atribuit segmentului de către utilizator. Acesta poate fi unic sau poate
fi identic cu un nume atribuit altor segmente. Segmentele cu acelaşi nume vor fi combinate de
către linker într-un singur segment, funcţie de celelalte atribute ale definiţiei de segment.
Atributele ce însoţesc directiva SEGMENT oferă o serie de informaţii editorului de
legături, informaţii ce se referă la:
- modul de încărcare a segmentului la momentul execuţiei;
- modul de grupare a segmentelor;
- modul de aliniere a segmentului.
Există următoarele tipuri de aliniere: PARA, BYTE, WORD, PAGE. Acestea indică tipul
adresei de început a segmentului. Astfel, PARA | BYTE | WORD | PAGE indică faptul că adresa
de început a zonei de memorie rezervată segmentului este divizibilă cu 16 | 1 | 2 | 256. Valoarea
adresei de segment utilizată se obţine prin truncherea adresei fizice. De exemplu, dacă prima
locaţie liberă are adresa fizică 12345h şi pentru un segment se consideră o aliniere de tip BYTE,
atunci pentru adresa de segment se va utiliza valoarea 1234h. Prima rezervare din acest segment
va avea adresa relativă 5. Dacă pentru aceeaşi situaţie se consideră o aliniere de tip PARA,
atunci, pentru adresa de segment se va utiliza valoarea 1235h. Implicit se consideră tipul de
aliniere PARA.
combinare este o informaţie pentru editorul de legături care defineşte modul de combiare a
segmentelor având acelaşi nume. Această informaţie indică raportul între acest segment şi
segmente definite în alte module obiect. Tipul de combinare poate fi:

2-55
- PUBLIC : dacă în alte module obiect cu care se leagă modulul obiect curent sunt
conţinute alte segmente cu acelaşi nume, atunci se va face o concatenare a acestora, obţinându-se
un unic segment. Toate instrucţiunile şi/sau datele din noul segment se referă la un registru de
segment unic, toate deplasamentele fiind astfel încât să reprezinte distanţa faţă de începutul
noului segment.
- COMMON : dacă în alte module obiect cu care se leagă modulul obiect curent sunt
conţinute alte segmente cu acelaşi nume, atunci acestea vor fi suprapuse unul peste celălalt, adică
încep la aceeaşi adresă. Lungimea zonei rezultate va fi dată de lungimea celui mai lung segment
de acest fel.
- AT expresie : segmentul va fi încărcat în memorie la adresa de segment reprezentată de
valoarea expresiei (ce nu va putea conţine o referinţă la vreun simbol definit ulterior).
- STACK : vor fi concatenate toate segmentele cu acelaşi nume pentru a forma un unic
segment ce constituie segmentul de stivă al programului. Registrul SP va fi iniţializat cu
lungimea stivei. De asemenea iniţializarea lui SS se face automat. Dacă se creează un segment
stivă ce nu utilizează tipul STACK se vor da explicit
instrucţiuni pentru iniţializarea registrelor SS şi SP.
- MEMORY : segmentul curent va fi aşezat în
memorie în spaţiul disponibil rămas după aşezarea
celorlalte segmente în memorie.
Observaţii:
1. Dacă pentru un segment nu se specifică tipul
de aliniere, atunci acesta va fi aliniat implicit la o
adresa de paragraf divizibilă cu 16 (vezi figura
alăturată).

2. Tipul de combinare COMMON face posibilă


crearea unor zone de date ce pot fi accesate în comun de mai multe module. Exemplu:
; MODUL SURSA1
Data SEGMENT COMMON
.................
.................
.................
Data ENDS
Code SEGMENT PUBLIC
.................
.................
.................
Code ENDS
; MODUL SURSA2
Data SEGMENT COMMON
.................
.................
.................
Data ENDS
Code SEGMENT PUBLIC
.................
.................

2-56
.................
Code ENDS
3. Tipul de combinare AT permite specificarea exactă a adresei de început a unui segment.
Adresa specificată prin tipul de combinare AT este o adresă absolută.
4. Pentru combinarea unor segmente cu nume diferite se foloseşte directiva GROUP.
utilizare se foloseşte numai pentru procesorul 80386 când specifică mărimea cuvântului
unui segment. În acest caz poate fi USE16 - cuvânt pe 16 biţi sau USE32 - cuvânt pe 32 biţi. În
rest nu se foloseşte.
clasa reprezintă un mijloc de asociere a segmentelor cu nume diferite, dar cu scopuri
similare. Tipul se foloseşte pentru a controla ordinea segmentelor şi a identifica segmentul de
cod. Toate segmentele aparţin unei clase. Segmentele pentru care nu este stabilit explicit un
mume de clasă, vor avea numele de clasă nul.
Linkerul consideră că segmentele cu numele de clasă CODE sau având sufixul CODE
conţin codul programului.

Utilizarea grupurilor de segmente. Directiva GROUP


Un grup de segmente poate să fie adresat utilizând un singur registru de segment, cu
condiţia ca suma lungimilor segmentelor să nu depăşească 64 Kocteţi.
Adresarea se realizează cu pseudoinstrucţiunea GROUP a cărei formă este:
nume_grup GROUP lista_nume_segmente
unde nume_grup este numele grupului de segmente, iar lista_nume_segmente este o listă de nume
de segmente, separate prin virgulă.
Exemplu:
cseg1 SEGMENT
.....................
proc1 PROC
.........
proc1 ENDP
.....................
cseg1 ENDS
cseg2 SEGMENT
.....................
proc2 PROC
.........
proc2 ENDP
.....................
cseg2 ENDS
dseg1 SEGMENT
.....................
alfa1 db ?
beta1 db ?
.....................
dseg1 ENDS
dseg2 SEGMENT
.....................

2-57
alfa2 db ?
beta2 db ?
.....................
dseg2 ENDS
dgrup GROUP dseg1, dseg2 ; Se defineşte grupul de segmente de date dgrup
cgrup GROUP cseg, cseg1, cseg2 ; Se defineşte grupul de segmente de cod cgrup
cseg SEGMENT
ASSUME CS : cgrup, DS : dgrup
mov ax, dgrup ; Adresa de început a grupului de date
mov ds, ax ;
................................
mov al, beta1 ; Referire la date
mov bl, beta2 ;
..............................
call proc1 ; Referire la cod
..............................
call proc2 ; Referire la cod
cseg ENDS
Se observă că utilizând pseudoinstrucţiunea GROUP, pentru adresarea datelor şi
procedurilor aflate în segmente diferite se foloseşte acelaşi registru de segment.
Adresa relativă asociată unei instrucţiuni conţinute într-un grup se calculează faţă de
începutul grupului şi nu faţă de începutul segmentului din care face parte instrucţiunea respectivă.

Accesul la numele externe


În cazul legării mai multor module obiect trebuie să existe posibilitatea ca anumite module
să refere date definite în alte module.
- Dacă un identificator (de variabilă sau etichetă) este definit şi folosit (referit) în acelaşi
modul de program, el se numeşte local sau intern modulului respectiv.
- Dacă un identificator nu este definit ci numai referit într-un anumit modul, dar este definit
într-unul din modulele de program cu care acesta se leagă, el se numeşte global sau extern relativ
la modulul respectiv.
Pentru un program format dintr-un singur modul obiect, toţi identificatorii trebuie să fie
locali modulului respectiv. Pentru un program format din mai multe module, asamblorul şi link-
editorul trebuie informaţi despre identificatorii definiţi extern şi referiţi de un anumit modul, cât
şi despre identificatorii definiţi intern şi făcuţi accesibili altor module. Pentru aceasta, fiecare
modul va conţine 2 liste:
1. Lista identificatorilor definiţi extern şi referiţi în modulul respectiv (Pentru fiecare
identificator trebuie specificat şi tipul acestuia). Declararea identificatorilor externi se face cu
directiva EXTRN a cărei sintaxă este:
EXTRN nume_identif : tip [, ...]
unde nume_identif este identificatorul definit în exteriorul modulului curent, iar:
tip = BYTE, WORD, DWORD, STRUC, RECORD, PROC - pentru variabile;
tip = NEAR, FAR sau PROC - pentru etichete sau proceduri;
tip = ABS - pentru constante.

2-58
2. Lista identificatorilor definiţi intern care sunt făcuţi disponibili altor module se declară
cu directiva PUBLIC a cărei sintaxă este:
PUBLIC nume_identif [, ...]
unde nume_identif este identificatorul definit în modulul curent ca variabilă sau etichetă (inclusiv
numele de proceduri).
Exemplul 1. Se prezintă un program împărţit pe două module sursă: salut şi afis. Modulul
salut este modulul de iniţializare al programului. Execuţia va începe de la eticheta start din
modulul salut. Modulul afis conţine procedura afis care este apelată din modulul salut.
Modulul salut se prezintă astfel:
TITLE salut
DOSSEG
.MODEL SMALL
.STACK 256
.DATA
PUBLIC mesaj, lung
mesaj DB "Salut ", 13, 10
lung EQU $ - mesaj
.CODE
EXTRN afis : PROC
start: mov ax, @data
mov ds, ax
call afis
mov ax, 4C00h
int 21h
END start
Modulul afis se prezintă astfel:
TITLE afis
EXTRN lung : ABS
.MODEL SMALL
.DATA
EXTRN mesaj : BYTE
.CODE
PUBLIC afis
afis PROC
mov cx, lung
lea dx, mesaj
mov ah, 40h
int 21h
ret
afis ENDP
END
Pentru crearea unui program executabil din aceste două module, fiecare modul va fi
asamblat separat astfel:
TASM salut
TASM afis
Apoi se vor edita legăturile pentru cele două module astfel:
TLINK salut afis
Rezultatul este obţinerea fişierului salut.exe

2-59
Pentru fiecare modul sursă, MASM scrie un nume de modul în fişierul obiect, care este
utilizat de programele de depanare şi de editorul de legături când afişează mesaje de eroare.
Începând cu versiunea 5.00, numele modulului este numele de bază al fişierului ce conţine
modulul sursă.
Exemplul 2. Să se determine suma elementelor unui vector array având n componente
utilizând o procedură la care transferul parametrilor se face printr-o zonă comună de memorie
plasată într-un segment cu tipul de combinare COMMON:
TITLE ad_elem
DATA SEGMENT COMMON 'DATA'
num DW 5 DUP(?)
n DW ?
sum DW ?
DATA ENDS
CODE SEGMENT PUBLIC 'CODE'
PUBLIC ad_elem
ASSUME cs:CODE, ds:DATA
ad_elem PROC NEAR
push ax
push cx
push si
lea si, num
mov cx, n
xor ax, ax
inel: add ax, [si]
add si, 2
loop inel
mov sum, ax
pop si
pop cx
pop ax
ret
ad_elem ENDP
CODE ENDS
END
TITLE sumav
DATA SEGMENT COMMON 'DATA'
array DW 7, 9, -1, 2, 10
n DW 5
total DW ?
DATA ENDS
CODE SEGMENT PUBLIC 'CODE'
EXTRN ad_elem : NEAR
ASSUME cs:CODE, ds:DATA
start: mov ax, DATA
mov ds, ax
call ad_elem
mov ax, 4c00h
int 21h
CODE ENDS
END start

2-60
Programul este alcătuit din două module sursă. Modulul sursă ad_elem conţine procedura
de calcul ce accesează o zonă comună de memorie plasată în segmentul comun DATA. Modulul
sursă sumav plasează datele în acelaşi segment comun DATA şi deşi acestea au nume diferite,
ele sunt accesate corect de procedura ad_elem. Segmentul de cod CODE a fost declarat PUBLIC,
astfel că cele două porţiuni ale sale din cele două module sursă sunt concatenate, formând un
singur segment.
Pentru crearea unui program executabil din aceste două module, fiecare modul va fi
asamblat separat astfel:
TASM ad_elem
TASM sumav
Apoi se vor edita legăturile pentru cele două module astfel:
TLINK sumav ad_elem
Rezultatul este obţinerea fişierului sumav.exe
Exemplul 3. Programul următor determină de asemenea suma a două numere întregi
reprezentate în dublă precizie. Suma se calculează printr-o procedură adecvată.
Noutatea faţă de exemplul anterior o constituie modul de comunicare a parametrilor
procedurii care, de data aceasta, se face prin variabilele comune par1 şi par2, cu plasarea
rezultatului în variabila comună result. Programul va fi structurat pe două module: un modul ce
conţine programul principal şi un modul ce conţine procedura de calcul:
Modulul principal este:
TITLE princ
DOSSEG
.MODEL SMALL
INCLUDE param.inc ; Fişierul param.inc care se include în
; program are structura de mai jos
.DATA
num1 DW 9999h, 7777h
num2 DW 6666h, 1111h
suma DW 2 DUP(?)
.CODE
EXTRN calcs:PROC
start: mov ax, @data
mov ds, ax
mov ax, num1
mov par1, ax
mov ax, num1+2
mov par1+2, ax
mov ax, num2
mov par2, ax
mov ax, num2+2
mov par2+2, ax
call calcs
mov ax, result
mov suma, ax
mov ax, result+2
mov suma+2, ax
mov ah, 4ch
int 21h
END start
TITLE calcs

2-61
.MODEL SMALL
INCLUDE param.inc
.CODE
PUBLIC calcs
calcs PROC
mov ax, par1
add ax, par2
mov result, ax
mov ax, par1+2
add ax, par2+2
mov result+2, ax
ret
calcs ENDP
END
Fişierul de includere param.inc conţine următoarea declaraţie de variabile comune:
COMM par1:WORD:2, par2:WORD:2, result:WORD:2.
Pentru crearea unui program executabil din aceste două module, fiecare modul va fi
asamblat separat astfel:
TASM princ
TASM calcs
Apoi se vor edita legaturile pentru cele două module astfel:
TLINK princ calcs
Rezultatul este obţinerea fişierului princ.exe.
Observaţie: Fişierul param.inc trebuie să se afle în acelaşi director cu fişierele princ.asm
şi calcs.asm.

Definirea şi utilizarea procedurilor


Limbajul de asamblare ASM86 implementează conceptul de subrutină cu ajutorul definiţiei
de procedură. Deci, o procedură este o porţiune de program care se poate accesa printr-o
instrucţiune specială de apel şi după execuţia căreia se poate reveni la instrucţinea imediat
următoare celei care a generat apelul, printr-o instrucţiune specială de revenire.
La apelul unei proceduri trebuie satisfăcute următoarele 3 cerinţe:
- instrucţiunea de apel trebuie să salveze adresa următoarei instrucţiuni astfel încât să poată
fi posibilă revenirea din procedură;
- registrele utilizate de procedură trebuie salvate în stivă la intrarea în procedură şi
restaurate înaintea instrucţiunii de revenire din procedură;
- procedura trebuie să poată comunica cu secvenţa apelantă şi, eventual, să întoarcă
rezultate pentru secvenţa apelantă.
Datorită mecanismului specific de adresare (utilizând registre segment) execuţia unei
instrucţiuni de apel sau de reîntoarcere din procedură se poate face în cadrul aceluiaşi segment
sau între 2 segmente diferite. În primul caz, ceea ce trebuie să se salveze/refacă în/din stivă este
numai conţinutul registrului IP, în timp ce în al doilea caz trebuie să se salveze/refacă în/din stivă
şi conţinutul registrului CS.
Definirea şi delimitarea procedurilor într-un program sursă se face cu ajutorul
directivelor PROC şi ENDP, astfel:
nume_procedură PROC [atribut]

2-62
..........
.......... Corpul procedurii
..........
RET
nume_procedură ENDP
unde:
nume_procedură este un identificator cu care se vor face apelurile procedurii respective.
Acest nume are asociată ca valoare adresa primei instrucţiuni din procedură. Ca orice adresă,
această valoare are două componente: adresa de segment şi adresa relativă în segment. În funcţie
de numele atributului sunt semnificative ambele componente sau numai adresa relativă în
segment.
atribut - poate să fie FAR sau NEAR. Dacă atributul lipseşte, pentru el se consideră
valoarea implicită NEAR. Atributul NEAR indică faptul că apelurile la această procedură se fac
fără a schimba conţinutul registrului segment de cod CS (adică se operează numai în segmentul
de cod curent). Atributul FAR indică faptul că apelurile la această procedură se fac şi cu
schimbarea conţinutul registrului segment de cod CS (în stivă se va salva şi adresa de segment
pentru a permite o reîntoarcere corectă în punctul de apel).
În cazul unui apel de procedură putem avea următoarele situaţii de amplasare a procedurii
apelate:
1. În acelaşi segment de cod cu instrucţiunea de apel; în acest caz atributul trebuie să fie
NEAR;
2. Într-un segment de cod diferit de cel care conţine instrucţiunea de apel; în acest caz
atributul trebuie să fie FAR;
3. Într-un alt modul sursă decât cel care conţine instrucţiunea de apel; în acest caz atributul
trebuie să fie FAR, iar numele procedurii trebuie declarat într-o directivă PUBLIC - în modulul
care conţine definiţia procedurii şi într-o directivă EXTRN – în modulul care conţine
instrucţiunea de apel.
Exemplu: Să considerăm următoarea procedură:
PROCED proc FAR
.................
alfa: .................
.................
ret
PROCED endp
Orice instrucţiune de apel a procedurii PROCED are ca efect salvarea în stivă a conţinutului
registrului CS şi apoi a conţinutului registrului IP. La execuţia instrucţiunii de reîntoarcere din
procedură se realizează refacerea corespunzătoare a conţinutului registrelor IP şi CS.
Pentru microprocesoarele I8086/I8088, instrucţiunile pentru apelul procedurilor sunt
următoarele:
1. a) Apel direct intrasegment
CALL DST
unde DST este un deplasament pe 16 biţi, notat DEPL16 ce reprezintă distanţa dintre destinaţia
apelului şi adresa următoarei instrucţiuni de după apel. Se efectuează operaţiile:
SP <----- SP - 2
(SP+1, SP) <----- IP

2-63
IP <----- IP + DEPL16
Exemplu: call NEAR_PROC
b) Apel indirect intrasegment
CALL R16
unde R16 este un registru pe 16 biţi, cu excepţia registrelor de segment.
SP <----- SP - 2
(SP+1, SP) <----- IP
IP <----- R16
Exemplu: call BX
CALL M16
unde M16 este conţinutul unei locaţii de memorie pe 16 biţi.
SP <----- SP - 2
(SP+1, SP) <----- IP
IP <----- (EA+1, EA)
Exemplu: call WORD PTR [bx][si]

2. a) Apel direct intersegment


CALL DST
unde DST este o etichetă depărtată (SEGMENT:OFFSET) - 4 octeţi. Se efectuează operaţiile:
SP <----- SP - 2
(SP+1, SP) <----- CS
SP <----- SP - 2
(SP+1, SP) <----- IP
IP <----- OFFSET
CS <----- SEGMENT
Exemplu: call FAR_LABEL
call FAR_PROC
Cei 4 octeţi ai operandului DST indică adresele de OFFSET şi de SEGMENT.
b) Apel indirect intersegment
CALL M32
Se realizează salt intersegment la adresa precizată prin cei 4 octeţi plasaţi în memorie la
adresa specificată prin operandul M32. Se execută operaţiile:
SP <----- SP - 2
(SP+1, SP) <----- CS
SP <----- SP - 2
(SP+1, SP) <----- IP
IP <----- (EA+1, EA)
CS <----- (EA+3, EA+2)
Exemplu: call DWORD PTR [bx]
Pentru microprocesoarele I8086/I8088, instrucţiunile pentru revenirea în programul apelant
sunt următoarele:
a) Revenire intrasegment

2-64
RET (Return)
IP <----- (SP+1, SP)
SP <----- SP + 2
Instrucţiunea reface din stivă conţinutul indicatorului (numărătorului) de instrucţiuni IP.
b) Revenire intrasegment cu descărcarea stivei (cu POP)
RET EXP** (Return)
unde EXP** este o expresie constantă care se evaluează la o valoare ce se poate exprima printr-
un număr pe 16 biţi. Se realizează operaţiile:
IP <----- (SP+1, SP)
SP <----- SP + 2
SP <----- SP + EXP**
Exemplu: ret 8
Instrucţiunea reface din stivă conţinutul indicatorului (numărătorului) de instrucţiuni IP şi
descarcă stiva cu încă 8 octeţi.
c) Revenire intersegment
RET (Return)
Se realizează operaţiile:
IP <----- (SP+1, SP)
SP <----- SP + 2
CS <----- (SP+1, SP)
SP <----- SP + 2
Instrucţiunea reface din stivă conţinutul indicatorului (numărătorului) de instrucţiuni IP,
precum şi al registrului segment CS.
Observaţie: Tipul lui RET, intrasegment sau intersegment, rezultă din tipul celui mai recent
CALL.
b) Revenire intersegment cu descărcarea stivei (cu POP)
RET EXP** (Return)
unde EXP** este o expresie constantă care se evaluează la o valoare ce se poate exprima printr-
un număr pe 16 biţi. Se realizează operaţiile:
IP <----- (SP+1, SP)
SP <----- SP + 2
CS <----- (SP+1, SP)
SP <----- SP + 2
SP <----- SP + EXP**
Exemplu: ret 20
Instrucţiunea reface din stivă conţinutul indicatorului (numărătorului) de instrucţiuni IP şi al
registrului de segment CS, după care descarcă stiva cu încă 20 octeţi.

Comunicarea parametrilor procedurilor


Există 2 modalităţi de transfer a parametrilor către o procedură:
1) transfer prin valoare;

2-65
2) transfer prin adresă.
Această clasificare are în vedere ceea ce se transmite procedurii relativ la un parametru şi
anume valoarea, în primul caz, respectiv adresa, în cel de-al doilea caz. De asemenea, în cadrul
ambelor tipuri de transfer de mai sus putem avea mai multe situaţii în funcţie de locaţiile efective
utilizate pentru transfer.
Acestea pot fi:
a) registrele procesorului;
b) locaţii "cunoscute" de memorie atât de către secvenţa apelantă, cât şi de către secvenţa
apelată;
c) stiva procesorului.
Pe lângă aceste 3 situaţii mai există o tehnică des folosită: utilizarea blocurilor sau tabelelor de
parametri. În această situaţie, procedurii i se poate transmite fie blocul de parametri respectivi, fie
adresa blocului de parametri.
Transferul parametrilor prin registru
Exemplu: Calculul sumei elementelor unui vector organizat pe cuvinte, cunoscându-se adresa de
început a vectorului şi numărul său de componente. Considerăm că BX conţine adresa de început
a vectorului, CX - numărul de componente ale vectorului, iar suma rezultată este conţinută de
AX.
DATA SEGMENT
VECTOR dw 10 DUP (0102h)
NR_ELEM equ $ - VECTOR
SUMA dw ?
DATA ENDS
COD SEGMENT
ASSUME cs:COD, ds:DATA
start: mov ax, DATA
mov ds, ax
mov bx, OFFSET VECTOR ; Adresa de început a vect. în BX
mov cx, NR_ELEM/TYPE VECTOR ; Numărul de elem. ale vectorului în CX
call NEAR PTR ad_elem ; Apel procedură
mov SUMA, ax ; Rezultatul se depune în variabila SUMA
mov ax, 4c00h
int 21h
ad_elem PROC NEAR ; Procedura pentru calculul sumei elementelor
xor ax, ax ; AX = 0
xor si, si ; SI = 0
REPET: add ax, [bx][si] ; Suma se calculează în AX
add si, 2 ; Se trece la elementul următor
loop REPET
ret
ad_elem ENDP
COD ENDS
END start
Transferul parametrilor prin locaţii cunoscute de memorie
Procedura anterioară poate fi rescrisă astfel încât să adune întotdeauna primele NR_ELEM
elemente ale vectorului VECTOR şi să întoarcă rezultatul în variabila SUMA.

2-66
DATA SEGMENT
VECTOR dw 10 DUP (0102h)
NR_ELEM equ $ - vector
SUMA dw ?
DATA ENDS
STIVA SEGMENT STACK
dw 100 DUP (?)
STIVA ENDS
COD SEGMENT
ASSUME cs:COD, ds:DATA, ss:STIVA
start: mov ax, DATA
mov ds, ax
mov ax, STIVA
mov ss, ax
call NEAR PTR ad_elem ; Apel procedură
mov ax, 4c00h
int 21h
ad_elem PROC NEAR ; Procedura pentru calculul sumei elementelor
push ax
push cx
push si
lea si, VECTOR ; Adresa de început a vectorului în SI
mov cx, NR_ELEM/TYPE VECTOR ; Numărul de elemente ale vectorului în CX
xor ax, ax ; AX = 0
REPET: add ax, [si] ; Suma se calculează în AX
add si, 2
loop REPET
mov SUMA, ax ; Rezultatul se depune în variabila SUMA
pop si
pop cx
pop ax
ret
ad_elem ENDP
COD ENDS
END start
Transferul parametrilor prin stivă
Pentru acelaşi exemplu prezentat mai sus, presupunem că procedurii i se transmit: adresa de
început a vectorului, adresa numărului de elemente şi adresa rezultatului. Secvenţa de program va
arăta astfel:
Param_seg SEGMENT
VECTOR dw 10 DUP (0102h)
NR_ELEM dw $ - VECTOR
SUMA dw ?
Param_seg ENDS
Stack_seg SEGMENT
dw 100 DUP (?)
VIRF LABEL WORD ; Vârful stivei este de tip WORD
Stack_seg ENDS

2-67
Code SEGMENT
ASSUME cs:Code, ds:Param_seg, ss:Stack_seg
START: mov ax, Param_seg ; Se încarcă registrul DS corespunzător
mov ds, ax ; directivei ASSUME
mov ax, Stack_seg ; Se încarcă registrul SS corespunzător
mov ss, ax ; directivei ASSUME
mov sp, OFFSET VIRF ; Vârful stivei se încarcă în SP
mov bx, OFFSET VECTOR ; Adresa relativă a vectorului
push bx ; VECTOR se salvează în stivă
mov bx, OFFSET NR_ELEM ; Adresa relativă a numărului de
push bx ; elemente se salvează în stivă
mov bx, OFFSET SUMA ; Adresa relativă a rezultatului
push bx ; se salvează în stivă
call FAR PTR adun ; Apel procedură adun
mov ax, 4c00h
int 21h
Code ENDS
Code2 SEGMENT
ASSUME cs:Code2
Stack_struc STRUC ; Se defineşte o structură de date salvate în stivă
save_BP dw ? ; Conţinutul lui BP
save_CS_IP dw ?, ? ; Conţinutul lui CS şi IP
par3_adr dw ? ; Adresa relativă a rezultatului SUMA
par2_adr dw ? ; Adresa relativă a nr. de elemente
par1_adr dw ? ; Adresa relativă a vectorului VECTOR
Stack_struc ENDS
adun PROC FAR
push bp ; Se salvează în stivă vechiul conţinut al lui BP
mov bp, sp ; Registrul BP se încarcă cu valoarea lui SP
push ax ; Se salvează conţinutul registrelor AX, CX, SI, DI
push cx
push si
push di
mov si, [bp].par1_adr ; Încarcă în SI adresa de început a vect.
mov di, [bp].par2_adr ; Încarcă în DI adresa nr de elemente
mov ax, [di] ; Încarcă în AX nr. de octeţi ai vect.
mov cl, TYPE VECTOR
div cl
xor ah, ah
mov cx, ax ; Încarcă în CX nu. de elem. ale vect.
mov di, [bp].par3_adr ; Încarcă în DI adresa rezultatului
xor ax, ax ; AX = 0
REPET: add ax, [si] ; Suma elementelor se face în AX
add si, 2
loop REPET
mov [di], ax ; Rezultatul se depune în variabila SUMA
pop di ; Se reface conţinutul registrelor DI, SI, CX, AX
pop si
pop cx

2-68
pop ax
pop bp
ret 6 ; Se descarcă stiva cu 6 octeţi
adun ENDP
Code2 ENDS
END START

După salvarea registrului DI, structura stivei arată ca în figura de mai sus. Ca elemente de noutate
apar următoarele:
1. Salvarea registrului BP în stivă imediat după intrarea în procedură şi utilizarea lui BP pentru
adresarea datelor de pe stivă. Datele adresate reprezintă parametrii transmişi.
2. Definirea unui cadru al stivei cu ajutorul directivei STRUC.
3. Utilizarea, pentru ieşirea din procedură, a unei instrucţiuni RET cu parametru, care descarcă
automat stiva astfel încât la reîntoarcerea în programul principal starea stivei să fie identică
cu cea de dinaintea apelului.

Utilizarea blocurilor (tabelelor) de parametri


Această metodă constă în construcţia unei tabele ce conţine parametri ce trebuie transmişi
procedurii. În acest caz procedurii i se transmite adresa tabelei.
Reluăm exemplul de mai sus referitor la calculul sumei elementelor unui vector, de data
aceasta utilizând un tabel al parametrilor notat TABEL a cărei adresă este introdusă în registrul
BX.
Prog_seg SEGMENT
VECTOR dw 10 DUP (0102h)
NR_ELEM dw $ - VECTOR
SUMA dw ?
TABEL dw ?, ?, ? ; Tabela prin intermediul căreia se transmit parametrii
dw 100 DUP (?) ; Alte 100 cuvinte rezervate pentru stivă
VIRF LABEL WORD ; Vârful stivei este de tip WORD
ASSUME cs : Prog_seg, ds : Prog_seg, ss : Prog_seg
START: mov ax, Prog_seg ; Se încarcă registrele DS şi SS
mov ds, ax ; corespunxător directivei ASSUME
mov ss, ax ;
mov sp, OFFSET VIRF ; Vârful stivei se încarcă în SP

2-69
mov TABEL, OFFSET VECTOR ; Se completează tabela cu
mov TABEL+2, OFFSET NR_ELEM ; adresele relative ale
mov TABEL+4, OFFSET SUMA ; parametrilor
mov bx, OFFSET TABEL ; Adresa relativă a tabelei în BX
call NEAR PTR adun ; Apel procedură adun
mov ax, 4c00h
int 21h
;
adun PROC NEAR ; Procedura de adunare
push ax ; Se salvează conţinutul registrelor AX, CX, SI, DI
push cx
push si
push di
mov bx, OFFSET TABEL ; Încarcă în BX adresa de început a tabelei TABEL
mov si, [bx] ; Încarcă în SI primul element al tabelei
; (adresa deînceput a vectorului VECTOR)
mov di, [bx+2] ; Încarcă în DI adresa numărului de elemente
mov ax, [di] ; Încarcă în AX numărul de octeţi al vectorului
mov cl, TYPE VECTOR ; CL = 2
div cl
xor ah, ah ; AH = 0
mov cx, ax ; Încarcă în CX numărul de elemente ale vectorului
mov di, [bx+4] ; Încarcă în DI adresa rezultatului
xor ax, ax ; AX = 0
REPET: add ax, [si] ; Suma elementelor se face în AX
add si, 2
loop REPET
mov [di], ax ; Rezultatul se depune în variabila SUMA
pop di ; Se reface conţinutul registrelor DI, SI, CX, AX
pop si
pop cx
pop ax
ret
adun ENDP
Prog_seg ENDS
END START

2-70
CAP. 3. PROGRAMAREA SISTEMATICĂ A APLICAŢIILOR DE
SUPRAVEGHERE ŞI CONDUCERE ÎN TIMP REAL A PROCESELOR
INDUSTRIALE

Un sistem de calcul pentru conducerea unui proces reprezintă o unitate dialectică între
componenta hardware a sa, cea care defineşte configuraţia sistemului, şi componenta sa software,
care constituie totalitatea programelor sistemului. Programele implementate pe un astfel de sistem
de calcul se împart în două mari categorii:
a) programe de sistem;
b) programe de utilizator sau de aplicaţie.
Programele de sistem - sunt programe care au un caracter universal şi sunt parte
componentă a unui anumit tip de calculator, independent de procesul pe care-l va conduce. Acest
ansamblu de programe formează ceea ce se numeşte sistemul de operare al calculatorului şi are
rolul de a asigura executarea corectă a sarcinilor sale. O funcţie foarte importantă a SO este aceea
de a asigura interfaţa între calculator şi utilizator, altfel spus el este interpretul cerinţelor
utilizatorului exprimate într-un limbaj adecvat, cerinţe care trebuie satisfăcute cu ajutorul
instrucţiunilor maşină prin planificarea adecvată a componentelor hardware (HW) a sistemului de
calcul (SC).
Natura funcţiilor, precum şi modul în care acestea sunt realizate, determină atributele care
caracterizează şi departajează sistemele de operare.
Sistemele de calcul destinate conducerii proceselor industriale trebuie să posede în mod
necesar SO în timp real cu facilităţi multitasking. Privit prin prisma utilizatorului şi a programelor
de aplicaţie, ansamblul de programe al acestui tip de SO poate fi împărţit în două categorii:
- programe necesare în faza de pregătire, elaborare şi testare a programelor de aplicaţie
(editorul de texte, compilatorul, link-editorul, debuggerul etc.), numite, din acest motiv, şi
programe de serviciu;
- programe necesare în etapa de conducere, care se leagă cu programele utilizatorului în
faza de dezvoltare, formând aplicaţia dedicată care se implementează pe echipamentul de
conducere.
Programele de utilizator (de aplicaţie sau de conducere), în opoziţie cu programele de
sistem, au un caracter specific, funcţie de proces, ele fiind o imagine a ceea ce se întâmplă în
proces.
O particularitate esenţială a ansamblului programe de sistem - programe de aplicaţie constă
în aceea că acestea trebuie să realizeze atributele de timp real, adică să precizeze cu exactitate
locul şi timpul desfăşurării evenimentelor din procesul condus. Pentru programarea sistemelor de
calcul care să răspundă acestor cerinţe se folosesc două tehnici de bază:
1. Utilizarea mecanismului de întreruperi al microprocesorului şi a ceasului de timp real,
problemele specifice timpului real fiind rezolvate de la caz la caz prin tehnici mai mult sau puţin
unitare şi sistematice. Acest procedeu este mai puţin accesibil unui utilizator obişnuit necesitând
un efort mai mare precum şi cunoştinte fine de programare în limbajul microprocesorului.
Metoda are însă avantajul că programul, odată pus la punct, oferă un optim din punct de vedere al
eficienţei şi al timpului de răspuns.
2. Utilizând facilităţile multitasking ale unui program special creat, numit EXECUTIV de
timp real implementat pe echipament în acest scop. Acest al doilea procedeu este mai avantajos
pentru utilizator din punct de vedere al programării. Utilizatorul are posibilitatea să realizeze
cerinţele de timp real ale aplicaţiei utilizând serviciile pe care le poate oferi acest EXECUTIV,

3-1
servicii care apar în programul utilizatorului sub forma unor apeluri de subrutine (instrucţiuni
CALL) sau macrouri de apel. Aceste subrutine, parte componentă a EXECUTIVULUI (pe care
utilizatorul le poate doar utiliza, dar nu modifica), poartă denumirea de directive sau primitive,
deoarece la nivelul taskului se comportă ca şi instrucţiunile, deci sunt indivizibile şi
neîntreruptibile. Ele au o semantică uşor accesibilă şi pot fi utilizate fară a fi necesară cunoaşterea
modului lor de implementare în SW-ul EXECUTIVULUI. Pentru a şti dacă o directivă a lucrat
sau nu, unul din parametrii ei, numit parametru de stare al directivei ne indică acest lucru prin
diferitele valori pe care le returnează.
Astfel, programul aferent unei anume aplicaţii, reprezintă un ansamblu de instrucţiuni scrise
de utilizator în care sunt incluse şi cererile de servicii către EXECUTIV în vederea obţinerii
atributelor de timp real. În realitate, EXECUTIVUL foloseşte mecanismul de întreruperi şi ceasul
de timp real, dar aceasta este o activitate programată o singură dată şi utilizată ulterior ori de câte
ori este nevoie. În felul acesta programatorul va fi preocupat mai puţin de aspectele particulare
ale implementării diferitelor comenzi, concentrându-se strict asupra organizării programului de
aplicaţie. În plus, performanţele acestor programe sunt comparabile cu cele din cazul anterior
oferind însă avantaje nete în ceea ce priveşte flexibilitatea, extensibilitatea şi portabilitatea lor.

Arhitectura programelor de aplicaţie

Bazându-ne pe existenţa unui EXECUTIV în timp real putem aborda în mod sistematic
dezvoltarea programelor de aplicaţie pe baza următoarelor elemente:
1. Definirea conceptului de "echipament virtual de conducere", un echipament ipotetic
(care nu există fizic), dar care înglobează caracteristicile unor echipamente de conducere
existente, cărora le va fi destinat programul de aplicaţie. Aceste echipamente au o structură de
tipul celei din Fig. 3.1.

Fig. 3.1.

Ca atare, configuraţia echipamentului virtual, poate fi definită, din punct de vedere al


utilizatorului, astfel:
- unitatea centrală cu microprocesor I80x86 sau de alt tip;
- modul de intrări analogice;
- modul de ieşiri analogice;
- modul de intrări numerice;
- modul de ieşiri numerice;
- consolă operator (display + tastatură + imprimantă);
- 8 sau mai multe nivele de întrerupere;
- ceas de timp real;
- interfaţă de comunicare cu nivelul ierarhic superior.
Utilizatorul va fi preocupat de modul de scriere a aplicaţiei, având în minte structura acestui
echipament virtual şi mai puţin modul cum se comandă concret modulele specificate mai sus.

3-2
2. Scrierea şi organizarea executivului astfel încât să fie compatibil cu conceptul de
echipament virtual. Aceasta presupune organizarea lui pe două categorii de module SW
(software) având următoarele caracteristici:
- o primă categorie de module nu trebuie să conţină nimic legat de structura concretă a
vreunui echipament fizic, adică să fie independentă de echipament, având deci o portabilitate de
100%;
- a doua categorie de module pe care o vom numi "interfaţa între echipamentul virtual şi
echipamentul real" depinde de echipament şi formează o bibliotecă ce conţine o serie de
proceduri specifice, purtând nume dedicate.
În felul acesta, odată scris EXECUTIVUL şi puse la punct interfeţele cu diferitele
echipamente reale, utilizatorul îşi scrie programul de aplicaţie pe un sistem de dezvoltare
utilizând serviciile executivului şi procedurile de interfaţă aferente acestui sistem. După scrierea,
depanarea şi testarea programului, schimbând interfaţa se va obţine aplicaţia destinată
echipamentului fizic real (ţintă). Comutarea de la o interfaţă la alta se realizează link-editând
programul cu o bibliotecă sau alta, funcţie de situaţie, programul nu suferă nici o modificare,
procedurile din interfaţă având, aşa cum am mai spus, nume dedicate.
Din cele de mai sus rezultă următoarea arhitectură a programului de aplicaţie:

Fig. 3.2.

Pentru clasa echipamentelor de conducere, "interfeţele" ar trebui să conţină următoarele


subrutine şi funcţii:
- subrutină de programarea sistemului prioritar de întreruperi (circuitelor din familia
8259);
- subrutină de poziţionare şi citire a măştilor circuitului 8259;
- subrutină de achitare a întreruperii (uzual se lucrează în modul nespecificat);
- funcţie pentru preluarea unui caracter de la tastatură în urma unei întreruperi;

3-3
- subrutină de transmisie a unui caracter la display în urma unei întreruperi de tip TxRDY
(interfaţă gata de transmisie);
- subrutină de programare a circuitului 8253 (ceasul de timp real);
- subrutina de programare a circuitului 8251 (USART - comunicaţii asincrone seriale);
- subrutină de selecţie a canalului analogic de intrare şi declanşare a conversiei analog -
numerice;
- funcţie de preluare a valorii de la convertorul analog-numeric în urma unei întreruperi de
tip EOC (End Of Convertion);
- subrutină pentru ieşiri numerice;
- subrutină pentru ieşiri analogice (transmise prin intermediul convertorului numeric
analogic);
- subrutină pentru tratarea intrărilor numerice.
Pe baza celor spuse mai sus, programarea sistemică a unei aplicaţii de supraveghere şi/sau
conducere în timp real a unui proces presupune parcurgerea următoarelor etape:
- scrierea EXECUTIVULUI de timp real compatibil cu conceptul de echipament virtual;
- scrierea "interfeţelor" pentru clasa de echipamente avută în vedere;
- descompunerea în taskuri a programului de aplicaţie având în vedere ca taskurile
componente să fie disjuncte sau să interacţioneze cât mai slab;
- programarea pe sisteme de dezvoltare a aplicaţiei (descompusă în taskuri) utilizând
principiile programării paralele şi serviciile EXECUTIVULUI de timp real;
- depanarea şi testarea în mediu simulat a programului astfel obţinut;
- link-editarea programului cu interfaţa corespunzătoare echipamentului real;
- implementarea aplicaţiei pe echipamentul real.
Primele două etape, deşi necesită un efort de programare considerabil, se parcurg o singură
dată, rezultatele putând fi folosite în toate aplicaţiile ulterioare destinate unei anumite clase de
echipamente.
Următoarele două etape par, la prima vedere, că trebuie complet dezvoltate, în mod
specific, pentru fiecare aplicaţie în parte. Dar, şi în aceste cazuri, datorită descompunerii
programelor în taskuri, pot fi refolosite, de la o aplicaţie la alta, o serie de produse program
reprezentând taskuri comune mai multor aplicaţii (taskuri de achiziţie şi conversie de date din
proces, taskuri de reglare etc.). Se obţine astfel, şi la acest nivel, posibilitatea de tipizare şi
refolosire a unor produse program, ceea ce va uşura şi va reduce substanţial activitatea de
programare a unei aplicaţii.
De asemenea, procedând în această manieră, programarea unei aplicaţii poate fi începută de
un programator sau de un grup de programatori şi poate fi modificată şi dezvoltată fără probleme
de alt grup de programatori care sunt familiarizaţi însă cu metodologia de programare prezentată
mai sus. În cazul realizării unei aplicaţii după concepţii mai mult sau mai puţin particulare şi
nesistematice, acest deziderat este, în general, foarte greu de realizat.
În cele ce urmează, după prezentarea unor probleme specifice sistemelor de operare în timp
real, va fi prezentată modalitatea de proiectare şi scriere a unui EXECUTIV în timp real.

3-4
CAP.4. SISTEME DE OPERARE ÎN TIMP REAL

Un sistem de operare este o colecţie organizată de programe numite programe de sistem,


care:
a) realizează o interfaţă între utilizator şi sistemul de calcul extinzând setul de operaţii
executate de calculator, minimizând efortul de programare a calculatorului şi optimizând
interacţiunea om-calculator;
b) gestionează resursele calculatorului, în sensul optimizării utilizării lor.
În funcţie de complexitatea sistemului de calcul, programele de sistem se numesc:
- program monitor;
- program executiv;
- program de comandă;
- sistem de operare.
În general, sistemele de calcul mici şi, în special, cele dedicate dispun doar de un monitor
care asigură un minim de servicii utilizatorului, cum ar fi: vizualizarea conţinutului memoriei,
modificarea conţinutului memoriei RAM, vizualizarea conţinutului registrelor şi a indicatorilor
de stare (condiţie) precum şi modificarea valorilor lor, compararea unor zone de memorie etc.
Sistemele de calcul complexe lucrează sub comanda unui sistem de operare.

4.1. Funcţiile unui S.O.


Principalele funcţii asigurate de S.O. actuale sunt:
4.1.1. Funcţia de asistenţă a utilizatorului. Obiectivele urmărite sunt:
a) Furnizarea unui limbaj de comandă care permite introducerea de către utilizator a unor
parametri şi opţiuni pentru utilizarea resurselor fizice şi logice ale sistemului. Realizarea acestei
funcţiuni se face cu ajutorul unui interpreter de comenzi.
b) Furnizarea unor programe (editoare de legături) care realizează legarea diferitelor
module ale unui program sau a mai multor programe de utilizator şi a unor subrutine din
biblioteci de programe într-un singur program executabil. Aceasta permite o mare flexibilitate în
programare, pentru că, diversele module ale programului pot fi iniţial scrise în limbaje diferite,
care să asigure o programare optimă pentru modulul respectiv.
c) Existenţa unor sisteme de gestiune a bibliotecilor de programe destinate înscrierii,
păstrării, actualizării şi eliminării programelor prezente;
d) Furnizarea unui set de macroinstrucţiuni care să permită utilizatorului folosirea în
programele proprii a unor funcţii specifice S.O. (de exemplu subrutine de lucru cu dispozitivele
de I/E).
e) Furnizarea unor programe utilitare pentru editarea programelor de utilizator şi pentru
manipularea informaţiei prezente sub formă de fişiere, programe de copiere a fişierelor etc.
f) Furnizarea unui limbaj de control de tip conversaţional, de dialog între operator şi sistem.
De obicei, S.O. au un limbaj de comandă de tip cu autodocumentare datorită unor puternice
funcţii HELP pe care le au implementate.
4.1.2. Funcţia de asistenţă a execuţiei. S.O. trebuie să permită:
a) Izolarea logică a dispozitivelor defecte şi asigurarea condiţiilor pentru o eventuală
execuţie a lucrărilor cu ajutorul resurselor rămase utilizabile.
b) Testarea automată şi diagnosticarea defectelor.

4-1
c) Afişarea automată a informaţiei de stare.
S.O. sunt dinamice, în sensul că, în permanenţă pot fi adăugate noi funcţii sau rescrise
programele ce realizează funcţii deja implementate.
4.1.3. Funcţia de gestiune. Principala sarcină a unui S.O. este aceea de gestiune a
resurselor sistemului de calcul: unitatea centrală, memoria principală (internă), perifericele de I/E,
bibliotecile şi fişierele de date. Programele pentru gestiune ale unui S.O. pot fi împărţite în 4 mari
categorii:
1) Funcţia de gestiune a memoriei, cu următoarele atribute:
- ţine evidenţa utilizării memoriei, adică permite cunoaşterea în orice moment a zonelor
de memorie libere şi ocupate;
- decide ce proces primeşte memorie, când şi ce cantitate de memorie i se alocă. Alocarea
memoriei se face atât pentru păstrarea programului corespunzător procesului cât şi pentru
necesităţile de execuţie.
- asigură tehnici corespunzătoare de protecţie a memoriei;
- dezalocă resursa când procesul s-a încheiat sau nu mai are nevoie de o anumită cantitate
de memorie.
2) Funcţia de gestiune a procesorului şi proceselor:
- ţine evidenţa procesorului precum şi evidenţa stării proceselor;
- decide prioritatea în utilizarea procesorului, în funcţie de prioritatea lucrărilor ce trebuie
executate;
- planificatorul lucrărilor alocă resursele procesorului necesare realizării unui proces
(lucrare);
- eliberează resursa când procesul nu mai are nevoie de procesor sau când s-a depăşit o
anumită cuantă de timp alocată pentru utilizare.
3) Funcţia de gestiune a dispozitivelor periferice are rolul de a aloca resursele şi a
iniţializa operaţiile de I/E precum şi de a dezaloca aceste resurse când operaţiile de I/E s-au
încheiat.
4) Funcţia de gestiune a informaţiei:
- ţine evidenţa resurselor (fişierelor) şi localizarea acestora pe suporturi magnetice;
- oferă rutinele de acces la informaţie;
- alocă şi dezalocă informaţie prin funcţia de deschidere şi respectiv de închidere a
fişierelor.
Deci, putem spune că:
- funcţia de gestiune trebuie să prevadă funcţiile de control automat prin rutine
specializate asupra tuturor resurselor fizice şi logice ce apar;
- să asigure o cât mai mare independenţă a programelor utilizator faţă de particularităţile
sistemului pe care s-a implementat S.O.;
- să rezolve toate problemele de control al funcţionării sistemului printr-un procedeu
performant de tratare a întreruperilor (utilizarea întreruperilor permite un dialog foarte flexibil
între U.C. şi mediul extern, permiţând semnalarea promptă a diverselor evenimente interne sau
externe);
- să permită modificarea configuraţiei de echipamente periferice, fără ca aceasta să
afecteze programele deja implementate.
Din punct de vedere al utilizatorului, S.O. apare ca o interfaţă între programele sale de
aplicaţii şi echipamentele (elementele) sistemului de calcul, care poate fi reprezentată printr-o
structură ierarhică de forma din Fig. 4.1.

4-2
Se observă că accesul direct la resursele sistemului de calcul este puternic limitat de
existenţa a două nivele intermediare: procesorul de limbaj şi S.O. Fiecare nivel introduce funcţii
noi inexistente la nivelele inferioare definind o maşină virtuală corespunzătoare acelui nivel.

Fig. 4.1.

4.2. Structura sistemelor de operare


Componentele în care se descompune un S.O. sunt situate la diferite nivele ierarhice, având,
de exemplu, structura din Fig. 4.2. Plasarea unei funcţii a S.O. pe unul din cele trei nivele se
realizează pe baza depărtării funcţiei respective de echipamentul fizic. Acest aspect este foarte
evident în toate calculatoarele care folosesc S.O. şi, în special, pentru S.O. scrise în limbaje
evoluate.

S.O. pot fi scrise într-un limbaj de nivel evoluat numai la nivelele superioare, care nu
interacţionează direct cu maşina fizică.
Existenţa nucleului este obligatorie în orice S.O. Nucleul conţine funcţiile privind tratarea
operaţiilor de I/E la nivel fizic, tratarea întreruperilor, tratarea sincronizării şi comunicării între
procese, care sunt scrise, de obicei, în cod maşină sau limbaj de asamblare. Funcţiile care
formează nucleul S.O. sunt intens utilizate de celelalte două nivele superioare şi, din această
cauză, se implementează prin secvenţe de program rezidente în M.O. într-o zonă special rezervată
acestui scop.
Funcţiile de suport pentru execuţia programului sunt apelate în timpul execuţiei unui
program printr-un procedeu asemănător apelului macroinstrucţiunilor, adică prin folosirea unor
parametri. Nu toate funcţiile acestui nivel sunt rezidente în memorie, ci numai acele funcţii care
sunt cel mai des utilizate, iar celelalte se încarcă numai în funcţie de necesităţi.
Nivelul superior (3) constă din programe relativ rar apelate, care permit aducerea unui
program în starea în care să poată fi executat. Programele scrise în limbaje evoluate utilizează
S.O. tocmai la acest nivel.
Orice acces al programelor utilizator la funcţiile de la nivelele 2 şi 1 se realizează indirect
(şi din această cauză, acest nivel se numeşte suport de pregătire a programelor). Apelul la
componentele S.O. se realizează printr-un limbaj de comandă specific S.O. respectiv.
Într-o succesiune normală, un program de aplicaţie parcurge, înainte de a fi executat,
următoarele etape: introducerea în sistem, compilarea, editarea de legături, activarea programului.

4-3
Nu este obligatoriu ca toate lucrările să parcurgă toate aceste etape. Sunt lucrări la care fiecare
fază poate să apară o dată sau de mai multe ori.
Fiecăreia din etapele prezentate, în S.O. îi corespund programe specifice: compilatoare,
editoare de legături, editoare de rapoarte pentru prezentarea rezultatelor etc.

4.3. Caracteristici ale S.O.


Modul în care diversele S.O. implementează funcţiile specifice determină atributele S.O.
Punerea în evidenţă a acestor atribute este foarte importantă pentru că reprezintă un mijloc
obiectiv de comparare între diverse S.O.
Fiecare S.O. prezintă anumite caracteristici specifice, dar pot fi puse în evidenţă şi câteva
caracteristici de ordin general, valabile în orice sistem de operare, din care putem enumera:
1) Timpul de răspuns, calculat ca intervalul de timp între lansarea unei comenzi (cereri de
servicii către executiv) şi achitarea acesteia de către sistem. Acest atribut are în general două
componente distincte şi anume:
- timpul de aşteptare corespunzător intervalului de timp pentru ca cererea să fie luată în
considerare;
- timpul de execuţie (timpul necesar pentru a efectua operaţiile specifice cererii).
2) Simultaneitatea utilizării, se referă la gradul în care un sistem de calcul poate fi utilizat în
acelaşi timp de mai mulţi utilizatori (multiprogramare) sau să execute simultan mai multe
programe (lucrări) ale aceluiaşi utilizator (multitasking).
3) Eficienţa, reprezintă proprietatea S.O. de a folosi în mod optim resursele de care dispune
sistemul de calcul.
4) Partajarea şi protecţia, caracterizează gradul în care utilizatorii au posibilitatea să
utilizeze în comun informaţia prezentă în sistem, modul în care ei pot să comunice între ei fără ca
execuţia programelor specifice unui utilizator să afecteze execuţia programelor celorlalţi
utilizatori. Este necesar ca, interacţiunea dintre utilizatori să nu conducă la alterarea intenţionată
sau accidentală a informaţiei.
5) Generalitatea, flexibilitatea, extensibilitatea, măsoară gradul în care un S.O. poate fi
adaptat pe alte sisteme de calcul decât sistemul pentru care a fost creat. De asemenea, indică
gradul în care un S.O. poate fi dezvoltat, fie prin modificarea unora din funcţiile deja
implementate, fie prin introducerea de noi funcţii şi componente software şi hardware fără
eforturi deosebite de programare şi proiectare.
6) Fiabilitatea şi disponibilitatea unui S.O. este strâns legată de fiabilitatea întregului sistem
de calcul şi exprimă proprietatea sistemului de a funcţiona în continuu, fără a avea goluri de
funcţionare din cauza defectării sau blocării unor componente ale sale. Creşterea fiabilităţii se
poate face pe două căi:
- creşterea fiabilităţii componentelor hardware şi software precum şi introducerea rezervării
unor blocuri critice;
- utilizarea unor S.O. şi programe tolerante la defecte; aceasta înseamnă că, în cazul
apariţiei unor anomalii de funcţionare, S.O. asigură în continuare desfăşurarea activităţii
sistemului, acceptându-se o degradare a performanţelor în anumite limite impuse care nu
afectează însă esenţa activităţii sistemului.
Un accent deosebit se pune pe fiabilitatea şi disponibilitatea sistemelor în cazul utilizării
acestora pentru prelucrări în timp real.
7) Transparenţa şi vizibilitatea. Transparenţa indică gradul în care realizarea funcţiilor S.O.
se face fără aportul utilizatorului. Pentru utilizator, ceea ce se află sub interfaţa de utilizare care i
se oferă trebuie să fie invizibil, deci realizarea efectivă a funcţiilor S.O. trebuie să fie invizibilă.

4-4
Vizibilitatea indică măsura în care un utilizator poate avea acces la programele ce implementează
anumite funcţii ale S.O. Există situaţii în care, deşi nu este absolut necesar, utilizatorul are nevoie
să cunoască anumite informaţii specifice activităţii S.O. pentru a putea creşte eficienţa
programelor sale de aplicaţie.

4.4. Tipuri de sisteme de operare


Plecând de la caracteristicile S.O. şi având în vedere şi destinaţia sistemului de calcul
utilizat, s-a ajuns la următoarea clasificare a S.O.:
- S.O. secvenţiale;
- S.O. cu multiprogramare;
- S.O. în timp real;
- S.O. cu prelucrare multiplă.
Un sistem de operare secvenţial permite executarea, la un moment dat, a unui singur
program care trebuie terminat înainte de a se lua în considerare un alt program. Principalul
dezavantaj al acestui tip de S.O. este timpul de răspuns mare comparativ cu timpul de operare al
unităţii centrale.
Sistemele cu multiprogramare acceptă la un moment dat mai multe programe în memoria
centrală partajată, acestea aflându-se în diverse stadii de execuţie. Execuţia acestor programe se
realizează prin multiplexarea unităţii centrale, urmărindu-se obţinerea, la un grad de
simultaneitate cât mai ridicat, a unui timp de răspuns cât mai mic şi a unei eficienţe de utilizare
maximă. În acest caz utilizatorul nu poate să intervină la nivelul S.O. pentru a dirija modul de
execuţie a programului.
Un S.O. în timp real este dedicat unei anumite clase de aplicaţii. Prelucrarea în timp real
presupune o viteză de răspuns foarte mare pentru că toate cererile din proces trebuie luate în
considerare imediat ce au fost formulate.
Noţiunea de timp de răspuns este foarte elastică, domeniul de variaţie al acestuia fiind
foarte larg în funcţie de domeniul de utilizare al sistemului de calcul (microsecunde pentru
procese foarte rapide, până la ore în dirijarea unor procese economice).
În general, aplicaţiile implementate pe echipamente de calcul ce funcţionează în timp real
sunt în buclă infinită şi presupun o baleiere permanentă a datelor sosite din proces concomitent cu
calculul comenzilor corespunzătoare, iar intervenţia din partea operatorului este minimă.
Complexitatea S.O. în timp real este mult mai mare decât a celorlalte tipuri de S.O. pentru
că se impun performanţe deosebite pentru a satisface într-un timp critic diversele cereri sosite din
exterior.
Deoarece, în multe astfel de sisteme apare problema cooperării între diversele programe
executate, trebuie rezolvate probleme sofisticate privind sincronizarea şi comunicarea între
programe.
Un sistem de calcul dotat cu un S.O. cu prelucrare multiplă dispune de mai multe
procesoare care pot să execute simultan unul sau mai multe programe. În cazul execuţiei mai
multor programe independente, avem de-a face cu efectul de multiprogramare menţionat mai sus,
dar cu performanţe mult îmbunătăţite.
În cazul execuţiei simultane a unui singur program de către mai multe unităţi trebuie să
existe posibilitatea de descopunere a acestui program în părţi componente numite sarcini de
program sau taskuri, care în timpul execuţiei trebuie să coopereze între ele în vederea atingerii
obiectivului urmărit de program în ansamblu.
Un sistem de operare care oferă posibilitatea de a executa în paralel (sau simultan) mai
multe programe (taskuri) care interacţionează între ele, părţi componente ale unui program dat,
poartă denumirea de S.O. cu facilităţi multitasking.

4-5
Menţionăm însă că nici multiprogramarea şi nici multitaskingul nu impun capacitatea de
prelucrare multiplă din partea sistemului de calcul, deci astfel de S.O. pot fi implementate şi pe
sisteme monoprocesor.
Sistemele de calcul destinate conducerii proceselor industriale trebuie să posede în mod
necesar sisteme de operare în timp real cu facilităţi multitasking. O particularitate esenţială a unui
astfel de S.O. este aceea că el trebuie să fie accesibil utilizatorului care îi poate cere o serie de
servicii în vederea realizării evoluţiei dorite a programului.
Privit prin prisma utilizatorului şi a programelor de aplicaţii, ansamblul de programe al
acestui tip de S.O. poate fi împărţit în două categorii:
- programe necesare în faza de pregătire, elaborare şi testare a programelor de aplicaţii
(editorul de texte, compilatorul, link-editorul, debuggerul etc.) numite, din acest motiv, şi
programe de serviciu;
- programe necesare în etapa de conducere, care se leagă cu programele utilizatorului în
faza de dezvoltare, formând aplicaţia dedicată care se implementează pe echipamentul de
conducere.
Pentru a nu încărca în mod nejustificat atât din punct de vedere hardware cât şi software
echipamentul de calcul destinat conducerii procesului industrial, dezvoltarea aplicaţiei se va face
pe un alt sistem numit sistem de dezvoltare care va conţine ambele categorii de programe.

4.5. Principiile programării paralele


Consideraţii generale
Programarea paralelă sau concurentă este activitatea de scriere a unui program care conţine
o serie de părţi componente necesar a se afla în execuţie în acelaşi moment.
Orice aplicaţie în timp real conţine astfel de operaţii paralele care reprezintă etape de
execuţie asincronă a acesteia. Aşa cum am menţionat în capitolul anterior, părţile componente ale
programului ce pot fi executate în paralel poartă denumirea de taskuri. Din punct de vedere al
sistemului de calcul, taskul este cea mai mică unitate de prelucrare căreia i se atribuie o identitate.
Taskul reprezintă un program în formă executabilă compus dintr-o succesiune de
instrucţiuni executate secvenţial şi care realizează de obicei o anumită funcţie.
Dacă un task este încărcat şi executat în orice zonă a memoriei principale spunem că taskul
este relocabil. Fiecărui task i se asociază un indicator de importanţă numit prioritate. Alocarea
priorităţii poate fi fixă sau dinamică. În cazul priorităţilor fixe, înseamnă că, unui task i se alocă,
în faza de proiectare a aplicaţiei, o prioritate şi că aceasta nu poate fi modificată indiferent de
evoluţia ulterioară a procesului, pe când în cazul alocării dinamice a priorităţii, prioritatea unui
task se poate modifica pe baza anumitor criterii prestabilite în funcţie de evenimentele ce au loc
în proces. Alocarea dinamică a priorităţii este realizată de S.O., iar dezavantajul acestui procedeu
îl constituie complexitatea sporită a gestiunii lucrărilor (taskurilor).
Taskurile sunt activate în funcţie de priorităţile lor de o componentă a S.O. numită
PLANIFICATOR (SCHEDULER).
Rutinele (ROUTINES) sunt unităţi mai mici de program destinate tratării rapide a unor
evenimente. Sunt activate direct de S.O. la detectarea producerii unor evenimente în procesul
industrial. Detectarea acestor evenimente se realizează de regulă prin intermediul sistemului de
întreruperi al sistemului de calcul.
Subrutinele (SUBROUTINES) sunt cele mai mici unităţi de program apelate de taskuri.
Acestea pot fi: dedicate, adică specifice unui singur task sau comune, situaţie în care pot fi
apelate de mai multe taskuri sau rutine. Spre deosebire de taskuri care sunt întreruptibile,

4-6
subrutinele nu sunt întreruptibile, adică nu se acceptă întreruperea activităţii unei subrutine pentru
a trece la execuţia unui alt task. Acest lucru se datoreşte faptului că, în general, subrutinele
implică un timp de răspuns foarte mic, critic sau, altfel spus, sunt asociate unor evenimente
critice.
Există şi aşa numitele subrutine reentrante disponibile mai multor taskuri şi care pot fi
întrerupte deoarece nu sunt asociate unor evenimente critice.
Vom spune că două taskuri sunt paralele sau concurente dacă prima instrucţiune a unui task
demarează înainte ca ultima instrucţiune a celuilalt task să fi fost completată.
Dacă sistemul de calcul (conducere) este multiprocesor, paralelismul execuţiei taskurilor
poate fi asigurat în mod real în sensul că fiecare task poate fi executat de către un procesor. În
acest caz, se obţine o execuţie paralelă suprapusă în timp, numită şi execuţie paralelă fizică.
Dacă echipamentul de calcul este monoprocesor şi dotat cu un S.O. în timp real cu facilităţi
multitasking, execuţia paralelă a taskurilor se va face intercalat, pe principiul distribuirii timpului
unităţii centrale între taskuri ("time slicing"). La un moment dat, va deţine controlul procesorului
un singur task, dar datorită vitezei mari de lucru a acestuia, precum şi datorită modului de
programare se lasă impresia că taskurile se execută simultan, ca şi când fiecare task ar beneficia
de un procesor propriu - virtual, evident ceva mai lent. În acest caz, se spune ca are loc o execuţie
pseudo-paralelă sau o execuţie paralelă logică .
În cele ce urmează ne vom referi la acest din urmă mod de execuţie paralelă a taskurilor,
ceea ce corespunde situaţiei mai frecvent întâlnite în aplicaţiile de conducere şi supraveghere
automată a proceselor.
Pentru a putea realiza acest paralelism în prelucrarea taskurilor, arhitectura sistemelor de
calcul trebuie să conţină obligatoriu canale care să execute toate operaţiile de transfer de
informaţie, independent de procesor. Procesorul va avea doar rolul de a iniţia şi iniţializa operaţia
de I/E printr-un dialog adecvat cu canalul. În continuare canalul execută toate operaţiile de
transfer necesare, iar în încheiere semnalează procesorului, printr-un semnal de întrerupere, că şi-
a încheiat activitatea. Aceasta presupune existenţa unui sistem de întreruperi bine pus la punct.
Exemplu de execuţie a taskurilor în regim de multiprogramare
Considerăm cazul unui sistem în care există disponibile simultan trei taskuri T1, T2, T3.
Taskul T1 are prioritatea maximă, dar la iniţializarea sistemului, se presupune că este gata pentru
execuţie taskul T3.
Schematic, ocuparea de către cele trei taskuri a procesorului şi activitatea S.O. şi a canalelor
de I/E este reprezentată în următoarea diagramă.

4-7
Haşurat s-a reprezentat starea activă a unui task, a S.O. sau a CANAL-ului.
*** - reprezintă starea blocată a unui task, adică starea în care acesta nu poate fi executat,
fiind în aşteptarea unei resurse (pentru exemplul dat, resursa este un canal I/E).
------ reprezintă starea de întrerupere a unui task.
Iniţial, la pornirea sistemului, se execută programe specifice S.O. Acesta, va da la un
moment dat, controlul primului program gata de execuţie, adică taskului T3. La momentul (1),
taskul T3 iniţiază o operaţie de I/E. După ce transmite canalului toţi parametrii necesari executării
operaţiei de I/E, T3 trece în starea blocat pentru că aşteaptă rezultatele operaţiei de I/E iniţiate.
Aceasta conduce la preluarea controlului de către S.O., care va selecta acum taskul T1 (task care
are prioritate maximă în acest moment) căruia îi va da controlul.
La momentul (2) canalul lansează o întrerupere către procesor indicând încheierea operaţiei
de I/E iniţiată de taskul T3 ceea ce duce la suspendarea taskului T1 aflat în execuţie (trecerea lui
în starea întrerupt) controlul preluându-l S.O., care trece la o subrutină de tratare a întreruperii
sosite. După acceptarea şi tratarea întreruperii, taskul T3 trece din starea blocat în starea întrerupt.
Aceasta înseamnă că, din acest moment, execuţia taskului T3 poate fi reluată imediat ce se
încheie execuţia taskurilor de prioritate superioară.
După terminarea tratării întreruperii, la momentul (3) se reia execuţia taskului T1 pentru că
acesta este, în acest moment, de prioritate maximă. La momentul (4) şi taskul T1 lansează o
operaţie de I/E, după care trece în starea blocat, redând controlul S.O. Acesta va lansa în execuţie
la momentul (5) taskul cu prioritate maximă în acel moment, în cazul nostru taskul T2. După
terminarea operaţiei de I/E, canalul trimite, la momentul (6), un semnal de întrerupere, care
determină trecerea taskurilor T1 şi T2 în starea de întrerupere, controlul procesorului fiind preluat
de S.O. Acesta trece la subrutina de tratare a întreruperii generate de canal şi, după încheierea
tratării acesteia, dă controlul taskului T1 care are acum prioritate maximă. Terminarea execuţiei
taskului T1 determină reactivarea S.O. (momentul (7)), care va da controlul taskului T2, care la
terminarea execuţiei (momentul (8)) redă controlul S.O. Acesta reactivează taskul T3, iar după
terminarea acestuia (momentul (9)), controlul este preluat de S.O.
Din acest exemplu, se vede clar că în cazul programării paralele, un task este un ansamblu
indivizibil program-procesor.
În cadrul oricărui fel de execuţie paralelă există două categorii de taskuri peste un program
dat: taskuri disjuncte sau independente şi taskuri care interacţionează (sau care cooperează).
Două sau mai multe taskuri se numesc disjuncte dacă nu schimbă informaţii între ele sau
dacă nu utilizează resurse (zone de memorie, periferice etc.), în comun. În caz contrar, se spune
că ele interacţionează. Evoluţia unui program alcătuit numai din taskuri disjuncte este unică
indiferent de ordinea de execuţie a taskurilor. Dar, în cazul unei execuţii pseudo-paralele a două
sau mai multe taskuri peste un program dat, avem de-a face, în general, cu taskuri care
interacţionează.
Pentru o mai bună înţelegere a celor spuse prezentăm o serie de exemple.
Exemplul l: Fie o aplicaţie formată din trei taskuri: T1, T2, T3 având următoarea
componenţă:
Task T1 Task T2 Task T3
M1 = MAX(A, B) M2 = MAX(C, D) M = MAX(M1, M2)
Structura taskurilor este foarte simplă: T1 şi T2 calculează valoarea maximă dintre două
numere A, B, respectiv C, D, rezultatele fiind numerele M1, respectiv M2. Taskul T3 determină
maximul dintre M1 şi M2. Se observă imediat că taskurile T1 şi T2 sunt disjuncte, ordinea
execuţiei lor nealterând evoluţia în ansamblu a programului. Taskul T3, în schimb, cooperează cu
taskurile T1 şi T2 (preia valorile M1 şi M2 de la acestea) şi, ca atare, el trebuie să intre în
execuţie numai după terminarea execuţiei acestor două taskuri.

4-8
Ca urmare, ordinea de execuţie a taskurilor pentru o evoluţie corectă a programului dat va
fi: T1, T2, T3 sau T2, T1, T3, oricare altă ordine de execuţie având ca rezultat scăparea de sub
control a evoluţiei programului.
Exemplul 2: Fie o aplicaţie formată din două taskuri T1 şi T2.
Taskul T1 observă şi contorizează o serie de evenimente incrementând o variabilă
CONTOR. Taskul T2 tipăreşte ocazional numărul evenimentelor contorizate de taskul T1 şi după
fiecare tipărire anulează variabila CONTOR:
Task T1 Task T2
Observă evenimentul Tipareşte CONTOR
CONTOR = CONTOR + 1 CONTOR = 0
Se observă că cele 2 taskuri interacţionează între ele utilizând în comun variabila CONTOR
care se modifică în timp.
Dacă nu se iau măsuri speciale de programare, poate apare următoarea situaţie eronată:
presupunem că T1 a incrementat variabila CONTOR la 20, iar taskul T2 a tipărit aceaste cifre. Se
poate întâmpla însă ca înainte ca T2 să anuleze variabila CONTOR, taskul T1 să sesizeze un nou
eveniment şi să incrementeze variabila CONTOR de la 20 la 21. Rezultă deci că acest eveniment
se va pierde, el rămânând neraportat.
O altă situaţie, mai puţin evidentă, dar care conduce la rezultate eronate este următoarea:
Implementrea operaţiei CONTOR = CONTOR + 1 presupune existenţa mai multor
instrucţiuni în cod maşină:
- încarcă CONTOR în acumulator;
- incrementează acumulatorul;
- memorează conţinutul acumulatorului în CONTOR.
În timp ce taskul T1 execută această secvenţă, el poate fi întrerupt de T2 şi să se ajungă la
următoarea situaţie:
Presupunem că variabila CONTOR = 15 şi această valoare este încărcată în acumulator.
Considerăm că T2 tipăreşte valoarea 15 şi face CONTOR = 0. În continuare, taskul T1 adună 1 la
conţinutul acumulatorului şi memorează rezultatul 16 în CONTOR. Rezultă deci că au fost
raportate 15 evenimente, iar variabila CONTOR = 16 şi nu 0 cum ar fi trebuit să fie în mod
normal.
Exemplul 3: Se consideră 2 taskuri T1 şi T2 care scriu fiecare câte un mesaj pe consola
operatorului (display), folosind poziţionarea directă a cursorului în câte o poziţie (linie, coloană)
a consolei.
Task T1 Task T2
Poziţionează cursor în (L1,C1) Poziţionează cursor în (L2,C2)
Scrie MESAJ 1 Scrie MESAJ 2
MESAJ 1 şi MESAJ 2 sunt de fapt şiruri de caractere, iar (L1, C1) şi (L2, C2) numere de
linie şi coloană pe display (uzual, un display alfanumeric are 24 de linii şi 80 de coloane).
Dacă nu se iau măsuri speciale de protecţie, se poate ajunge la următoarea situaţie eronată:
taskul T1 preia controlul, poziţionează cursorul în linia şi coloana (L1, C1) şi începe să tipărească
MESAJ 1; dacă T1 este întrerupt înainte ca să fie terminată tipărirea lui MESAJ 1 şi controlul
este preluat de T2, acesta va poziţiona cursorul pe display în linia/coloana (L2, C2), va scrie
MESAJ 2, după care controlul revine lui T1, care continuă din punctul în care a fost întrerupt,
deci continuă tipărirea lui MESAJ 1; cursorul a rămas însă în poziţia lăsată de acţiunea taskului
T2 şi tipărirea lui MESAJ 1 este astfel compromisă.
Din aceste exemple rezultă clar că dacă nu se iau măsuri speciale de programare, în cazul
taskurilor care interacţionează, rezultatul nu poate fi prevăzut, aceasta datorită imposibilităţii
aprecierii momentului când se face transferul controlului.

4-9
Evoluţia unui program compus din astfel de taskuri nu este unică, ea depinzând de modul
de planificare al taskurilor spre execuţie, precum şi de timpul de execuţie al acestora. Pentru
obţinerea unei evoluţii dorite a programului, este necesară o programare foarte atentă care să
permită realizarea interacţiunii corecte între taskurile componente.

4.6. Gestiunea memoriei


Alături de procesor, memoria constituie o resursă fizică fundamentală a oricărui calculator
numeric.
Distingem: memoria principală sau operativă - MO reprezentând memoria internă a
sistemumlui de calcul şi memoria secundară sau externă. Se ştie că nici un program nu poate fi
executat dacă el nu se află depus în memoria operativă. Ţinând cont de lungimea, în general,
mare a programelor de aplicaţie în timp real, de obicei, acestea nu sunt integral rezidente în
memoria internă. Din această cauză, se impune ca, parţial sau total, programul să fie înmagazinat
pe un suport extern de memorie, de regulă, disc magnetic. După cum s-a arătat, fiecare program
de aplicaţie poate fi privit ca o reuniune de taskuri care interacţionează între ele.
Pentru a putea fi executat, la un moment dat, un task trebuie să fie complet încărcat în
memoria internă. Taskul trebuie să aibă alocată suficientă memorie, atât pentru el, cât şi pentru
datele pe care le vehiculează.
Rezultă că sistemul de operare trebuie să dispună de un mecanism special care să aloce
memorie internă diferitelor taskuri care sunt activate la un moment dat. Deoarece mai multe
taskuri pot îndeplini condiţiile de activare, la un moment dat, acestea cer să li se aloce spaţiu în
memoria internă. Având în vedere că memoria are o capacitate limitată, gestiunea memoriei
presupune introducerea unor tehnici de plasare şi înlocuire în memoria operativă a programelor şi
datelor aflate pe suporturi de memorie secundară. Alocatorul de memorie trebuie să rezolve
problema schimbului de informaţie între memoria operativă şi memoria secundară în mod
automat, printr-o tehnică de dute-vino (swapping) şi să determine în orice moment cum trebuie
distribuită informaţia în memorie, în scopul optimizării utilizării ei. Componentele sistemului de
operare prevăzute pentru gestiunea memoriei fac parte din suportul de execuţie a programelor şi
sunt situate deasupra suportului de gestiune a unităţii centrale.
Prin spaţiu de adresare se înţelege totalitatea numerelor de adresă referite într-un program.
În timpul execuţiei programului, fiecărei variabile din program îi va fi asociată o anumită adresă
din memoria operativă.
Gestiunea memoriei include două operaţii esenţiale:
- adresarea memoriei;
- protecţia memoriei.
Adresarea memoriei constă din procedee prin care se realizează asocierea între un element
al spaţiului de memorie şi o adresă efectivă din memoria operativă (un element al spaţiului de
adresare).
Protecţia memoriei constă din acele procedee care garantează utilizarea corectă a memoriei
operative de către toate taskurile aflate în execuţie la un moment dat.

Gestiunea memoriei în sistemele cu monoprogramare


În astfel de sisteme, la un moment dat, în memoria internă este încărcat şi se execută un
singur task, celelalte taskuri aflându-se pe suportul de memorie externă (disc magnetic). În
principiu, memoria operativă este împărţită în trei zone distincte, Fig. 4.3.

4 - 10
Fig. 4.3.
În zona rezervată sistemului de operare (SO) sunt plasate modulele rezidente ale SO sau
anumite module folosite temporar. Restul memoriei operative este disponibilă programelor
utilizatorului.
Suportul software pentru gestiunea memoriei în aceste sisteme este foarte redus. De regulă
se verifică dacă programele utilizator planificate pentru execuţie nu depăşesc capacitatea
memoriei operative disponibile în sistem (capacitatea MO - capacitatea zonei destinate SO). Dacă
se constată depăşirea capacităţii disponibile, se va emite un semnal de eroare, iar lucrarea
respectivă se va abandona. Mecanismele de protecţie a memoriei constau din procedee relativ
simple prin care se permite citirea informaţiei din zona aferentă SO şi interzicerea operaţiei de a
înscrie informaţii în această zonă. Sistemele de operare de acest tip se numesc monitor sau
supervizor . Funcţiile unui asemenea SO sunt:
1. Asigurarea continuităţii încărcării sistemumui. Aceasta înseamnă că în momentul în care
se termină execuţia unui task, controlul este preluat de supervizor, care iniţiază execuţia taskului
celui mai prioritar în acel moment, care preia şi controlul. Dacă taskul aflat în execuţie este
întrerupt (de un task mai prioritar), SO va suspenda execuţia taskului curent şi acesta, împreună
cu informaţia aferentă contextului când a fost întrerupt, va fi imediat transferat pe un suport de
memorie externă, în memoria operativă încărcându-se noul task ce urmează a fi executat.
Reluarea execuţiei taskului întrerupt se va face, după reîncărcarea acestuia în memorie, din
punctul în care a fost întrerupt.
2. Iniţierea şi achitarea operaţiilor de intrare-ieşire solicitate de programele utilizator.
3. Punera la dispoziţie, pentru programele utilizator, a unor rutine standard frecvent
utilizate.
Singura cale de a obţine accesul în zona aferentă SO de către programele utilizator constă în
apelul unor rutine ale SO.
Pprincipalul avantaj al acestei metode constă în simplitatea SO şi a spaţiului de memorie
mic ocupat de acesta, precum şi în faptul că se dispune pentru execuţia taskului curent de întregul
spaţiu al memoriei disponibile.
Dezavantajul metodei îl constituie timpul de răspuns mare datorat comutărilor frecvente
între taskuri sau de la un program la altul, deoarece transferul între memoria internă şi memoria
externă cere mult timp.
O metodă de a elimina acest dezavantaj constă în desemnarea unor taskuri critice pentru
care se impune un timp de răspuns minim, care rămân permanent într-o zonă protejată a memoriei
interne. De asemenea, utilizatorul are la dispoziţie un mecanism prin care va putea executa
programe, uneori cu mult mai mari decât spaţiul de adrese fizice disponibile. Acest mecanism se
numeşte metoda înlănţuirii şi suprapunerii (overlay) şi constă în suprapunerea unor module de
program. În acest caz, un program aplicativ sau un task aflat în execuţie controlează el însuşi
încărcarea de pe suportul extern a unor module de program sau taskuri. Încărcarea se face la
momente de timp bine definite impuse de evenimente externe sau interne, noile taskuri aducându-
se în memoria internă în zona proprie a programului apelant, putând să-l acopere parţial sau total.
Rezultă că programul de aplicaţie preia atât funcţia de planificare a execuţiei taskurilor, cât
şi de gestiune a memoriei interne, substituindu-se SO. Deşi această metodă presupune o
complicare a programului de aplicaţie, totuşi este foarte utilă pentru aplicaţii de complexitate

4 - 11
mică şi medie şi la care timpii de răspuns au valori foarte critice, precum şi în cazul sistemelor cu
divizarea timpului.
Dezavantajul esenţial al monoprogramării este acela că existând la un moment dat un singur
program în memorie, nu poate fi utilizat paralelismul între efectuarea operaţiilor de intrare-ieşire
şi operaţiile de prelucrare propriu-zise, ceea ce conduce la un timp de lucru global mult mai mare
şi un factor redus de utilizare a resurselor.
Cu toate acestea, această tehnică este foarte utilizată, mai ales, în cazul unor calculatoare de
putere mică şi medie destinate prelucrării unor lucrări cu caracter tehnico-ştiinţific. Astfel de
lucrări ocupă un timp îndelungat procesorul cu efectuarea unor operaţii aritmetice şi logice
complexe ceea ce face să se resimtă mai puţin influenţa timpului necesar schimbului informaţiei
între MO şi memoria externă.

Gestiunea memoriei în sistemele cu multiprogramare


Multiprogramarea a fost introdusă pentru creşterea gradului de utilizare a procesorului prin
exploatarea paralelismumui între activitatea procesorului şi activitatea dispozitivelor de intrare-
ieşire.
Multiprogramarea presupune existenţa simultană în memoria internă a mai multor taskuri şi
execuţia lor paralelă prin mecanismul multitasking. Comutarea între taskuri se realizează sub
controlul SO în funcţie de priorităţile taskurilor şi de evenimentele ce au loc în proces. Existenţa
mai multor programe în memoria operativă presupune împărţirea acesteia în zone distincte
numite partiţii sau regiuni. Situaţia alocării memoriei la un moment dat, într-un sistem cu
multiprogramare, se poate reprezenta ca în Fig. 4.4.

Fig. 4.4.
Se observă că, şi în acest caz, o anumită zonă de memorie va fi alocată necesităţilor SO.
Fiecare partiţie va fi formată dintr-o zonă utilă în care se încarcă programele şi datele aferente
unui task şi o zonă neutilizată. În ceea ce priveşte protecţia memoriei, apar două aspecte:
1. Ca şi în cazul monoprogramării este necesar ca programele utilizator să nu afecteze în
nici un fel informaţiile din zona SO.
2. Se impune ca execuţia unui program (task) să nu afecteze în nici un fel celelalte
programe (taskuri) cu care coexistă în memorie.
Un mecanism uşor de implementat care să răspundă cerinţelor de mai sus îl reprezintă
mecanismul cheie de protecţie - cheie de acces. Conform acestui mecanism, fiecărei partiţii i se
asociază, utilizând mijloace hardware, o cheie de protecţie. Când procesorul este alocat unui
program (task), câmpul din tabela de stare a taskului ce conţine cheia de acces la memorie va fi
actualizat corespunzător partiţiei programului curent aflat în execuţie. În timpul execuţiei, la

4 - 12
fiecare acces la memorie se verifică egalitatea cheii de acces cu cea a cheii de protecţie, accesul
fiind permis numai în partiţiile unde se înregistrează egalitatea.
Mecanismul cheie de protecţie - cheie de acces poate fi extins uşor şi la canalele de intrare-
ieşire.
Dacă memoria operativă este divizată în partiţii înainte de execuţia oricărei lucrări, se spune
ca lucrăm cu partiţii statice (fixe). În acest caz dimensiunea partiţiei este fixată încă din etapa de
generare a SO.
Într-o asemenea organizare, un program (task) dintr-o partiţie este executat până în
momentul în care va iniţia o operaţie de intrare-ieşire. Evident că cel care iniţiază propriu-zis
operaţia de intrare-ieşire este SO.
După iniţierea operaţiei de intrare-ieşire, SO va trece controlul unui alt task rezident în altă
partiţie a memoriei şi care dispune de toate resursele necesare cu excepţia procesorului. La fel se
petrec lucrurile şi în cazul în care un task este întrerupt de un task mai prioritar sau ca urmare a
apariţiei unui eveniment în proces: SO va da controlul taskului mai prioritar sau se trece la rutina
de tratare a întreruperii solicitate. Dacă într-o fază a lucrării cantitatea de memorie solicitată
depăşeste cantitatea de memorie ce poate fi pusă la dispoziţie într-o partiţie, întreaga lucrare se
abandonează.
Modul de alocare a memoriei cu partiţii fixe este indicat în situaţia în care se cunosc
dimensiunile programelor (taskurilor) şi zonele de memorie ocupate de datele pe care acestea le
vehiculează. În acest caz partajarea memoriei se va face în funcţie de necesităţi, obţinând deci o
bună utilizare a memoriei.
Dacă partiţiile sunt create nu la generarea sistemului, ci chiar în timpul execuţiei lucrării,
înaintea începutului fiecărei faze a lucrării, se spune că sistemul de calcul lucrează cu partiţii
dinamice. În această situaţie SO poate ajusta dimensiunea partiţiilor în funcţie de necesităţile
curente. Uneori aceste modificări se realizează chiar în timpul execuţiei unor programe prin
extensia sau reducerea memoriei alocate acestor programe. SO poate modifica şi numărul
partiţiilor existente la un moment dat în memorie. Aceste apecte impun ca SO să deţină informaţii
detaliate despre organizarea memoriei sub forma a două tabele: una, pentru partiţiile alocate şi
alta, pentru partiţiile libere. Informaţiile ce se păstrează în aceaste tabele se referă la dimensiunile
partiţiilor, adresa primei locaţii a partiţiei, rectricţiile de acces la fiecare partiţie.
Cele mai cunoscute procedee de alocare dinamică a memoriei sunt: procedeul FIRST FIT
(procedeul primei partiţii) - eficient în cazul programelor de dimensiuni mari şi procedeul BEST
FIT (procedeul celei mai bune partiţii) - specific în cazul unor programe mici şi cu o mare
diversitate. Alte algoritme de alocare dinamică a memoriei sunt: algoritmul înjumătăţirii
(BUDDY SYSTEM), care impune ca fiecare partiţie liberă să aibe o dimensiune egală cu o putere
a lui 2, algoritmul numerelor lui Fibonacci, care presupune o divizare a memoriei proporţională
cu numerele din şirul lui Fibonacci etc.
Deoarece alocarea dinamică a memoriei duce la apariţia unor fragmente de memorie
neutilizate, în general de dimensiuni mici, ceea ce duce la amânarea introducerii în execuţie a
unor lucrări noi până la terminarea unei lucrări în curs de execuţie ce eliberează o partiţie
suficientă de memorie, este necesar ca, periodic, aceste regiuni libere să fie combinate într-o
regiune mai mare, operaţie numită compactare sau recompactare a memoriei. Operaţia este foarte
costisitoare deoarece presupune deplasarea programelor în memorie, cu modificarea tuturor
adreselor (mai puţin adresele porturilor dispozitivelor de intrare-ieşire) şi se realizează printr-un
mecanism comun software-hardware.
Principalul avantaj al alocării dinamice, în special în cazul folosirii programelor relocabile
(adică programe ce conţin adrese relative după faza de editare a legăturilor) îl constituie
eliminarea fragmentării memoriei, cea ce duce la o utilizare mult mai eficientă a MO şi la un grad
superior de multiprogramare.

4 - 13
Dezavantajul constă în folosirea unor componente hardware suplimentare, reducerea vitezei
de lucru datorită timpului necesar pentru calculul adreselor efective şi creşterea timpului efectiv
de lucru datorită timpului mare necesar compactării memoriei, în special dacă această operaţie se
realizează frecvent.
Menţionăm că metoda este mai puţin utilizată în cazul SO cu divizarea timpului.

Gestiune memoriei operative prin paginare


Dacă se renunţă la cerinţa ca o partiţie să fie contiguă şi se prevăd dispozitive hardware
necesare, se obţine o soluţie la fragmentarea memoriei şi anume gestiunea memoriei prin
paginare.
Conform acestei metode, spaţiul de adresare al fiecărui program se consideră divizat în
părţi egale numite pagini; de asemenea, MO se consideră divizată în zone de aceeaşi dimensiune
numite blocuri de memorie sau cadre-pagină. Fiecărui program (task) i se alocă un număr întreg
de astfel de blocuri.
Alegerea dimensiunii blocului este o problemă de optimizare. Dacă blocurile sunt prea
lungi, se simplifică activitatea de gestiune, dar poate apare fenomenul de utilizare neraţională a
memoriei. Dacă blocurile sunt prea mici, eventualul câştig de memorie este plătit prin
complexitatea tabelelor de pagină şi a programelor de gestiune a memoriei.

4.7. Gestiunea proceselor (taskurilor) şi a procesorului


Se ştie că procesorul sau, mai general, unitatea centrală reprezintă principala resursă a
oricărui calculator. Orice program (task) destinat prelucrării datelor apelează la serviciile
procesorului.
Analizăm cazul unui sistem de calcul monoprocesor. În această situaţie, în cazul
multiprogramării, la un moment dat, mai multe taskuri din componenţa unui program pot solicita
resursele unităţii centrale. Apar, deci, conflicte pentru utilizarea procesorului.
Din punct de vedere al organizării funcţionale interne a unui calculator numeric, unui task îi
corespunde un proces.
Fiecare proces are asociate o serie de resurse care îi condiţionează desfăşurarea şi este
reprezentat în sistemul de operare printr-o structură de date numită bloc de comandă a procesului
(taskului).
Un bloc de comandă a procesului (taskului) va reflecta starea procesului (taskului) şi va
conţine toate informaţiile necesare pentru a relua procesul (taskul) din punctul în care a fost
întrerupt. Cu mici diferenţe de la un sistem de operare la altul, un bloc de comandă a procesului
(taskului) va conţine:
- identificatorul procesului (taskului);
- starea procesului (taskului);
- copia registrelor generale la suspendarea procesului;
- informaţii despre resursele alocate procesului.
Observaţie: Modul în care este creat un proces (task) este specific fiecărui sistem de
operare.
Taskurile care compun o aplicaţie se pot afla în una din următoarele trei stări:
NEINSTALAT, INACTIV sau ACTIV, Fig. 4.5.

4 - 14
Fig. 4.5.
Un task ACTIV poate fi, la rîndul lui, în una din următoarele substări: BLOCAT
(BLOCKED), GATA DE EXECUŢIE (READY) sau ÎN EXECUŢIE (RUN).
Un task neinstalat este un task creat rezident pe un suport extern sau în memoria internă a
calculatorului, dar care nu a fost încă adus la cunoştinta sistemului de operare
(EXECUTIVULUI). Un task creat este făcut cunoscut sistemului de operare prin operaţia de
instalare, în urma căreia el este trecut automat în starea INACTIV.
Un task se află în starea INACTIV dacă este instalat, dar nu este planificat pentru execuţie.
Prin instalare se creează şi i se alocă taskului un vector de stare sau un bloc de control al
taskului care reprezintă materializarea taskului în sistem şi care conţine informaţiile specificate
mai sus.
Vectorii de stare ai taskurilor sunt grupaţi într-o tabelă a taskurilor care este folosită de
sistemul de operare cu ocazia instalării şi distrugerii (ştergerii) taskurilor, precum şi pentru
efectuarea schimbărilor survenite în starea taskurilor pe parcursul duratei lor de existenţă.
Taskului i se atribuie un nume sau un număr care permite sistemului de operare şi altor
taskuri să-l desemneze fără ambiguitate pe toată durata lui de existenţă.
Un task poate reveni în starea NEINSTALAT numai din starea INACTIV prin operaţia de
ştergere (sau distrugere) a lui, dezafectîndu-i-se vectorul de stare.
Un task pentru care se face o cerere de intrare în execuţie trece din starea INACTIV în
starea ACTIV şi anume în substarea READY, tranziţia 1, adică are îndeplinite toate condiţiile şi
poate astfel concura la ocuparea procesorului. Momentul trecerii unui task în substarea GATA
DE EXECUŢIE nu poate fi prevăzut cu exactitate de către programator, acest moment fiind
funcţie de complexitatea aplicaţiei şi de modul în care se face planificarea taskurilor pentru
intrarea lor în execuţie. Precizăm că planificarea taskurilor pentru execuţie este realizată de un
modul al sistemului de operare numit planificator (SCHEDULER).
Trecerea unui task în substarea ÎN EXECUŢIE (RUN) se face numai din substarea
READY, tranziţia 2. Există două tehnici de bază pentru realizarea planificării taskurilor spre
execuţie:
10. Procedeul round-robin, prin care taskurile aşezate într-o coadă de aşteptare sunt
executate succesiv, fie până la terminarea lor normală, fie un interval (cuantă) de timp Δt bine

4 - 15
determinat. Strategia de administrare a cozii este de tip FIFO (First In - First Out : Primul venit -
Primul ieşit). După ce un task a fost executat, acesta este trecut în coada de aşteptare şi este lansat
în execuţie taskul următor. Dacă taskul nu se termină în timpul alocării curente, el este trecut prin
coada de aşteptare de n ori, unde n este cel mai mic întreg care satisface relaţia t ≤ n × Δt unde Δt
este cuanta de timp alocată rulării curente a unui task, iar t este timpul de execuţie al taskului. De
obicei, parametrul Δt se alege astfel încât majoritatea interacţiunilor utilizator-sistem să se
termine într-o singură cuantă (de regulă de ordinul milisecundelor). Se observă că, acest algoritm
întrerupe un task în curs de execuţie indiferent dacă la epuizarea cuantei de timp acordate taskul
respectiv s-a terminat sau nu.
20. Procedeul după priorităţi, prin intermediul căruia fiecărui task îi este atribuit un
indicator de importanţă materalizat printr-un număr numit prioritate, iar dintre taskurile gata de
execuţie, la un moment dat, care concură la ocuparea procesorului, sistemul de operare va aduce
ÎN EXECUŢIE taskul cu prioritatea cea mai mare la acel moment.
Observaţii:
1. În cazul EXECUTIVELOR care permit ambele moduri de planificare a taskurilor pentru
execuţie, procedeul round-robin se aplică taskurilor de aceeaşi prioritate.
2. Există sisteme de operare evoluate care oferă posibilitatea de activare a taskurilor în
condiţii de criză de timp şi care dispun de proprietatea remarcabilă de creştere automată a
priorităţii unui task dacă acesta nu a fost executat într-un anumit interval de timp.
3. Este evident că pe un sistem de calcul monoprocesor, la un moment dat, un singur task se
află ÎN EXECUŢIE.
Trecerea unui task dintr-o stare în alta se poate realiza, de asemenea, în două moduri:
10. Prin intermediul întreruperilor determinate de evenimentele interne sau externe generate
prin intermediul sistemului de întreruperi, contextul comutării fiind determinat de nivelul
întreruperii şi de subrutina de tratare a acesteia. Evenimentele ce sunt luate în considerare de
sistem sunt:
- întreruperi de la procesul condus;
- întreruperi de la ceasul de timp real;
- întreruperi generate de dispozitivele de intrare-ieşire;
- întreruperi iniţiate de operator de la COP;
- terminarea sau suspendarea executării unui task activ.
20. Prin directive (cereri de servicii) către sistemul de operare (EXECUTIV) din taskul care
se află în execuţie, contextul comutării fiind determinat de tipul directivei şi de parametrii
acesteia.
Un sistem de operare în timp real trebuie să permită ambele procedee de comutare a
taskurilor, aceasta şi datorită faptului că directivele folosesc implicit sistemul de întreruperi al
microprocesorului.
Mai mult, un EXECUTIV de timp real este necesar să fie însoţit de un MONITOR care să
constituie interfaţa între operator şi programul ce reprezintă aplicaţia de conducere şi care să
conţină comenzi având acelaşi efect asupra taskurilor ca şi directivele. Astfel, prin intermediul
MONITORULUI, operatorul se poate informa asupra stării taskurilor, poate realiza, dacă este
necesar, modificarea stării acestora, acţiuni necesare, mai ales, în faza de dezvoltare şi depanare a
programului.
Celelalte tranziţii ale unui task dintr-o stare în alta au loc în următoarele condiţii:
- Tranziţia 3 din substarea RUN în starea INACTIV apare în mod logic (sau normal) la
terminarea taskului.
- Tranziţia 4 din substarea RUN în substarea READY se realizează în două situaţii:

4 - 16
a) taskul curent este întrerupt de un alt task, de un task critic, mai prioritar, apărut în
condiţii de context extern sau intern;
b) în cazul modului de prelucrare a taskurilor în regim de time sharing (cu divizarea
timpului), când cuanta de timp alocată execuţiei taskului curent s-a epuizat, deşi el dispune în
continuare de toate resursele necesare execuţiei sale.
- Trecerea din substarea RUN în substarea BLOCKED, tranziţia 5, se realizează în situaţia
în care taskul aflat în execuţie este întrerupt pentru îndeplinirea uneia dintre următoarele condiţii:
a) terminarea unei operaţii de intrare-ieşire solicitată de task;
b) apariţia unui eveniment extern;
c) trecerea unui anumit interval de timp.
- Un task trece din substarea BLOCKED în substarea READY, tranziţia 6, când cauzele
care au produs blocarea execuţiei taskului au fost înlăturate, adică sunt îndeplinite condiţiile:
a) s-a încheiat operaţia de intrare-ieşire iniţiată de task;
b) s-a eliberat o zonă de memorie internă suficientă pentru a permite execuţia taskului;
c) a avut loc evenimentul extern aşteptat;
d) a expirat intervalul de timp de aşteptare.
- Tranziţia 7 din substarea READY în substarea BLOCKED apare în situaţia când un task
ce era gata de execuţie este trecut în substarea BLOCAT de un task aflat în execuţie, sau nu mai
poate fi executat din considerente că nu mai dispune de suficientă memorie internă.
- De asemenea, un task în execuţie poate trece, prin terminare forţată, în starea INACTIV
atât taskuri aflate în substarea READY, tranziţia 8, cât şi taskuri aflate în substarea BLOCKED,
tranziţia 9.
Observaţie: Prin terminare forţată, unui task activ i se suspendă toate condiţiile de
aşteptare şi i se retrage orice posibilitate de alocare a unei resurse.
Trebuie făcută menţiunea că dacă un task pierde controlul procesorului rămânând în starea
ACTIV, reluarea execuţiei lui se va face din punctul în care a fost întrerupt. Pentru ca reluarea
execuţiei să se facă în contextul întreruperii taskului este necesar ca, în momentul întreruperii
unui task, sistemul de operare să asigure salvarea întregului context aferent taskului, adică
conţinutul registrelor generale ale unităţii centrale, conţinutul registrului indicatorilor de stare etc.
Dacă comutarea stării taskurilor se face sub controlul unui EXECUTIV de timp real prin
intermediul directivelor, în urma lansării unei directive, controlul procesorului este transferat de
la taskul aflat în execuţie (taskul care a lansat directiva) către EXECUTIV pentru ca acesta să
satisfacă imediat cererea conţinută în directivă. Din punct de vedere al returnării controlului de
către EXECUTIV către taskurile componente aplicaţiei distingem două categorii de directive:
- Directive pe care EXECUTIVUL le satisface returnând apoi controlul taskului care a dat
directiva (care a lansat cererea de servicii);
- Directive care cer o serie de servicii EXECUTIVULUI, după satisfacerea cărora acestea
nu mai returnează controlul taskurilor apelante ci, determină o nouă replanificare (rescheduling) a
taskurilor pentru execuţie. EXECUTIVUL va aduce în execuţie taskul gata de execuţie cu
prioritatea cea mai mare. În acest caz, se spune că directiva declară eveniment semnificativ .
Structura generală a unui task executat sub controlul unui EXECUTIV de timp real este
prezentată în Fig. 4.6.

4 - 17
Fig. 4.6.

4 - 18
CAP.5. INTERACŢINEA TASKURILOR CONCURENTE

5.1. Consideraţii generale


Exploatarea avantajelor aduse de considerarea unei aplicaţii ca fiind compusă din mai multe
taskuri ce se execută în paralel sau concurent impune, aşa cum a rezultat şi din exemplele
prezentate în capitolul anterior, folosirea unor mecanisme care să asigure interacţiunea corectă a
taskurilor pentru ca programul în ansamblu să aibă evoluţia dorită. Dening P. (în Operating
Systems Theory) a arătat că interacţiunea taskurilor poate fi redusă la trei tipuri de operaţii
multitasking: comunicarea între taskuri, sincronizarea taskurilor şi excluderea mutuală a
taskurilor.
Comunicarea între taskuri este operaţia multitasking prin care se permite taskurilor să
schimbe date între ele. Datele comune (utilizate de mai multe taskuri) sunt memorate în memoria
internă a calculatorului în anumite zone declarate ca zone comune (pentru datele comune) şi la
care vor avea acces toate taskurile. Deoarece zonele de date comune organizate în memoria
internă au o capacitate mică şi limitează la un volum mic datele comune, în cazul unui volum
mare de date, acestea se organizează în fişiere plasate pe un suport de memorie externă (de obicei
disc magnetic).
Majoritatea sistemelor de operare actuale oferă un sistem de lucru cu fişierele prin
intermediul unui SGF (sistem de gestiune a fişierelor). Dezavantajul acestei metode este legat de
timpii relativ mari pentru accesarea datelor din fişiere, dar metoda este utilizată datorită
capacităţii mari de memorare a acestor sisteme.
Sincronizarea este operaţia multitasking care asigură eşalonarea corectă a execuţiei
taskurilor în timp sau, altfel spus, care stabileşte o relaţie de ordine între instrucţiunile executate
de acestea, independent de vitezele relative ale lor.
Scopul unei metode de sincronizare este de a oferi unui task Ti aflat în execuţie mijloacele
care să-i permită, în primul rând, să blocheze un alt task activ Tj sau să se blocheze el însuşi în
aşteptarea producerii unui eveniment extern sau expirării unui interval de timp şi, în al doilea
rând, să deblocheze un task Tk căruia să-i transmită eventual şi unele informaţii.
În evoluţia lor două sau mai multe taskuri se pot sincroniza fie în funcţie de o condiţie de
timp, fie în funcţie de un eveniment exterior. Mai exact, în cadrul unei aplicaţii, se poate întâlni
situaţia ca un task Tk pentru a-şi putea continua execuţia să fie nevoit să aştepte trecerea unui
anumit interval de timp sau realizarea unui eveniment din proces, eveniment controlat de regulă
de un alt task Ti.
În cazul sincronizării pe o condiţie de timp, taskul Tk se va bloca până la expirarea
intervalului de timp menţionat după care va trece în starea READY şi îşi va putea continua
execuţia. În cazul sincronizării pe un eveniment exterior, taskul Tk se va bloca dacă evenimentul
nu a avut loc. De regulă, acest eveniment este supravegheat de un alt task Ti care va debloca
taskul Tk în momentul în care evenimentul s-a îndeplinit.
Operaţiile de sincronizare pot fi:
- explicite (directe), caz în care un task acţionează direct asupra altui task, primitivele de
blocare şi deblocare trebuind să fie astfel concepute încât să accepte ca parametru numele
taskului asupra căruia se acţionează;
- implicite (indirecte), caz în care un task acţionează asupra altui task prin declanşarea unor
mecanisme intermediare; primitivele de blocare şi deblocare nu mai folosesc explicit numele
taskului asupra căruia se acţionează, ci folosesc o serie de variabile special-create în acest scop
(semafoare, variabile eveniment etc.).

5-1
Restricţiile care determină sincronizarea taskurilor pot fi concentrate sub forma:
- operaţia A nu se poate executa înaintea trecerii intervalului de timp ΔT;
- operaţia A nu se poate executa înaintea operaţiei B.
Excluderea mutuală este operaţia multitasking prin care se exclude accesul simultan al
mai multor taskuri la una şi aceeaşi resursă (zona de date din memorie, fişier, periferic etc.).
Restricţiile, în acest caz, sunt de tipul: operaţiile A, B, C, ..., X nu pot avea loc simultan.
Definiţie: Secvenţa de program a fiecărui task în care se apelează o resursă comună
partajată se numeşte secţiune critică a taskului. (Din această cauză, de multe ori, excluderea
mutuală a taskurilor se mai întâlneşte şi sub denumirea de problema secţiunii critice).
Plecând de la ipoteza că intervalele de timp de execuţie ale taskurilor sunt diferite şi
necunoscute şi că orice task iese din secţiunea sa critică după un interval finit de timp, soluţia
unei probleme de acest tip trebuie să satisfacă următoarele condiţii:
a) - utilizarea exclusivă: la un moment dat un singur task şi numai unul se poate afla în
secţiunea sa critică corespunzătoare unei resurse;
b) - evitarea blocajului reciproc: dacă mai multe taskuri sunt blocate în aşteptarea aceleiaşi
resurse critice şi aceasta nu este ocupată, atunci unul dintre aceste taskuri (de regulă cel mai
prioritar), trebuie să poată să intre în secţiunea sa critică la capătul unui interval finit de timp;
c) - evitarea dependenţelor inutile: dacă un task este blocat în afara secţiunii sale critice,
acest blocaj nu trebuie să împiedice intrarea unui alt task în secţiunea sa critică.
Datorită condiţiilor restrictive similare, problemele sincronizării şi excluderii mutuale pot fi
tratate cu procedee comune. În prezent există o mare varietate de procedee puse la dispoziţia
utilizatorului pentru rezolvarea acestor operaţii multitasking şi anume:
- folosirea unor variabile de tip întreg numite semafoare (Dijkstra - 1965);
- folosirea unor variabile logice numite variabile eveniment (Dijkstra - 1965, Latteux -
1980);
- cu ajutorul unor structuri de date numite mesaje şi a unor zone de memorie unde se depun
aceste mesaje numite celule mesaj sau cutii poştale (Hoare - 1971);
- cu ajutorul conceptului de monitor (Brinch Hansen - 1972);
- cu ajutorul conceptului de rendezvous (Ichbiach - 1979).
Observaţie: Ultimele trei procedee au avantajul de a rezolva în mod unitar şi problema
comunicării între taskuri.

5.2. Utilizarea semafoarelor pentru excluderea mutuală a taskurilor şi pentru


sincronizarea lor indirectă
Un semafor SEM este definit de perechea [v(SEM), q(SEM)], unde:
- v(SEM) = valoarea semaforului;
- q(SEM) = o coadă de aşteptare destinată să primească taskurile care eşuează în încercarea lor
de a trece de acest semafor.
Variabila v(SEM) este de tip întreg, iar valoarea sa iniţială v0(SEM) este fixată în momentul
creării semaforului.
Administrarea cozii q(SEM) este la latitudinea sistemului de operare, iar conţinutul său
înaintea primei utilizări a semaforului este vid.
Semafoarele pot fi împărţite în două categorii:
- semafoare care pot lua numai două valori, de obicei 0 şi 1, numite, din acest motiv,
semafoare binare;
- semafoare care pot lua orice valoare întreagă, numite semafoare generale sau contorizate.

5-2
Pentru manipularea semafoarelor s-au creat două primitive speciale, neîntreruptibile, notate
cu P şi V (notaţii introduse de Dijkstra) implementate în software-ul EXECUTIVULUI. Primitiva
P apare ca o cerere de depăşire a semaforului, iar primitiva V are semnificaţia eliberării, în
anumite condiţii, a unei autorizaţii de trecere.
Observaţie: Menţionăm că, semafoarele binare sunt suficiente pentru rezolvarea operaţiilor
multitasking menţionate, astfel încât în continuare se vor face referiri numai la acestea.
Pentru semafoarele binare, primitivele P şi V au următoarea structură:
Primitiva P(SEM):
dacă v(SEM) = 0 atunci
q(SEM) ← Ti // Blochează taskul Ti, adică taskul care
// a lansat primitiva, introducându-l în coada
// de aşteptare a semaforului q(SEM)
altfel
v(SEM) = v(SEM) - 1
Primitiva V(SEM):
dacă v(SEM) ≠ 0 atunci
dacă q(SEM) ≠ atunci
Tj ← q(SEM) // Deblochează taskul Tj, care poate fi
// fie primul task din coada de aşteptare
// a semaforului, fie taskul cel mai
// prioritar din aceasta
altfel
v(SEM) = v(SEM) + 1
dacă q(SEM) ≠ atunci
Tk ← q(SEM) // Deblochează toate taskurile Tk din
// coada de aşteptare q(SEM) a
// semaforului SEM
Prin utilizarea semafoarelor binare şi a primitivelor P şi V care acţionează asupra lor aşa
cum s-a arătat mai sus, se poate rezolva eficient problema excluderii mutuale a resurselor critice
partajate. Pentru aceasta, fiecărei resurse critice i se asociază câte un semafor având iniţial
valoarea 1. Pentru claritate considerăm:
Exemplul 5.1. Considerăm n taskuri
T1,T2, ..., Tn, care în execuţia lor pot apela
simultan o aceeaşi resursă. Pentru
realizarea excluderii mutuale asociem
acestei resurse critice un semafor binar
SEM având valoarea iniţială v0(SEM) = 1.
Înainte de a intra în propria secţiune
critică, fiecare task este obligat să execute
primitiva P(SEM), iar după părăsirea
secţiunii critice trebuie să execute operaţia
V(SEM). Astfel, secvenţa de program care
încadrează secţiunea critică a fiecărui task
arată ca în Figura 5.3.
Taskul Ti aflat în execuţie care
efectuează operaţia P(SEM) se blochează dacă v(SEM) = 0 şi îşi continuă execuţia dacă v(SEM)
= 1. În cazul blocării taskului Ti pe operaţia P(SEM), sistemul de operare va da controlul unui alt
task Tj din coada de aşteptare q(SEM) a semaforului, aflat în starea READY. Dacă taskul Ti intră

5-3
în propria sa secţiune critică, atunci v(SEM) = 0 şi nici o altă operaţie P(SEM) nu mai poate avea
loc, deci nici un alt task Tj, j ≠ i nu mai poate intra în secţiunea critică a programului său, până
când taskul Ti nu o părăseşte pe a lui, moment în care executând primitiva V(SEM), face v(SEM)
= 1. În acest moment are loc deblocarea taskurilor care aşteptau să intre în propria lor secţiune
critică pentru aceeaşi resursă.
Există şi situaţii nedorite şi care trebuie eliminate. De exemplu, dacă taskul aflat în execuţie
este blocat în propria sa secţiune critică, atunci, întrucât v(SEM) a rămas 0 (după execuţia
primitivei P(SEM)), se realizează blocajul infinit al tuturor celorlalte taskuri care utilizau aceeaşi
resursă. Din această cauză trebuie luate măsuri pentru eliminarea acestei situaţii, sau de eliberare
a resursei.
Pentru a-i garanta fiecărui task introducerea în secţiunea sa critică după un interval de timp
finit, trebuie acordată o atenţie deosebită administrării cozilor de aşteptare a semafoarelor. Cea
mai simplă metodă din acest punct de vedere este metoda FIFO, dar, în multe situaţii, metoda
după priorităţi (utilizată în multe EXECUTIVE de timp real) poate prezenta avantaje evidente.
Semafoarele binare împreună cu primitivele P şi V pot constitui un mijloc de soluţionare a
problemelor de sincronizare indirectă a taskurilor cu evenimente exterioare. Primitiva P
acţionează ca o operaţie de blocare a unui task, în timp ce primitiva V poate fi privită ca un
semnal de deblocare al acestuia. Valoarea semaforului v(SEM) se asociază cu starea
evenimentului exterior astfel:
v(SEM) = 0 - evenimentul nu a avut loc;
v(SEM) = 1 - evenimentul a avut loc.
În aceste condiţii, valoarea iniţială a semaforului va fi totdeauna zero (v0(SEM) = 0). În
cazul a două sau mai multe taskuri sincronizate pe un singur eveniment exterior, procedeul este
foarte eficient şi se desfăşoară ca în exemplul 5.2.
Exemplul 5.2. Considerăm 2 taskuri T1 şi T2 care trebuie sincronizate pe un eveniment
exterior, eveniment de îndeplinirea căruia este condiţionată la un moment dat execuţia taskului
T1.
Pentru aceasta procedăm astfel. Asociem acestui eveniment un semafor SEM. Valoarea
semaforului v(SEM) se asociază cu starea evenimentului exterior aşa cum s-a arătat mai sus.
Realizarea evenimentului respectiv este supravegheat de taskul T2. Atât timp cât evenimentul nu
a avut loc, semaforul SEM are valoarea v(SEM) = 0. Taskul T1 fiind în execuţie şi ajungând la
momentul critic al programului, va încerca să execute operaţia P(SEM) şi se va bloca deoarece
v(SEM) = 0.
Taskul T2 va debloca taskul T1 executând primitiva V(SEM) care va face v(SEM) = 1 când
va sesiza îndeplinirea evenimentului. Structura programelor celor două taskuri în vederea
sincronizării pe un eveniment exterior este prezentată în Figura 5.4.

Figura 5.4.

5-4
Precizăm că acest procedeu devine ineficient în cazul unor taskuri sincronizate pe mai
multe evenimente externe. De asemenea, prin intermediul acestor variabile (semafoare binare), nu
este posibilă realizarea sincronizării taskurilor pe o condiţie de timp. Semafoarele rămân însă
foarte eficiente în rezolvarea problemei secţiunii critice.

5.3. Utilizarea variabilelor eveniment pentru sincronizarea indirectă şi excluderea


mutuală a taskurilor
Variabilele tip eveniment sunt variabile logice speciale, partajate care pot fi manipulate
numai cu ajutorul unor primitive special-compuse în acest scop. Aceste variabile pot fi declarate
prin program sau pot fi parte constituentă a EXECUTIVULUI, caz în care acestea se cunosc şi
pot fi numai apelate prin program.
Operaţiile posibile asociate unei variabile eveniment sunt, de regulă, DECLANŞAEA
provocată de un task supraveghetor şi AŞTEPTAREA şi/sau CONSUMAREA (sau ambele),
executate de un task a cărei execuţie este condiţionată de realizarea respectivului eveniment.
Efectul acestor operaţii depinde de natura evenimentului. În acest sens se definesc
evenimente nememorate şi evenimente memorate.
În cazul evenimentelor nememorate, o condiţie esenţială pentru ca acestea să fie
exploatate constă în aceea ca sosirea lor să fie aşteptată. Astfel, dacă unul sau mai multe taskuri a
căror execuţie depinde de un astfel de eveniment se află, în momentul sosirii evenimentului, în
starea BLOCKED, ele vor fi trecute imediat în starea READY. Altfel, declanşarea evenimentului
rămâne fără efect şi, în plus, el este pierdut. Justificarea unui astfel de mod de tratare se explică
prin faptul că în anumite aplicaţii, anumite evenimente sunt semnificative numai în anumite
momente ale derulării procesului şi, în cosecinţă, dacă nu sunt aşteptate acestea nu mai prezintă
nici un interes.
Evenimentul memorat este obţinut prin extensia celui nememorat şi este reprezentat
printr-o variabilă logică notată "EV" care poate lua valorile FALS (asociat cu valoarea 0) sau
ADEVĂRAT (asociat cu valoarea 1), indicând cele două alternative posibile: nedeclanşarea,
respectiv declanşarea acestui eveniment.
Când un task ajunge într-un punct în care continuarea execuţiei lui este condiţionată de
sosirea unui eveniment asociat cu variabila EV, el se va bloca numai dacă evenimentul aşteptat
nu s-a produs (EV = FALS). Sosirea evenimentului (EV = ADEVĂRAT) provoacă trecerea
taskului care îl aştepta în starea READY. Acum este necesară exprimarea faptului că respectivul
eveniment a fost consumat. Consumarea sau anularea unui eveniment se face prin atribuirea
variabilei EV a valorii FALS.
De regulă, în aplicaţiile de conducere a proceselor se operează cu conceptul de eveniment
memorat, primitivele care pot acţiona asupra variabilelor eveniment asociate fiind:
AŞTEAPTĂ(expresie logică formată cu variabile eveniment): blochează taskul până când
expresia logică conţinând una sau mai multe variabile eveniment capătă valoarea ADEVĂRAT.
DECLANŞAZĂ(EV): face ca variabila eveniment EV să capete valoarea ADEVĂRAT şi
are semnificaţia că evenimentul asociat cu această variabilă logică a avut loc.
CONSUMĂ(EV): face ca variabila eveniment menţionată EV să capete valoarea FALS şi
are semnificaţia că evenimentul asociat cu această variabilă logică s-a consumat.
Valoarea iniţială a unei variabile eveniment este FALS. Variabilele eveniment sunt diferite
de semafoare şi prin aceea că primitiva AŞTEAPTĂ(⋅) nu le modifică valoarea.
Variabilele tip eveniment sunt adecvate pentru sincronizarea taskurilor în funcţie de
evenimente.

5-5
Exemplul 5.3. Structura programelor a două taskuri T1 şi T2 sincronizate pe un eveniment
exterior căruia i se asociază variabila eveniment EV este prezentată în Figura 5.5.

Figura 5.5.
Taskul T2 trebuie să conţină după directiva AŞTEAPTĂ(EV) directiva CONSUMĂ(EV)
care semnifică fapul că evenimentul a fost luat în considerare şi care va permite o nouă aşteptare
din partea taskului T2 pe acelaşi eveniment, în cazul funcţionării celor două taskuri în buclă
infinită. De asemenea, taskul T1 trebuie să aibă posibilitatea de a da controlul taskului T2 imediat
după îndeplinirea evenimentului. Aceasta se realizează fie prin introducerea după directiva
DECLANŞAZĂ(EV) a unei directive care să declare eveniment semnificativ, fie prin construirea
directivei DECLANŞAZĂ (EV) cu o opţiune de acest fel.
Exemplul 5.4. Considerăm trei taskuri T1, T2, T3, primele două urmărind îndeplinirea a
două evenimente externe, asincrone, asociate cu variabilele EV1 şi EV2, iar al treilea fiind
condiţionat în execuţia lui, la un moment dat, de îndeplinirea ambelor evenimente. Ca atare, la
momentul critic, taskul T3 va fi obligat să execute primitiva AŞTEAPTĂ(EV1 şi EV2) şi se va
bloca dacă cel puţin una dintre variabile are valoarea FALS, ceea ce semnifică faptul că cel puţin
unul dintre evenimente nu a avut loc.

5-6
Pe măsură ce evenimentele au loc, taskul T1, respectiv T2 vor executa primitivele
DECLANŞAZĂ(EV1), respectiv DECLANŞAZĂ(EV2) care vor avea ca efect deblocarea
taskului T3 şi aducerea lui în situaţia de aşi putea continua execuţia. Structura programelor celor
trei taskuri este prezentată în Figura 5.6.
Variabilele tip eveniment pot fi utilizate şi în realizarea operaţiilor multitasking de
excludere mutuală. Pentru evitarea accesului simultan a două sau mai multe taskuri la o resursă
partajată, acesteia i se asociază o variabilă eveniment EVM căreia i se atribuie iniţial valoarea
ADEVĂRAT. Directiva DECLANŞAZĂ(EVM) simulează primitiva V (de la semafoare), iar
ansamblul de directive AŞTEAPTĂ(EVM) urmată imediat de CONSUMĂ(EVM) poate simula
primitiva P, dacă secvenţa se execută neîntreruptibil, ceea ce nu este greu de realizat. Structura a
două taskuri T1 şi T2 în situaţia de excludere mutuală este prezentată în Figura 5.7.

Figura 5.7.
Primul task care intră în secţiunea critică ajunge în aceasta trecând de primitiva
AŞTEAPTĂ(EVM) - posibil, deoarece iniţial EVM = ADEVĂRAT, executând apoi primitiva
CONSUMĂ(EVM) ceea ce duce la EVM = FALS. În acest moment orice alt task care doreşte să
pătrundă în propria sa secţiune critică se va bloca pe primitiva AŞTEAPTĂ(EVM) până când
taskul iniţial abandonând resursa comună execută primitiva DECLANŞAZĂ(EVM) în urma
căreia variabila eveniment EVM capătă valoarea ADEVĂRAT.

5.4. Sincronizarea taskurilor pe o condiţie de timp. Reprogramarea execuţiei


taskurilor
Pentru realizarea sincronizării taskurilor pe o condiţie de timp se pot crea trei tipuri de
directive:
1. AŞTEAPTĂ( interval de timp Δt )
2. MARCHEAZĂ( interval de timp Δt, variabilă eveniment EV )
3. REPROGRAMEAZĂ( număr (nume) task NRTASK, interval de timp Δt )
1. Primitiva AŞTEAPTĂ(Δt) are efect numai asupra taskului care a lansat-o, presupunând
din partea EXECUTIVULUI următoarele acţiuni neîntreruptibile:
- înscriera valorii Δt într-un contor local aferent taskului;
- blocarea taskului până la expirarea intervalului de timp Δt;
- decrementarea contorului cu o cuantă de timp la fiecare întrerupere dată de ceasul de timp
real;

5-7
- trecerea taskului în starea READY la anularea contorului şi declararea de eveniment
semnificativ.
Din punct de vedere al evoluţiei programului, dacă taskul lucrează în buclă infinită, modul
de sincronizare realizat de această directivă este prezentat în Figura 5.7.

Se observă că intervalul de timp de reprogramare a execuţiei taskului este Δt + τ cu τ


variabil deoarece nu este cunoscut momentul intrării în execuţie a taskului şi nici durata execuţiei
lui. (Observaţie: La expirarea intervalului de timp Δt, taskul este trecut în starea READY
urmând să fie adus în execuţie de către EXECUTIV funcţie de procedeul ales pentru planificarea
taskurilor pentru execuţie). Acest mod de sincronizare a execuţiei unui task poate fi satisfăcător
numai dacă τ << Δt. În caz contrar, intervalul de timp de reprogramare a execuţiei taskului nu mai
poate fi evaluat.
În aplicaţiile practice se doreşte însă ca intervalul de reprogramare a execuţiei unui task să
fie cunoscut şi să aibă valoarea Δt, specificată ca parametru în directivă. Altfel spus, se doreşte o
sincronizare de tipul celei arătate în Figura 5.8.

Utilizând directiva AŞTEAPTĂ(Δt) o astfel de evoluţie se poate obţine introducând în


aplicaţie un task suplimentar numit task planificator şi utilizând o variabilă eveniment EVS având
valoarea iniţială FALS. Structura celor două taskuri (planificator şi reprogramat) este prezentată
în Figura 5.9, iar diagrama de lucru este cea din Figura 5.10.

5-8
Deşi se pierde un interval de timp Δt la pornirea aplicaţiei (momentul 0) şi deşi nu se
cunoaşte exact momentul intrării în execuţie a taskului şi nici durata execuţiei sale, evoluţia este
satisfăcătoare dacă suntem siguri că execuţia taskului REPROGRAMAT are loc în intervalul de
timp Δt, adică τ < Δt.
2. Primitiva MARCHEAZĂ (Δt, EV) deşi are
efect tot numai asupra taskului care o lansează,
prezintă avantaje şi facilităţi în privinţa realizării
sincronizării dorite conform diagramei din Figura 5.8.
Această primitivă presupune efectuarea din partea
EXECUTIVULUI a următoarelor acţiuni
neîntreruptibile:
- înscriera valorii Δt într-un contor local aferent
taskului;
- ştergerea variabilei eveniment EV (EV devine
FALS);
- decrementarea contorului cu o cuantă de timp la
fiecare întrerupere dată de ceasul de timp real;
- setarea variabilei eveniment EV (EV devine
ADEVĂRAT) la anularea contorului şi declararea de
eveniment semnificativ. Figura 5.11

De remarcat este faptul că în urma apelării acestei directive, taskul nu se blochează, ci îşi va
continua execuţia până va întâlni şi va lansa directiva AŞTEAPTĂ(EV). Dacă în acest moment
intervalul de timp Δt nu expirase, taskul se va bloca până la expirarea acestui interval de timp,
când variabila eveniment EV va fi setată şi taskul va trece în starea READY. Structura
programului unui task reprogramat prin intermediul acestei directive este prezentată în Figura
5.11, iar diagrama de lucru este cea din Figura 5.8.
Avantajul acestei structuri este acela că nu mai este nevoie de un task suplimentar, ca în
cazul anterior, şi nu se mai pierde primul interval de reprogramare.
3. Primitiva REPROGRAMEAZĂ (NRTASK, Δt) are efect asupra taskului al cărui număr
sau nume este specificat ca parametru în directivă. Acest task poate fi chiar taskul care apelează
directiva sau oricare alt task component al aplicaţiei. În cazul în care taskul menţionat în directivă
este chiar taskul apelant, sincronizarea funcţionării se realizează conform schemei din Fig. 5.7,
iar când taskul menţionat este altul decât taskul apelant, sincronizarea funcţionării se realizează
conform schemei din Fig. 5.10. Acest din urmă caz presupune existenţa fie a unui task
suplimentar care să efectueze reprogramarea tuturor taskurilor constituente ale aplicaţiei, sau
reprogramarea să se facă în secvenţa de iniţializare a taskului (care se execută o singură dată la
pornire). Activitatea EXECUTIVULUI în urma apelării acestei directive este următoarea:

5-9
- trece taskul specificat într-o tabelă de ceas aferentă unităţii de timp asociate intervalului
de timp Δt;
- încarcă valoarea Δt într-un contor inclus în aceeaşi tabelă;
- blochează taskul până la expirarea intervalului de timp Δt;
- decrementează contorul cu o cuantă de timp la fiecare întrerupere dată de ceasul de timp
real;
- trece taskul specificat în starea READY la anularea contorului, reînscrie valoarea Δt în
contor şi declară eveniment semnificativ.
Structura programului unui task reprogramat prin intermediul acestei directive este
prezentată în Fig. 5.12, iar diagrama de lucru este cea din Fig. 5.10.

Observaţie: Pentru anularea reprogramării unui task trebuie creată o primitivă specială,
ANULEAZĂ, având ca parametru numărul sau numele taskului, care determină EXECUTIVUL
să-l scoată din listele de ceas.

5.5. Comunicarea între taskuri


În cazul în care excluderea mutuală şi sincronizarrea taskurilor se realizează prin
intermediul semafoarelor şi a variabilelor eveniment, cel mai eficient mod de a rezolva problema
comunicării între taskuri constă în utilizarea unei zone de memorie accesibilă tuturor taskurilor
care cooperează, numită zonă comună. Această zonă este structurată în funcţie de natura
informaţiilor schimbate şi de regulile care guvernează comunicarea propriu-zisă. Datele comune
schimbate între taskuri poartă denumirea generală de mesaje. Ele sunt transmise de un task numit
task PRODUCĂTOR şi destinate unui alt task numit task CONSUMATOR, care fie că le
aşteaptă, fie că le va găsi în momentul în care are nevoie de ele.
În procesul de comunicare prin intermediul zonelor comune, pot apare două situaţii:
1. Mesajul transmis de un task nu are o destinaţie specială, el putând fi consumat de orice
alt task al aplicaţiei. Dacă mesajul nu este consumat între două depuneri succesive, el se va
pierde prin înscriera peste el al unui alt mesaj. În acest caz este nevoie ca taskul consumator să nu
poată extrage un mesaj pe care producătorul este în curs să-l depună, iar taskul depunător să nu
poată depune un mesaj pe care consumatorul este în curs a-l extrage sau, altfel spus, operaţiile de
depunere şi extragere a mesajelor trebuie să se execute în excludere mutuală la nivelul mesajului.
Această condiţie este satisfăcută prin introducerea unui semafor de excludere mutuală asociat
zonei comune, notat ZC. Corespondenţa între două taskuri Ti şi Tj se stabileşte programând la
nivelul fiecăruia următoarele secvenţe de instrucţiuni, Fig. 5.13.

5 - 10
Figura 5.13
Deci, zonei comune i se asociază semaforul ZC având valoarea iniţială 1. Înainte de
depunerea mesajului, taskul PRODUCĂTOR Ti este obligat să execute primitiva P(ZC) în urma
căreia este exclus accesul la zona comună al oricărui alt task Tj, j ≠ i, iar după depunerea
mesajului este obligat să execute primitiva V(ZC) care eliberează accesul la zona de date comune
a taskurilor consumatoare.
2. Mesajul este destinat numai unui singur task. În acest caz se creează primitive speciale
de transmitere, respectiv de recepţionare a mesajelor care vor cuprinde pe lângă mesajul transmis
(recepţionat) numele sau numărul taskului transmiţător (consumator), precum şi un mecanism de
sincronizare. Cel mai eficient este ca acest mecanism să fie implicit, adică încorporat în directive
prin intermediul variabilelor eveniment. Aceste primitive sunt de forma:
- TRANSMITE (EV, TASKCONS, MESAJ);
(SEND)
- RECEPTIONEAZĂ (TASKPROD, MESAJ).
(RECEIVE)
Directiva TRANSMITE(⋅) este lansată din taskul producător TASKPROD şi presupune
executarea următoarelor acţiuni din partea EXECUTIVULUI:
- setarea variabilei eveniment EV (EV capătă valoarea ADEVĂRAT);
- depunerea mesajului (de regulă de lungime fixă) şi a numelui sau numărului taskului
căruia îi este destinat acest mesaj (TASKCONS) la o adresă MESAJ într-o zonă de memorie de
regulă alocată dinamic.
Directiva RECEPTIONEAZĂ(⋅) lansată din taskul consumator TASKCONS testează dacă
la adresa MESAJ este înscris numele sau numărul său şi dacă da, preia mesajul transmis, iar dacă
nu, evoluţia programului, în general, nu mai poate fi controlată. De aceea, pentru o funcţionare
corectă a comunicării între taskuri prin intermediul acestor directive, trebuie realizate următoarele
deziderate:
- taskul producător TASKPROD transmite un mesaj taskului consumator TASKCONS şi
nu trebuie să-i mai transmită un alt mesaj până nu se asigură că acest task a preluat mesajul (adică
până nu i se confirmă recepţionarea lui);
- taskul consumator TASKCONS trebuie să aştepte mesajul transmis de taskul producător
TASKPROD, dacă acesta nu a fost încă transmis, şi să confirme consumarea lui pentru a permite
taskului producător să-i transmită un nou mesaj.
Sincronizarea comunicării celor două taskuri se realizează cu ajutorul variabilelor
eveniment. Cum, de obicei, în orice problemă de transmisie-recepţie mesaje este necesară şi o
sincronizare a comunicării cu o condiţie de timp, în Fig. 5.14 este prezentată structura celor două

5 - 11
taskuri care comunică prin intermediul celor două directive TRANSMITE şi RECEPTIONEAZĂ
şi unde sincronizarea cu timpul se realizează prin intermediul unei directive tip
REPROGRAMEAZĂ(NRTASK, Δt).

Variabilele de sincronizare EV1 şi EV2 au valoarea iniţială FALS. În felul acesta taskul
consumator TASKCONS aşteaptă de fiecare dată pe variabila EV1 până când taskul producător
TASKPROD îi transmite mesajul pregătit, la expirarea intervalului de timp Δt (când EV1 capătă
valoarea ADEVĂRAT). În continuare, taskul producător aşteaptă pe variabila eveniment EV2
până îi soseşte confirmarea (adică variabila EV2 capătă valoarea ADEVĂRAT) că taskul
consumator a preluat mesajul şi este capabil să primească un nou mesaj.
Observaţie: După cum s-a mai arătat, directiva REPROGRAMEAZĂ putea fi lansată şi
dintr-un alt task, eventual un task de iniţializare.

5.6. Realizarea operaţiillor multitasking prin intermediul mesajelor şi cutiilor


poştale
Acest mod de realizare a operaţiillor multitasking a fost creat de Hoare în anul 1972.
Mesajul reprezintă un anumit volum de informaţii, de regulă cu structură fixă, care trebuie
transmis de la un task către alt task în procesul interacţiunii lor. Taskul care a transmis un mesaj,
trebuind să-şi continue execuţia, face necesară memorarea mesajului până ce acesta va fi
recepţionat de celălalt task. Zona din memorie unde sunt înscrise informaţiile necesare pentru
transmisia şi recepţia corectă a mesajelor poartă denumirea de cutie poştală (mailbox).
În cadrul acestui mecanism, mesajele sunt manevrate prin intermediul a două directive:
- TRANSMITE(adresă cutie poştală, adresă mesaj);
(SEND)
- RECEPŢIONEAZĂ(adresă cutie poştală, interval de timp Δt).
(RECEIVE)
Dacă în directiva RECEPŢIONEAZĂ, intervalul de timp Δt este nul, atunci taskul care
apelează această directivă se va bloca până la sosirea mesajului la cutia poştală specificată. Dacă
intervalul de timp este nenul (Δt ≠ 0), atunci taskul se va bloca fie până la sosirea mesajului, fie

5 - 12
până la expirarea intervalului de timp Δt. O altă particularitate a mecanismului constă în aceea că
mesajele transmise de un task nu se înscriu unele peste celelalte, ci formează o coadă de mesaje.
De asemenea, dacă mai multe taskuri solicită un mesaj de la o cutie poştală la care mesajul
încă nu a sosit, taskurile formează şi ele o coadă de aşteptare de tip FIFO. Astfel, dacă un mesaj
este transmis la o cutie poştală la care aşteaptă mai multe taskuri, el va fi preluat de primul task
din coada de aşteptare la cutie. Dacă un task soseşte la o cutie poştală la care aşteaptă mai multe
mesaje, taskul va primi primul mesaj din coada de mesaje.
Prin intermediul mesajelor şi cutiilor poştale, operaţiile multitasking permit o tratare
unitară.
Astfel, schema de sincronizare a două taskuri pe un eveniment exterior este prezentată în
Fig. 5.15.

Taskul T2 este planificat pentru execuţie de către un alt task T1 numit task planificator,
care are o structură ciclică bine determinată:
- aşteaptă pe o cutie poştală CX un mesaj de la un periferic P sau din proces, mesaj care are
semnificaţia că evenimentul exterior a avut loc;
- aşteaptă pe o cutie poştală C2, un mesaj răspuns MES_RĂSP de la taskul T2 care
specifică faptul că acest task este funcţional;
- transmite prin cutia poştală C1 mesajul de sincronizare MES_SINCR taskului T2 care va
permite intrarea acestuia în execuţie;
- revine în aşteptarea mesajului pe cutia poştală CX.
Observaţie: La pornire, taskul planificator T1, în secvenţa de iniţializare, trebuie să
transmită un mesaj răspuns MES_RĂSP în cutia poştală C2 pentru a-şi putea continua execuţia
(taskul T2 neexecutându-se niciodată nu a putut să depună nici un MES_RĂSP în cutia poştală
C2 chiar dacă acesta este funcţional).
Taskul T2 are şi el, în general, o structură ciclică bine determinată:
- aşteaptă pe cutia poştală C1 mesajul de sincronizare de la taskul T1 pentru a-şi putea
continua execuţia;
- transmite, prin cutia poştală C2, taskului T1 mesajul răspuns care confirmă că taskul T2
este funcţional şi deci va putea primi un nou mesaj;
- execută secvenţa de instrucţiuni care realizează funcţia pentru care a fost creat taskul;
- revine în aşteptare pe mesajul de sincronizare de la taskul T1.

5 - 13
Procedeul de mai sus poate fi utilizat şi în cazul reprogramării execuţiei taskului T2 cu un
interval de timp predefinit, Δt, obţinându-se astfel o sincronizare pe o condiţie de timp de tipul
celei din Fig. 5.16.

Figura 5.16.
În acest caz, taskul T1 va aştepta pe cutia poştală goală CX intervalul de timp Δt specificat
în directiva RECEIVE. Evident, în cutia poştală CX nefiind nici un mesaj, taskul T1 va trebui să
aştepte intervalul de timp Δt după care îşi va putea continua execuţia şi deci va determina intrarea
în execuţie a taskului T2. Schema de sincronizare a taskului T2 pe o condiţie de timp este
prezentată în Figura 5.17.

Pentru realizarea excluderii mutuale între două sau mai multe taskuri se foloseşte o cutie
poştală CEM în care este depus un mesaj simbolic MEM. Fiecare task, înainte de a intra în
propria secţiune critică este obligat să extragă mesajul din această cutie poştală şi să-l depună
înapoi la părăsirea secţiunii critice. În caz că un task Tj care solicită intrarea în secţiunea critică
constată că în cutia poştală CEM nu există mesajul, aceasta semnifică faptul că un alt task Ti se
află în secţiunea critică a programului său şi taskul solicitant Tj este pus să aştepte până când
taskul Ti iese din secţiunea sa critică depunând mesajul MEM înapoi în CEM. În felul acesta,
suntem siguri că nu poate avea loc accesul simultan (execuţia mutuală) a două sau mai multe
taskuri la una şi aceeaşi resursă. Schema de excludere mutuală între două sau mai multe taskuri
este dată în Figura 5.18.

5 - 14
Pentru realizarea comunicarii între taskuri se pot folosi zone de date comune protejate la
accesul simultan prin mecanismul de excludere mutuală prezentat mai sus, sau se pot folosi
mesaje care se transmit între taskuri prin intermediul cutiilor poştale.
În acest din urmă caz, se utilizează 2 cutii poştale C1 şi C2, prima memorând mesajul util
(care conţine datele transmise de către taskul producător către taskul consumator), iar a doua
memorând un mesaj simbolic, de răspuns, transmis de către taskul consumator către taskul
producător care semnifică faptul că mesajul util a fost recepţionat, taskul consumator este
funcţional şi deci capabil să primească un nou mesaj în cazul unei funcţionări ciclice a acestuia.
Taskul producător nu va trimite un nou mesaj taskului consumator până când acesta din
urmă nu va confirma primirea lui prin mesajul răspuns pe care îl returnează. În felul acesta se va
evita blocarea sistemului prin încărcarea cutiilor poştale cu mesaje nepreluate. Acest procedeu se
utilizează când este necesar transferul unui volum mic de date între taskuri, care pot fi conţinute
într-un singur mesaj.
Schema comunicării între două taskuri prin intermediul mesajelor şi cutiilor poştale este
prezentată în Figura 5.19.

5 - 15
Observaţie: Un volum mai mare de date se transmite prin intermediul zonelor comune.

Utilizarea conceptului de MONITOR pentru realizarea operaţiilor multitasking


Conceptul de MONITOR reprezintă procedeul cel mai modern de rezolvare a operaţiilor
multitasking. El poate fi gândit ca o "împrejmuire" în interiorul căreia sunt incluse toate datele
critice (date care se schimbă între taskuri). "Împrejmuirea" are o serie de "porţi", fiecare "poartă"
corespunzând unei proceduri speciale de program numită ENTRY (ACCES) declarată şi
construită în structura de MONITOR. Orice task care solicită accesul la datele critice sau la o
resursă partajată, trebuie să apeleze în prealabil o astfel de procedură.
Executivul S.O. este astfel conceput încât unui singur task şi numai unuia singur i se
permite accesul, la un moment dat, în interiorul monitorului, ceea ce asigura implicit situaţia de
excludere mutuală şi comunicare între taskuri prin zone de date comune.
Pentru realizarea sincronizării se folosesc 2 directive WAIT şi SIGNAL care acţionează
asupra unor variabile logice speciale numite variabile de tip condiţie.
Dacă continuarea execuţiei unui task T1 este dependentă, la un moment dat, de o anumită
condiţie (expirarea unui interval de timp sau producerea unui eveniment exterior), taskul T1 este
introdus în MONITOR printr-o procedură ENTRY şi, la momentul critic al execuţiei, va executa
directiva WAIT(C) unde C este variabila de tip condiţie asociată. Dacă condiţia C nu a fost
îndeplinită, executarea acestei directive va bloca taskul şi îl va elimina din MONITOR, punându-l
într-o coadă de aşteptare până la îndeplinirea condiţiei C. Dacă între timp un alt task T2, intrând
în MONITOR, găseşte condiţia C satisfăcută, va fi pus să execute directiva SIGNAL(C) care are
ca efect eliminarea taskului T2 din MONITOR şi reîntoarcerea taskului T1 (în general, a primului
task care aşteapta pe condiţia C) care îşi va continua execuţia. În felul acesta, toate operaţiile
multitasking se realizează în mod unitar şi comod din punct de vedere al programatorului.
Conceptul de MONITOR stă la baza EXECUTIVELOR sistemelor de operare care permit
implementarea limbajului PASCAL-CONCURENT.

Utilizarea conceptului de RENDEZVOUS pentru realizarea operaţiilor multitasking


Acest concept a fost introdus odată cu limbajul ADA, permiţând (alături de alte facilităţi
specifice) realizarea operaţiilor multitasking direct în limbaje de nivel înalt.
Conceptul de RENDEZVOUS poate fi privit ca o combinare a operaţiilor de sincronizare şi
de comunicare între taskuri.
Presupunem 2 taskuri care lucrează independent şi care la un moment dat trebuie să se
sincronizeze pentru a schimba date, după care îşi vor continua execuţia. Sincronizarea în scopul
comunicării de date între taskuri a primit în ADA numele de RENDEZVOUS.
Fie 2 taskuri T1 si T2 care trebuie sincronizate în scopul unui schimb de date.

Taskul T1 conţine o construcţie similară unui apel de procedură, specificând însă şi numele
taskului cu care se va sincroniza (T2); apelul de procedură poate conţine o listă de parametri
actuali. În taskul T2 se foloseşte un bloc special (instrucţiune) numit ACCEPT, similar declarării
unei proceduri.
Blocul ACCEPT conţine o secvenţă de instrucţiuni marcată de cuvintele cheie do şi end.
Cele două puncte specificate se numesc, în taskul T1 - punct de RENDEZVOUS, iar în
taskul T2 - punct de sincronizare.

5 - 16
Când T1 ajunge în punctul de RENDEZVOUS, aşteaptă ca T2 să ajungă în punctul de
sincronizare; similar, dacă T2 ajunge în punctul de sincronizare, aşteaptă ca T1 să ajungă în
punctul de RENDEZVOUS, realizându-se astfel sincronizarea celor 2 taskuri.
În acest moment, se execută o acţiune similară apelului între proceduri. Taskul T1 este
blocat, iar instrucţiunile cuprinse în blocul ACCEPT se execută ca o procedură, implicând deci şi
un transfer de parametri între cele două taskuri.
După execuţia instrucţiunii ACCEPT, cele două taskuri îşi continuă execuţia în mod
independent.

5 - 17
CAP. 6. EXECUTIV DE TIMP REAL DESTINAT CONDUCERII CU
CALCULATOR A PROCESELOR INDUSTRIALE

6.1. Prezentare generală


Scrierea unui EXECUTIV multitasking în timp real destinat administrării software (SW) a
unei aplicaţii de conducere are rolul de a degreva programatorul de unele activităţi de rutină,
comune tuturor aplicaţiilor cu opţiuni de timp real, permiţând concentrarea atenţiei acestuia
exclusiv asupra organizării şi structurării aplicaţiei şi asupra scrierii programelor specifice.
În acest capitol se va prezenta structura unui astfel de EXECUTIV în timp real dedicat
aplicaţiilor de conducere a proceselor industriale cu microcalculator de proces.
Schema bloc a acestui EXECUTIV este prezentată în Fig. 6.1.

Fig. 6.1.

Acest EXECUTIV are următoarele caracteristici:


- este implementabil, cu mici modificări, pe orice echipament numeric de conducere bazat
pe microprocesorul 80x86;
- este modularizat, oferind posibilitatea folosirii în cadrul unei aplicaţii numai a modulelor
SW necesare, evitându-se astfel încărcarea nejustificată a memoriei echipamentului;
- modulele executivului legate cu programele specifice aplicaţiei sunt complet rezidente în
memoria calculatorului formând aplicaţia "dedicată";

6-1
- permite realizarea operaţiilor multitasking de sincronizare şi excludere mutuală cu ajutorul
variabilelor tip eveniment (flaguri) care se împart în două categorii: flaguri pentru sincronizare şi
flaguri pentru excludere mutuală;
- permite realizarea comunicării între taskuri prin intermediul zonelor de date comune;
- planificarea taskurilor pentru execuţie se poate face pe bază de priorităţi alocate taskurilor;
- comutarea stării taskurilor se poate realiza atât prin întreruperi cât şi prin directive
apelabile din taskuri;
- pentru efectuarea calculelor implicate în taskurile componente ale aplicaţiei poate fi
folosită orice bibliotecă aritmetică cu proceduri reentrante, fie în virgulă fixă (mai rapidă), fie în
virgulă mobilă (mai lentă), modulele bibliotecii legându-se opţional în cadrul aplicaţiei alături de
modulele scrise de utilizator;
- pentru a uşura activitatea de dezvoltare şi de depanare a programului aferent aplicaţiei,
EXECUTIVUL poate fi însoţit de un MONITOR propriu care permite programatorului
inspectarea şi modificarea tabelelor de taskuri şi de flaguri.
Mecanismul multitasking pe care-l oferă EXECUTIVUL (stările taskurilor şi tranziţiile
între aceste stări) este prezentat în diagrama din Fig. 6.2.

6.2. Nucleul EXECUTIVULUI de timp real


(modulul de gestiune al taskurilor - TKMS)
EXECUTIVUL prezentat permite lucrul pseudoconcurent a maximum 63 de taskuri de
aplicaţie, un al 64-lea task fiind un task de aşteptare (WAITSYS) propriu nucleului. Acest task
menţine unitatea centrală a echipamentului în starea HALT pe perioadele când toate celelalte
taskuri aferente aplicaţiei sunt blocate. S-a ales această stare (HALT), deoarece din această stare
microprocesorul poate servi o cerere de întrerupere cu cea mai mare promptitudine.
Taskurile componente aplicaţiei, rezidente în memoria echipamentului la adrese cunoscute,
sunt aduse la cunoştinţa EXECUTIVULUI şi, mai exact, a părţii sale componente cea mai
importantă numită "planificatorul de taskuri" prin directiva de instalare.

6-2
Planificatorul de taskuri păstrează o "listă" cu informaţii despre taskuri, această listă având
un număr corespunzător de "casete" (câte o casetă pentru fiecare task). Fiecare casetă este
formată din câte 4 octeţi de memorie.
Această listă fiind aşezată în aceeaşi pagină de memorie RAM limitează numărul maxim de
taskuri la 64 (256 : 4 = 64).
Informaţiile care se păstrează în casetele acestei liste sunt următoarele (Fig. 6.3):

Fig. 6.3.

- Primul octet păstrează informaţii referitoare la starea taskului. Din punct de vedere al
planificatorului de taskuri, un task se poate afla în stările NEINSTALAT (planificatorul nu are
nici o informaţie despre task, deşi acesta este încărcat în memorie; taskul nu are rezervată nici o
casetă în lista taskurilor) şi ACTIV, cu substările prezentate în Fig. 6.2 (taskul a fost instalat
printr-o comandă de monitor sau directivă de instalare şi i s-a creat o casetă în lista
planificatorului). Octetul de stare al casetei poate avea următoarele valori hexazecimale:
- 00h reprezentând task OPRIT sau nivel liber;
- (01h-0FEh) reprezentând task BLOCAT pe un flag al cărui număr se calculează cu
relaţia "număr flag = valoare octet stare - 1" (avem astfel la dispoziţie un număr de 254 flaguri
eveniment a căror valoare este cuprinsă între 00h şi 0FDh, fiecare flag fiind reprezentat pe un
octet într-o listă sistem de flaguri);
- 0FFh reprezentând task aflat în substarea GATA DE EXECUŢIE;
- Octeţii 2 şi 3 conţin adresa vârfului stivei asociate taskului. Adresa bazei stivei se
defineşte la instalare şi această stivă va rămâne permanent sub administrarea unică a taskului. În
momentul blocării taskului, informaţiile despre el (adresa de continuare, conţinutul registrelor
generale şi al indicatorilor de condiţie) sunt salvate în această stivă în continuarea datelor utile.
Astfel, la revenirea în execuţie a taskului, după refacerea contextului, stiva se va găsi la fel ca în
momentul blocării taskului.
- Octetul 4 nu este folosit, fiind păstrat în rezervă.
Deci, fiecărui task îi corespunde o astfel de casetă în lista planificatorului. Ordinea acestor
casete în listă este fixă şi determină totodată şi nivelul de prioritate al taskului. Rezultă că
taskurile vor avea priorităţi fixe, nivelurile de prioritate fiind numerotate de la 0 la dimensiunea
maximă a listei de taskuri. Nivelul cel mai prioritar este nivelul 0 şi pe fiecare nivel de prioritate
se poate instala cel mult un task.

6-3
La iniţializarea sistemului, taskul de aşteptare WAITSYS este automat instalat pe nivelul cu
prioritatea cea mai mică (ultima casetă din listă) şi este trecut în substarea gata de execuţie.
Planificatorul de taskuri va verifica lista taskurilor pornind de la nivelul de prioritate 0, va
continua verificarea listei de taskuri până la nivelul de prioritate minimă pe care se va afla taskul
WAITSYS.
În caz că nici un task al aplicaţiei nu este gata de execuţie, planificatorul va găsi totuşi
taskul WAITSYS în starea GATA DE EXECUŢIE şi va aduce unitatea centrală în HALT,
urmând să fie scoasă din această stare printr-o întrerupere (eventual de la ceasul de timp real).
Pentru realizarea operaţiilor multitasking de sincronizare, excludere mutuală şi comunicare
între taskuri, programatorul are la dispoziţie un număr de 254 flaguri (variabile tip eveniment)
care pot lua doar două valori: RESET (flagul are valoarea 00h) şi SET (flagul are valoarea 0FFh)
şi care sunt memorate pe un octet într-o listă specială de flaguri a nucleului. Asupra acestor
flaguri utilizatorul poate acţiona numai prin intermediul unor directive specializate de tip
declanşează, consumă, citeşte, aşteaptă, directive care vor fi prezentate în continuare. De regulă,
primele 16 flaguri sunt la dispoziţia sistemului (se folosesc în drivere) şi nu se recomandă
utilizarea lor de către programator.
În vederea obţinerii cu succes a operaţiei de excludere mutuală (de simulare a primitivelor
P şi V), pentru flagurile începând de la o anumită valoare (selectabilă la generarea sistemului),
directivele de aşteptare şi consumare a unui eveniment se execută succesiv într-o secvenţă
neîntreruptibilă (simularea primitivei P). Primitiva V este realizată de directiva de declanşare a
evenimentului.

Directivele nucleului EXECUTIVULUI


Directivele nucleului executivului sunt subrutine de sistem prin intermediul cărora este
permis accesul taskurilor utilizator la listele interne ale sistemului, producând modificări în ele şi,
implicit, modificări ale stărilor taskurilor.
Directivele EXECUTIVULUI se pot împărţi în două categorii:
- directive explicite apelate de utilizator în cadrul taskurilor;
- directive implicite care sunt apelate prin intermediul directivelor din prima categorie.
De asemenea, directivele, după necesităţi, pot declara eveniment semnificativ la apelarea
lor (ceea ce va determina transferul controlului către planificatorul de taskuri) sau pot returna
controlul taskului apelant, după efectuarea serviciului cerut (nu declară eveniment semnificativ).
Transferul de parametri către şi dinspre directive se face prin intermediul registrelor
microprocesorului. Pe timpul lucrului directivelor, deoarece se fac modificări în tabelele de
sistem, sistemul de întreruperi al microprocesorului trebuie
dezactivat pentru a impiedica apariţia unor situaţii nedorite.
Din acest motiv, toate directivele explicite "sensibile" se
prezintă în două variante, apelabile astfel:
?nume şi ?Inume
Funcţia lor este identică, însă din punct de vedere al
întreruperilor situaţia se prezintă astfel:
- prima varianta (?nume) se foloseşte pentru apel din
task şi conţine în corpul ei instrucţiuni de dezactivare şi apoi
de activare a sistemului de întreruperi;
- a doua variantă se foloseşte fie ca apel direct din

6-4
întreruperi (poate fi considerată ca o subrutină de tratare a întreruperii), fie ca apel din task în
condiţiile în care sistemul de întreruperi era deja dezactivat.
Ca parametru de stare al directivelor se foloseşte indicatorul CF cu următoarea
semnificaţie: dacă directiva nu se execută cu succes CF = 1; în caz contrar CF = 0.

Directivele ?INS / ?IINS


- Sunt directive explicite de "instalare" a taskurilor folosite la comunicarea unor informaţii
despre task către planificator;
- Parametri:
- intrare: (AX) - nivel de prioritate al taskului;
(DX) - adresa de start a taskului;
(BP) - adresa bazei stivei asociate taskului.
- ieşire: -
- Directivele nu declară eveniment semnificativ.
Structura directivei ?IINS este prezentată în Figura 6.5.

Directiva ?SCINI
- Este o directivă explicită de iniţializare, care umple cu zero întreaga zonă de date sistem
(aflată între modulul FRAM = începutul zonei de date sistem şi modulul LRAM = sfârşitul zonei
de date sistem);
- Resetează toate flagurile;
- Dezactivează sistemul de întreruperi;
- Instalează pe ultimul nivel de prioritate considerat, taskul WAITSYS care este trecut în
starea gata de execuţie;
- Nu necesită parametri;
- Nu declară eveniment semnificativ.

6-5
Directiva ?DECLR
- Directivă atât explicită cât şi implicită care are ca efect declararea unui eveniment
semnificativ în sistem. În urma apelarii acestei directive de către taskul aflat în execuţie, controlul
se transferă planificatorului de taskuri care va baleia lista de taskuri şi va aduce în execuţie taskul
gata de execuţie cu prioritatea cea mai mare;
- Nu necesită parametri;
- Are următorul conţinut:
call ?MONI
jmp ?SC

Directiva ?MONI
- Este o directivă implicită care nu necesită parametri;
- Dezactivează întreruperile (dacă la apelul acestei directive, sistemul de întreruperi era deja
dezactivat, se face apelul: call ? MONI + 1);
- Salvează în stiva taskului apelant contextul momentului întreruperii (conţinutul registrelor
microprocesorului precum şi al indicatorilor de condiţie);
- Marchează în caseta taskului (în lista de taskuri) adresa vârfului stivei taskului;
- Comută pe o stivă monitor definită iniţial la generarea sistemului (pentru a nu altera stiva
taskului).
Adresa de restart (reluare) a taskului întrerupt se salvează în stiva taskului în momentul
apelului unei directive, care la rândul ei va apela ?MONI, înscriind în stiva taskului alţi 2 octeţi
care nu vor avea nici o utilitate, deoarece din ?MONI nu se mai revine prin instrucţiunea RET
(deoarece SP-ul a fost comutat de pe stiva taskului pe stiva monitor) ci printr-o tehnică specială
(vezi listingul programului - la aplicaţii). Rezultă deci necesitatea prevederii celor 2 octeţi
suplimentari (după adresa de restart) în stiva taskului (vezi Fig. 6.3) şi faptul că ei trebuie ignoraţi
de către utilizator.
Directiva ?SC
- Este punctul de intrare în planificatorul de taskuri;
- Determină baleierea listei de taskuri şi lansează în execuţie taskul gata de execuţie cu
prioritatea cea mai mare;
- Structura planificatorului de taskuri este dată în Figura 6.6;
- Lansarea planificatorului este precedată de directiva ?MONI care salvează în stivă
informaţiile despre task conţinute în registre, necesare în cazul reluării execuţiei taskului.

6-6
Figura 6.6
?ATCTA
Este adresa unei locaţii de memorie unde se păstrează, pe 2 octeţi, adresa de început a
casetei taskului aflat în execuţie. Această adresă este permanent împrospătată de către planificator
şi conţinutul ei este folosit de alte directive.

Directiva ?SCEXI
- Este o directivă implicită (în cazul de faţă, partea finală a planificatorului de taskuri);
- Nu necesită parametri;
- Preia adresa vârfului stivei asociate taskului care are adresa casetei în ?ATCTA;
- Reface din stivă toate registrele taskului;
- Activează sistemul de întreruperi;
- Dă controlul taskului lansându-l în execuţie.

Directivele ?RUN / ?IRUN


- Sunt directive explicite de trecere a unui task în starea GATA DE EXECUŢIE (înscriu în
octetul de stare al casetei taskului codul 0FFh).
- Parametri: la apelul acestor directive, registrul AL trebuie să conţină următoarele
informaţii:
(AL) = <Mod> <Nivel de prioritate>
- biţii A5-A0 ai acumulatorului AL conţin nivelul de prioritate al taskului ce trebuie
activat, nivel cuprins între (00h - 3Fh);
- bitul A6 = 0;

6-7
- bitul A7 este bitul <Mod> care indică dacă trecerea în starea GATA DE
EXECUŢIE a taskului specificat prin nivelul său de prioritate se va face "necondiţionat", adică
indiferent de starea în care se află, caz în care MOD = 1 sau "condiţionat", adică numai în cazul
în care taskul era în substarea OPRIT, caz în care MOD = 0;
- În prima variantă (?RUN), directiva declară eveniment semnificativ (vezi Figura 6.7.a),
iar în a doua variantă (?IRUN) returnează controlul taskului apelant;
- Structura directivei ?IRUN este prezentată în Figura 6.7.b.

Directivele ?ABORT / ?IABORT


- Sunt directive explicite de trecere forţată a unui task (altul decât taskul apelant) în
substarea OPRIT;
- Directivele vor înscrie în octetul de stare al casetei taskului codul 00h;
- Parametri: la apelul acestor directive, registrul AL trebuie să conţină nivel de prioritate al
taskului ce trebuie terminat forţat;
- Directiva declară eveniment semnificativ doar în prima variantă ?ABORT, asemănător
schemei din Figura 6.7.a, pe când varianta ?IABORT returnează controlul taskului apelant;
- Directiva ?IABORT calculează, pe baza nivelului de prioritate specificat, adresa casetei
taskului (ce se cere a fi terminat forţat) şi înscrie în octetul de stare al acestei casete codul 00h
corespunzător substării OPRIT.

6-8
Directiva ?EXIT
- Este o directivă explicită de terminare logică sau normală a unui task;
- Nu necesită parametri;
- Apelează directiva ?MONI pentru salvarea în stiva taskului apelant a stării taskului
(conţinutul registrelor);
- Pentru cazul în care se va face un nou apel de intrare în execuţie a acestui task este absolut
necesar ca în task, după directiva ?EXIT, să existe o instrucţiune de salt la prima instrucţiune a
taskului sau la un alt punct din task , pentru ca reluarea execuţiei să se facă corect;
- Directiva preia de la locaţia ?ATCTA adresa casetei taskului ce trebuie terminat sau
relansat în execuţie şi înscrie în octetul de stare al casetei lui codul 00h;
- Transferă controlul planificatorului de taskuri (declară eveniment semnificativ).

Directiva ?WAIT
- Este o directivă explicită care are ca efect punerea taskului apelant în aşteptare pe un flag
(blocarea taskului pe un flag);
- Parametru: la apelul acestei directive, registrul AL trebuie să conţină numărul flagului pe
care va fi blocat taskul;
- Dezactivează întreruperile;
- Salvează starea taskului apelând directiva ?MONI;
- Preia din ?ATCTA adresa casetei taskului ce trebuie pus în aşteptare şi înscrie în octetul
de stare al casetei codul corespunzător (format din numărul flagului specificat + 1);
- Transferă controlul planificatorului de taskuri (declară eveniment semnificativ).
În momentul ştergerii flagului, sau dacă flagul era deja şters, taskul trece în starea GATA
DE EXECUŢIE, iar atunci când prioritatea îi va permite îşi va continua execuţia cu instrucţiunea
următoare acestei directive. Dacă flagul este din categoria celor pentru excludere mutuală el va fi
imediat setat de către planificator (vezi structura planificatorului din Figura 6.6).

Directivele ?SETF / ?ISETF


- Sunt directive explicite care au ca efect setarea unui flag (specificat ca parametru în
directivă);
- Parametru: la apelul acestor directive, registrul AL trebuie să conţină numărul flagului
care va fi setat;
- Prima variantă (?SETF) declară eveniment semnificativ (asemănător schemei din Figura
6.7.a), iar cea de-a doua variantă (?ISETF) returnează controlul taskului apelant;
- Directiva ?ISETF intră în lista de flaguri a sistemului şi în octetul corespunzător flagului
ce trebuie setat înscrie codul 0FFh.

Directivele ?CLEF / ?ICLEF


- Sunt directive explicite care au ca efect resetarea (ştergerea) unui flag (specificat ca
parametru în directivă);
- Parametru: la apelul acestor directive, registrul AL trebuie să conţină numărul flagului
care va fi resetat;
- Directivele ?CLEF / ?ICLEF au aceleaşi caracteristici ca şi directivele ?SETF / ?ISETF,
cu observaţia că în lista de flaguri, în octetul corespunzător flagului specificat, directiva ?ICLEF
va trece codul 00h.

6-9
Directiva ?GETF
- Este o directivă explicită care permite citirea stării unui flag;
- Parametru: la apelul acestor directive, registrul AL trebuie să conţină numărul flagului
care va fi citit;
- Starea flagului este comunicată prin poziţionarea indicatorului CF astfel:
CF = 0 - flag resetat;
CF = 1 - flag setat;
- Nu declară eveniment semnificativ;
- Structura directivei este arătată în Figura 6.8.

Figura 6.8

Directiva ?GTSK
- Este o directivă explicită care permite citirea nivelului de prioritare pe care este instalat
taskul apelant;
- Nu necesită parametri;
- Citeşte adresa casetei taskului din ?ATCTA şi calculează, pe baza acestei adrese, nivelul
de prioritate al taskului;
- Returnează valoarea nivelului de prioritate în acumulator (AL);
- Nu declară eveniment semnificativ.

Nucleul EXECUTIVULUI oferă pe lângă directivele menţionate şi o serie de subrutine


scrise pentru uzul EXECUTIVULUI, dar care sunt accesibile şi utilizatorului, cum ar fi:
- subrutină de umplere cu zero a unei zone de date din memorie, ?ZERO;
- subrutină care calculează adresa casetei unui task plecând de la nivelul lui de prioritate,
?POZ;
- subrutină pentru modificarea indicatorului CF într-un task oprit (modificarea se face în
stiva taskului, acolo unde sunt salvaţi indicatorii de condiţie ai taskului), ?MODCF;
- subrutină pentru încărcarea în registrul BP a adresei vârfului stivei asociate taskului ce are
adresa casetei înscrisă în ?ATCTA, ?HLSPU etc.
Nucleul EXECUTIVULUI utilizează, prin intermediul planifica-torului de taskuri, o zonă
de memorie RAM rezervată pentru organizarea tabelelor sistem (lista de taskului, lista de flaguri,

6 - 10
anumite locaţii speciale, ca de exemplu ?ATCTA etc.). Este indicat ca lungimea acestei zone să
fie cât mai mică având în vedere că la majoritatea microcalculatoarelor de conducere a
proceselor, dimensiunea memoriei este critică. Valorile maxime limită pentru numărul de taskuri
(64), numărul de flaguri (254) rezultă din condiţia necesităţii plasării fiecarei liste într-o aceeaşi
pagină de RAM.
Tabelele de sistem se pot genera în limitele acestor dimensiuni prin intermediul următorelor
simboluri:
?NOT = numărul total de taskuri din listă (Observaţie: ?NOTmax = 64 = ?NOTT);
?TCT = adresa de început a listei de taskuri a planificatorului (lungimea maximă a listei va
fi (?NOTT x 4) octeţi);
?NOF = numărul de flaguri din listă;
?NOPF = numărul de unde încep flagurile pentru excludere mutuală;
?FLAG = începutul listei de flaguri;
?FRAM / ?LRAM = începutul şi sfârşitul zonei RAM de date sistem.

6.3.Definirea unor macroinstrucţiuni specifice nucleului executivului


Macroinstrucţiuni pentru instalarea unui task
INS macro NIVEL, START, STIVA
; NIVEL - nivelul de prioritate al taskului
; START - adresa de început a taskului
; STIVA - adresa bazei stivei asociate taskului
mov ax, NIVEL
mov dx, START
mov bp, STIVA
call ?INS
endm
IINS macro NIVEL, START, STIVA
mov ax, NIVEL
mov dx, START
mov bp, STIVA
call ?IINS
endm
Observaţie: Macroinstrucţiunea IINS poate fi apelată din întreruperi
Macroinstrucţiuni pentru trecerea unui task în starea READY
RUN macro NIVEL
mov al, NIVEL
call ?RUN
endm
Observaţie: Macroinstrucţiunea RUN declară eveniment semnificativ
IRUN macro NIVEL
mov al, NIVEL
call ?IRUN
endm
Observaţie: Macroinstrucţiunea IRUN nu declară eveniment semnificativ
Macroinstrucţiuni pentru declararea unui eveniment semnificativ
DECLR macro

6 - 11
call ?DECLR
endm
Macroinstrucţiuni pentru setarea unui flag
SETF macro FLAG
; FLAG - flagul pentru sincronizare sau pentru excludere mutuală
mov al, FLAG
call ?SETF
endm
Observaţie: Macroinstrucţiunea SETF declară eveniment semnificativ
ISETF macro FLAG
mov al, FLAG
call ?ISETF
endm
Observaţie: Macroinstrucţiunea ISETF nu declară eveniment semnificativ
Macroinstrucţiuni pentru resetarea unui flag
CLEF macro FLAG
mov al, FLAG
call ?CLEF
endm
Observaţie: Macroinstrucţiunea CLEF declară eveniment semnificativ
ICLEF macro FLAG
mov al, FLAG
call ?ICLEF
endm
Observaţie: Macroinstrucţiunea ICLEF nu declară eveniment semnificativ
Macroinstrucţiuni pentru blocarea unui task pe un flag
WAIT macro FLAG
mov al, FLAG
call ?WAIT
endm
Observaţie: Macroinstrucţiunea WAIT declară eveniment semnificativ
Macroinstrucţiuni pentru terminarea logică (normală) a unui task
EXIT macro
call ?EXIT
endm
Observaţie: Macroinstrucţiunea EXIT declară eveniment semnificativ
Exemplul 1. Activarea unui task din alt task
Se consideră 2 taskuri TA şi TB care afişează anumite mesaje pe display. Considerăm că
afişarea pe display se face prin intermediul unei subrutine CO care nu lucrează în întreruperi.
Taskul TA este instalat pe nivelul 2 de prioritate şi activat prin comenzi de la tastatură.
Taskul TA instalează, la rândul său, taskul TB pe nivelul 1 de prioritate şi îl activează, după care
tipăreşte un mesaj pe display. În continuare, taskul TA apelează directiva ?DECLR, deci declară
eveniment semnificativ. Planificatorul de taskuri ?SC preia acum controlul şi trece în execuţie
taskul TB care tipăreşte un mesaj pe display şi apoi apelează directiva ?EXIT (care declară
eveniment semnificativ). Planificatorul dă acum controlul taskului TA care îşi continuă execuţia
afişând al doilea mesaj pe display şi apoi îşi încheie execuţia prin directiva ?EXIT.
Structura programului care implementează cele două taskuri este următoarea:

6 - 12
EXTRN AFIS
TB equ ADR1 ; TB reprezintă adresa de start a taskului TB
STIVAB equ ADR2 ; STIVAB reprezintă adresa bazei stivei
; asociate taskului TB
TA: IINS 1, TB, STIVAB ; Macroinstrucţiunea IINS instalează
; taskul TB pe nivelul 1 de prioritate
IRUN 1 ; Macroinstrucţiunea IRUN trece în starea READY
; taskul TB instalat pe nivelul 1, fără să declare
; eveniment semnificativ
mov si, OFFSET mesaj1a
call AFIS
DECLR ; Macroinstrucţiunea DECLR declară eveniment
; semnificativ. Această directivă întrerupe taskul
; TA, salvează cu ?MONI conţinutul registrelor
; microprocesorului şi transferă controlul
; planificatorului de taskuri care va baleia lista de
; taskuri şi va aduce în execuţie taskul GATA DE
; EXECUŢIE cu prioritatea cea mai mare (în cazul
; nostru, taskul TB)
mov si, OFFSET mesaj2a
call AFIS
EXIT ; Macroinstrucţiune pentru terminarea logică
; (normală) a taskului TA care declară eveniment
; semnificativ (după execuţie transferă controlul
; planificatorului de taskuri ?SC)
TB: mov si, OFFSET mesaj1b
call AFIS
EXIT
mesaj1a db CR, LF, 'Task TA activ ...', $
mesaj2a db CR, LF, 'Task TA activ din nou ...', $
mesaj1b db CR, LF, 'Task TB activ ...', $
CR equ 0dh
LF equ 0ah
; Subrutina pentru afişare
AFIS: mov dl, [si]
cmp dl, '$'
jz FIN
inc si
mov ah, 2
int 21h
jmp AFIS
FIN: ret
end
După execuţia acestui program, pe ecran se vor afişa următoarele mesaje:
Task TA activ ...
Task TB activ ...
Task TA activ din nou ...
Se observă că deşi taskul TB este mai prioritar, el nu primeşte controlul decât la declararea
unui eveniment semnificativ (în urma apelului directivei ?DECLR).

6 - 13
Dacă taskul TB ar fi fost instalat pe un nivel mai puţin prioritar decât TA, de exemplu 3,
atunci, la declararea evenimentului semnificativ, s-ar fi dat controlul tot lui TA, deci ordinea
mesajelor afişate ar fi fost:
Task TA activ ...
Task TA activ din nou ...
Task TB activ ...
Să presupunem acum că nivele de prioritate alese sunt TA --> 2, TB --> 1, dar că în loc de
directiva ?IRUN, în taskul TA se foloseşte directiva ?RUN care, spre deosebire de ?IRUN,
declară eveniment semnificativ. În această situaţie, după instalarea taskului TB, la execuţia
directivei ?RUN se va declara eveniment semnificativ şi planificatorul va da controlul taskului
TB (cel mai prioritar în acel moment) şi deci secvenţa de mesaje afişate pe ecran va fi:
Task TB activ ...
Task TA activ ...
Task TA activ din nou ...
Cele trei situaţii expuse mai sus presupun că un eveniment semnificativ poate apare numai
în urma execţiei directivelor ?DECLR, ?EXIT, ?RUN.
Există însă posibilitatea apariţiei unui eveniment semnificativ datorită unei întreruperi
externe (de exemplu, de la ceasul de timp real). Dacă se consideră o asignare a priorităţilor de
forma TA --> 2, TB --> 1, iar pentru activarea lui TB se foloseşte directiva ?IRUN, apare ca
foarte probabilă următoarea situaţie: Taskul TA intră în execuţie, instalează şi activează taskul
TB şi începe afişarea caracterelor din mesaj1a. Dacă în acest moment apare o întrerupere de la
ceas, se declară eveniment semnificativ şi planificatorul găseşte taskul TB (cel mai prioritar) în
starea READY şi îi dă controlul. După terminarea lui TB se va continua execuţia lui TA din
punctul în care a fost întrerupt, deci mesajele afişate pe display ar putea apare în următoarea
secvenţă:
Task T ; Taskul TA a fost întrerupt
Task TB activ ... A activ ...
Task TA activ din nou ...
Această situaţie necesită ca cele două taskuri să se excludă reciproc pe durata afişării
mesajelor.

Exemplul 2. Sincronizarea taskurilor pe un eveniment


Considerăm 2 taskuri T1 şi T2 care, la un moment dat, trebuie să schimbe date între ele.
Taskul T1 preia o valoare dintr-un buffer, BUFT2 al taskului T2, după ce T2 a pregătit
aceste valori. T2 semnalează că datele sunt disponibile prin resetarea unui flag, FLG, flag pe care
aşteaptă T1 ca datele să devină disponibile. Se foloseşte un task de iniţializare T0 care instalează
T1 şi T2 şi setează flagul de sincronizare.
Structura programului este următoarea:
EXTRN AFIS, PRELUCRARE, GENERARE
STIVA1 equ ADR1 ; STIVA1 reprezintă adresa bazei stivei
; asociate taskului T1
STIVA2 equ ADR2 ; STIVA2 reprezintă adresa bazei stivei
; asociate taskului T2
BUFT2 dw ? ; Pentru bufferul BUFT2 se rezervă 2 octeţi
; începând de la adresa BUFT2
T0: IINS 1, T1, STIVA1 ; Se instalează taskul T1 cu adresa de început
; T1 pe nivelul de prioritate 1
IRUN 1 ; Taskul T1 este trecut în starea READY
IINS 2, T2, STIVA2 ; Se instalează taskul T2 cu adresa de început
; T2 pe nivelul de prioritate 2
IRUN 2 ; Taskul T2 este trecut în starea READY

6 - 14
SETF FLG ; Macroinstrucţiunea SETF setează flagul
; FLG şi declară eveniment semnificativ, deci
; va da controlul planificatorului
EXIT ; Terminare normală a taskului T0 cu
; declarare de eveniment semnificativ
T1: mov si, OFFSET mesaj1
call AFIS ; Afişează mesajul mesaj1
WAIT FLG ; Macroinstrucţiunea WAIT blochează taskul
; T1 pe flagul FLG în aşteptarea pregătirii
; datelor de către taskul T2.
; Directiva salvează în stivă starea taskului
; T1, apoi transferă controlul planificatorului
; de taskuri.
mov bx, BUFT2 ; Încarcă BX cu datele de la adresa
; (BUFT2+1, BUFT2)
call PRELUCRARE ; PRELUCRARE este o subrutină externă
; destinată prelucrării datelor preluate din
; BUFT2
mov si, OFFSET mesaj2
call AFIS ; Afişează mesajul mesaj2
EXIT ; Terminare normală a taskului T1
T2: call GENERARE ; GENERARE este o subrutină externă
; destinată generării
mov BUFT2, bx ; unor date care vor fi depuse în BUFT2
mov si, OFFSET mesaj3
call AFIS ; Afişează mesajul mesaj3
CLEF FLG ; Macroinstrucţiunea CLEF resetează
; flagul FLG, semnalând astfel taskului T1 că
; datele sunt disponibile şi dă controlul
; planificatorului de taskuri
mov si, OFFSET mesaj4
call AFIS ; Afişează mesajul mesaj4
EXIT ; Terminare normală a taskului T2
mesaj1 db CR, LF, 'Task T1: Aştept date ...', $
mesaj2 db CR, LF, 'Task T1: Am preluat datele ...', $
mesaj3 db CR, LF, 'Task T2: Date disponibile ...', $
mesaj4 db CR, LF, 'Task T2: Exit ...', $
CR equ 0dh
LF equ 0ah
FLG equ 32
; Subrutina pentru afişare
AFIS: mov dl, [si]
cmp dl, '$'
jz FIN
inc si
mov ah, 2
int 21h
jmp AFIS
FIN: ret

6 - 15
end
Acest program funcţionează astfel: Taskul T1 intră în execuţie, afişează mesajul mesaj1 şi
găsind flagul FLG setat se blochează. În acest moment se dă controlul taskului T2 (deoarece
directiva ?WAIT declară eveniment semnificativ) care pregăteşte datele şi le depune în bufferul
BUFT2, afişează apoi mesajul mesaj3, după care, prin ?CLEF, resetează flagul FLG cu declarare
de eveniment semnificativ. Planificatorul analizează starea taskului T1 (mai prioritar) şi îl găseşte
blocat pe fagul FLG, dar întrucât acesta fusese şters în taskul T2, taskul T1 va fi trecut în
READY şi va primi controlul. Acesta va continua din punctul în care a fost întrerupt (blocat).
Astfel, T1 preia şi prelucrează datele, afişează apoi mesajul mesaj2 şi îşi încheie execuţia. Se dă
apoi controlul taskului T2 care afişează mesajul mesaj4 după care îşi încheie execuţia. Rezultă că
succesiunea mesajelor afişate pe ecran va fi:
Task T1: Aştept date ...
Task T2: Date disponibile ...
Task T1: Am preluat datele ...
Task T2: Exit ...

6.4. Modulul de gestiune a timpului – TIMEMS


Aşa cum se ştie, în conducerea proceselor variabila timp are unul dintre cele mai importante
roluri. Funcţionarea în timp real a sistemelor de conducere este legată de posibilitatea de a măsura
timpul astronomic, adică timpul scurs între 2 evenimente precum şi de existenţa unor semnale
care să marcheze intervale de timp de durată prestabilită. În cadrul EXECUTIVULUI realizat,
toate aceste facilităţi sunt înglobate în modulul de gestiune a timpului. Modulul posedă o zona
proprie de date care conţine:
• contoarele generale pentru fracţiunile de timp considerate şi anume:
- tacturi de ceas - a căror durată este funcţie de perioada ceasului de timp real a
echipamentului stabilită la programarea dispozitivului 8253, în modulul de gestiune a
întreruperilor;
- secunde;
- minute;
- ore;
- zile;
- luni;
- ani;
• cinci liste pentru aşteptare care sunt compuse din mai multe casete organizate pe
principiul "listelor înlănţuite", adică primul octet al fiecărei casete dintr-o listă indică partea LOW
a adresei de offset a următoarei casete din aceeaşi listă. Pentru a indica sfârşitul unei liste, ultima
casetă din fiecare listă va conţine codul 0FFh în locul adresei (datele sunt plasate în aceeaşi
pagină de memorie şi este imposibil ca o casetă să înceapă la o adresă cu partea LOW având
această valoare). Capetele celor 5 liste de aşteptare se păstrează în 5 locaţii speciale.
O casetă din aceste liste conţine 4 octeţi, iar numărul casetelor se defineşte la generarea
sistemului, o aceeaşi casetă putând trece în mod dinamic dintr-o listă în alta în timpul execuţiei
programului.
Cele 5 liste de aşteptare conţin:
- lista 1 - casete libere;
- lista 2 - casete aferente taskurilor în aşteptare pe tacturi de ceas;
- lista 3 - casete aferente taskurilor în aşteptare pe secunde;
- lista 4 - casete aferente taskurilor în aşteptare pe minute;
- lista 5 - casete aferente taskurilor în aşteptare pe ore.

6 - 16
Modul de organizare a zonei de date aferente modului de gestiune a timpului este prezentat
în Fig. 6.19.

La iniţializarea modulului, toate casetele sunt incluse în lista 1 (lista casetelor libere), listele
2-5 fiind goale. Introducerea unui task în mecanismul de reprogramare implică înscrierea unor
informaţii în prima caseta liberă şi trecerea acestei casete din lista de casete libere în lista de
aşteptare pe unitatea de măsură corespunzătoare. Structura şi conţinutul unei casete este
prezentată în Fig. 6.20.
Întreruperile sosite de la ceas produc actualizarea contoarelor. Atunci când un contor
general este incrementat, se face şi o baleiere a listei de aşteptare anexate, decrementând
contoarele locale incluse în casetele acestei liste. În momentul când un contor local al unei casete
ajunge la zero, este reîncărcat cu valoarea iniţială (valoarea de reprogramare) conţinută în octetul
următor al casetei, după care taskul al cărui număr este specificat în octetul 4 al casetei (Fig. 6.20)
este trecut în starea READY în mod "condiţionat". Astfel, dacă un task nu se termină în intervalul
de reprogramare specificat, se aşteaptă sfârşitul său logic, prin apelarea din task a directivei
?EXIT care îl va trece în substarea OPRIT. Reprogramarea execuţiei lui se va face la iniţializarea
primului interval de timp de după terminarea lui logică.
Diagramele de sincronizare ale taskurilor pe condiţii de timp oferite de acest modul sunt
prezentate în Fig.6.21.a (unde durata de execuţie a taskului este mai mică decât valoarea
intervalului de reprogramare) şi Fig.6.21.b (unde durata execuţiei taskului este mai mare decât
valoarea intervalului de reprogramare).

6 - 17
Precizăm că contoarele pentru timpul astronomic pot fi scrise şi citite de programele
utilizatorului.

Directivele modulului de gestiune a timpului


Modulul de gestiune a timpului, ca şi celelalte module ale EXECUTIVULUI, oferă o serie
de directive ce pot fi apelate în programele utilizatorului în vederea conducerii în timp real a
procesului. Dintre acestea menţionăm:

?TIMEINI
- Este o directivă de iniţializare a modulului;
- Nu necesită parametri;
- Pune pe zero contoarele generale ale timpului astronomic în afara contoarelor pentru zile
şi luni care sunt puse pe 1;
- Include în lista 1 (lista casetelor libere) toate casetele;
- Nu declară eveniment semnificativ.

?SETTIME / ?ISETTIME
- Aceste directive permit potrivirea ceasului astronomic;
- Structura lor este asemănătoare celei din Fig.6.5;
- Parametru: la apelul acestor directive, registrul SI trebuie să
conţină adresa unei zone din memorie unde se găsesc noile valori ale
contoarelor în ordinea: oră, minut, secundă, tact de ceas, zi, lună, an;
- Nu declară eveniment semnificativ.

?GETTIME / ?IGETTIME
- Directivele transferă din contoarele generale într-o zonă indicată
din memorie valorile timpului astronomic;
- Structura lor este asemănătoare celei din Fig.6.5;
- Parametru: la apelul acestor directive, registrul DI trebuie să
conţină adresa unei zone din memorie unde se vor depune valorile contoarelor interne;
- Nu declară eveniment semnificativ.

6 - 18
?EXC/?IEXC
• Sunt cele mai importante şi utile directive explicite ale acestui modul, realizând
reprogramarea execuţiei unui task la intervale de timp dorite;
• Parametri: la apelul acestor directive, următoarele registre vor conţine:
(AL) = nivelul de prioritate al taskului (numărul taskului);
(BL) = valoarea intervalului de timp de reprogramare;
(CL) = <mod><unitate de măsură>, cu următoarea asamblare:
C7 = bitul de mod 0 mod sincronizat

1 mod nesincronizat
C6 - C2 = 0
C1, C0 = unitate de măsură:
00 = tacturi de ceas
01 = secunde
10 = minute
11 = ore
Modul sincronizat presupune că prima cerere de intrare în execuţie a taskului are loc ca şi
când reprogramarea sa ar fi fost făcută în momentul trecerii prin zero a contorului general aferent
unităţii de măsură specificate, după care intervalele de timp vor fi măsurate normal. Calculul
primei valori de reprogramare în modul sincronizat se realizează astfel:
- se citeşte valoarea curentă a contorului general aferent unităţii de măsură specificate;
- se compară această valoare cu valoarea de reprogramare (plasată în registrul BL);
- dacă valoarea curentă a contorului general este mai mică decât valoarea de reprogramare,
se face diferenţa dintre valoarea de reprogramare şi cea curentă, iar această diferenţă se înscrie în
locaţia a doua a casetei;
- dacă valoarea curentă este mai mare decât valoarea de reprogramare, se adună valoarea de
reprogramare cu ea însăşi de atâtea ori până devine strict mai mare decât valoarea curentă, se face
apoi diferenţa între valoarea astfel obţinută şi valoarea curentă şi se înscrie această diferenţă în
locaţia a doua a casetei.
Se observă că, în ambele situaţii, iniţial, în casetă se înscrie diferenţa dintre valoarea de
reprogramare şi valoarea curentă, modulo valoarea de reprogramare. În modul acesta,
reprogramarea taskurilor în mod sincronizat presupune alocarea aceleiaşi origini de timp tuturor
valorilor de reprogramare aferente unei unităţi de măsură.
Modul nesincronizat presupune începerea măsurării intervalului de timp de reprogramare
din momentul apelării directivei;
• Dacă toate casetele sunt ocupate, se poziţioneaza bitul CF pe 1 (CF = 1), ceea ce specifică
faptul că directiva nu s-a executat; altfel CF = 0;
• Directivele nu declară eveniment semnificativ;
• Structura acestor directive este asemănătoare celei din Fig. 6.5.
Exemplu: Să presupunem că se doreşte reprogramarea unui task în modul sincronizat, la un
interval de 5 sec. (Fig. 6.22.a)

6 - 19
Dacă valoarea contorului general pentru secunde este (în momentul apelului directivei)
egală cu 3 secunde, se va înscrie în locaţia a 2-a casetei valoarea 5 - 3 = 2, deci prima execuţie a
taskului va avea loc peste 2 secunde, deci ca şi cum reprogramarea cu 5 secunde ar fi avut loc
când contorul general secunde era zero.
Dacă valoarea contorului general este, de exemplu, egală cu 21, atunci se însumează
intervalul de reprogramare cu el însuşi până la prima valoarea mai mare decât 21, adică 25. Apoi
din această valoare se scade 21 şi se înscrie (25 - 21 = 4) în locaţia a 2-a casetei. Taskul va intra
deci în execuţie peste 4 secunde. În ambele exemple se observă că taskul va fi lansat în execuţie
la valori multiplu de 5 ale contorului general.
Dacă directiva se apelează în mod NESINCRONIZAT cu valoarea de reprogramare 5, iar
contorul general secunde, în momentul apelului directivei, era la 3 secunde, taskul va fi lansat în
execuţie la următoarele valori ale contorului general 8, 13, 18, 23, ... (Fig. 6.22.b).
În concluzie, Fig. 6.22 prezintă momentele de intrare în executie ale unui task reprogramat
a se executa la fiecare 5 secunde, apelul directivei ?EXC având loc când contorul general secunde
are valoarea 3, atât în varianta sincronizată cât şi în cea nesincronizată.
Structura directivei ?IEXC este prezentată în Fig.6.23.

6 - 20
?CAN / ?ICAN
- Directive explicite care anulează toate reprogramarile unui task (un task poate aparea în
mai multe liste);
- Parametru: la apelul acestor directive, registrul AL trebuie să conţină nivelul de prioritate
al taskului ce trebuie scos din listele de reprogramare;
- Directivele caută numărul taskului (menţionat ca parametru al directivelor) în toate
casetele celor 4 liste de aşteptare şi, în caz că îl găsesc, trec caseta respectivă în lista cu casete
libere;
- Structura celor 2 directive este asemănătoare celei din Fig.6.5;
- Nu declară eveniment semnificativ;
- Organizarea directivei ?ICAN este prezentată în Fig. 6.24.

6 - 21
?TINTR
- Este adresa de intrare a subrutinei de tratare a întreruperii de la ceas (după tratarea primară
care are loc în modulul de gestiune a întreruperilor);
- Salvează starea programului întrerupt (cu ?MONI);
- Produce incrementarea contoarelor generale ale ceasului de timp astronomic şi, după
incrementarea fiecărui contor, parcurge, prin intermediul unei subrutine - CRUN - (inclusă în
această subrutină de tratare a întreruperii), lista de aşteptare anexată, decrementând contoarele
locale (în afara contoarelor corespunzătoare zilelor, lunilor şi anilor);
- Dacă un contor local devine zero, subrutina CRUN îl reiniţializează şi lansează o directiva
?IRUN condiţionat, având ca parametru numărul taskului specificat;
- Dă controlul planificatorului de taskuri (declară eveniment semnificativ);
- Modul de organizare al subrutinei ?TINTR este prezentat în Fig. 6.25, iar în Fig. 6.26 este
prezentată structura subrutinei CRUN.

6 - 22
6 - 23
6 - 24
specificá segmente). Se recomandá pentru programe mici. Un dezavantaj
important íl reprezintá faptul cá nu conþin informaþii despre programul
LUCRAREA NR. 1 sursá ßi variabilele simbolice necesare depanatorului simbolic CV;
Descrierea pachetului de programe MASM (I) cod pentru ROM - Asamblorul poate fi utilizat pentru generarea
codului care este ínscris ín memorii ROM programabile. De obicei acesta
Scopul lucrárii este un format binar;
Lucrarea urmáreste familiarizarea studenþilor cu mediul de unitáþi de dispozitiv - Controleazá activitáþile de I/E pentru
dezvoltare a programelor scrise ín limbaj de asamblare, pus la dispoziþie unitáþile hardware de I/E.
de cátre macroasamblorul MASM, versiunea 5.00 (sau TASM, versiunea
3.2). Se prezintá, pe scurt, componentele pachetului de programe MASM Dezvoltarea programelor ín limbaj de asamblare
(TASM) ßi procedura generalá de lucru cu acesta.
Pentru a facilita dezvoltarea programelor ín limbaj de asamblare,
Chestiuni teoretice macroasamblorul MASM (TASM) oferá o serie de pseudoinstrucþiuni
sau directive ßi anume:
Introducere 1. Directive pentru definirea datelor:
Pachetul de programe MASM (TASM), pune la dispoziþia - directive pentru definirea constantelor simbolice: EQU;
utilizatorului toate instrumentele necesare pentru dezvoltarea - directive pentru definirea variabilelor: DB, DW, DD, RECORD,
programelor scrise ín limbaj de asamblare. Macroasamblorul MASM STRUC;
(TASM) produce module obiect relocabile din fißiere sursá scrise ín - directive pentru definirea etichetelor: LABEL.
limbaj de asamblare. Ín scopul obþinerii unor programe executabile sub 2. Directive pentru alocarea memoriei:
sistemul de operare DOS, aceste module obiect se pot "lega" íntre ele cu - directive pentru modificarea contorului de instrucþiuni: ORG;
programul LINK (TLINK). - directive pentru definirea segmentelor logice ßi adresabilitáþii
Pachetul de programe MASM (TASM) cuprinde: datelor: SEGMENT, ENDS, ASSUME, GROUP;
- macroasamblorul MASM (TASM); - directive pentru definirea procedurilor: PROC, ENDP.
- generatorul de referinþe íncrucißate CREF; 3. Directive pentru legarea modulelor de program: NAME, END,
- editorul de legáturi LINK (TLINK); PUBLIC, EXTRN, INCLUDE.
- bibliotecarul LIB; 4. Directive pentru controlul listárii: PAGE, TITLE, LIST etc.
- utilitarul MAKE; 5. Directive pentru asamblare conditionatá: IFxxxx, ENDIF.
- depanatorul simbolic Code View - CV (Turbo Debugger - TD). 6. Directive pentru definirea macroinstrucþiunilor: MACRO, ENDM.
Pentru depanare se poate folosi ßi depanatorul standard al
sistemului de operare DOS, DEBUG. Definirea ßi utilizarea segmentelor logice
Sunt posibile urmátoarele forme de fißiere executabile: Segmentul logic (numit pe scurt segment) este cea mai micá
EXE - Este formatul uzual pentru fißiere executabile sub sistemul unitate relocabilá a unui program. Relocabilitatea este proprietatea unui
de operare DOS. Programele executabile pástrate ín acest format pot program obiect de a putea fi linkeditat ßi fácut executabil prin plasarea sa
avea segmente multiple. Este formatul recomandat pentru programe de la orice adresá de ínceput ín memoria principalá.
dimensiuni mari. Extensia implicitá a acestor programe este .EXE;
COM - Programele ín acest format sunt limitate la un singur
segment, ele nedepáßind 64 Ko (exceptänd cazurile cänd nu se
Un segment fizic (numit ßi cadru) ín memoria lui I8086/I8088 . . . . . . . . . . Directive
constá dintr-un grup de locaþii adiacente de dimensiune ≤ 64 Ko, cu data_seg2 ENDS ; Sfärßitul segmentului data2
adresa absolutá de ínceput multiplu de 16. code_seg SEGMENT ; Ínceputul segmentului de cod code
La un moment dat microprocesorul poate sá facá acces la patru . . . . . . . . . . Directive
segmente logice: start:
- segmentul de cod - accesibil prin CS; . . . . . . . . . . Instrucþiuni
- segmentul de date, curent - accesibil prin DS; code_seg ENDS ; Sfärßitul segmentului code
- segmentul de date, suplimentar - accesibil prin ES; END start
- segmentul de stivá - accesibil prin SS. Avänd ín vedere ca íntr-un program pot sá existe mai multe
Aceste segmente logice pot sá corespundá la patru segmente fizice segmente este necesar ca asamblorul sa "ßtie" ín fiecare moment care
distincte, dar pot sá existe ßi coincidenþe ßi/sau suprapuneri parþiale íntre sunt cele patru segmente logice curente pentru a putea sá genereze corect
aceste segmente. codurile instrucþiunilor. De asemenea, asamblorul trebuie sá "ßtie" ce
Definirea unui segment se face sub forma: registre de segment se pot utiliza pentru a realiza accesul la datele
nume_segment SEGMENT referite. Aceastá informaþie este transmisá asamblorului cu ajutorul
Corpul segmentului pseudoinstrucþiunii ASSUME a cárei formá generalá este:
nume_segment ENDS ASSUME reg_segment : nume_segment [, . . . . . .]
unde nume_segment este numele asociat segmentului, care nu poate fi unde:
utilizat ín program cu altá semnificaþie. Acestui nume i se asociazá o reg_segment = CS | DS | SS | ES;
valoare ßi anume adresa de segment (16 biþi) corespunzátoare poziþiei nume_segment = numele segmentului logic sau numele unui grup
segmentului ín memorie. de segmente definit anterior printr-o directivá GROUP sau cuväntul
Structura unui segment de date este urmátoarea: cheie NOTHING care anuleazá selecþia precedentá a segmentului.
nume_segment SEGMENT Precizám cá nume_segment va fi adresat prin reg_segment
Directive de alocare memorie corespunzátor. Íncárcarea lui reg_segment cu adresa de bazá este sarcina
nume_segment ENDS programatorului.
Structura unui segment de cod este urmátoarea: Trebuie remarcat cá ASSUME este o pseudoinstrucþiune pentru
nume_segment SEGMENT care nu se genereazá cod, rolul ei fiind numai de a informa asamblorul de
Instrucþiuni ßi directive intenþia programatorului.
nume_segment ENDS Exemplu:
Directivele ßi instrucþiunile cuprinse íntre directivele SEGMENT ßi ASSUME CS : code_seg, DS : data_seg1, ES : data_seg2
ENDS se considerá cá fac parte din segmentul respectiv. Aceastá directivá va informa asamblorul cá adresa de segment a
Structura unui program format din douá segmente de date ßi un segmentului code_seg se va gási ín CS, adresa de segment a segmentului
segment de cod este urmátoarea: data_seg1 se va gási ín DS ßi adresa de segment a segmentului data_seg2
data_seg1 SEGMENT ; Ínceputul segmentului de date data1 se va gási ín ES. Asupra lui SS nu s-a facut nici o presupunere.
. . . . . . . . . . Directive Observaþie: Deoarece directiva ASSUME nu íncarcá adresele de
data_seg1 ENDS ; Sfärßitul segmentului data1 segment ín registrele de segment corespunzátoare, pentru toate registrele
de segment, cu excepþia lui CS, acest lucru se face ín mod explicit de
data_seg2 SEGMENT ; Ínceputul segmentului de date data2 cátre programator, ca ín exemplul urmátor:
code_seg SEGMENT Intr-un program, directiva .MODEL apare inaintea definirii
ASSUME CS : code_seg, DS : data_seg1, ES : data_seg2 oricarui segment. Ea este echivalenta cu definirea explicita a directivelor
start: mov ax, data_seg1 ; Íncárcarea registrului DS cu ASSUME, SEGMENT, GROUP necesare pentru definirea explicita a
mov ds, ax ; adresa de bazá a segmentului data_seg1 segmentelor corespunzatoare modelului ales.
mov ax, data_seg2 ; Íncárcarea registrului ES cu Observatie: Este indicata utilizarea modelului SMALL, deoarece
mov es, ax ; adresa de bazá a segmentului data_seg2 modelele MEDIUM, LARGE, HUGE conduc la executia lenta a
code_seg ENDS programului, iar COMPACT, LARGE, HUGE sunt dificil de tratat de
END start catre asamblor.
Incepind cu versiunea 5.00, macroasamblorul MASM (TASM),
permite utilizarea unor directive de segment simplificate. Implicit, Definirea simplificata a unui segment se face cu directivele:
directivele de segment simplificate, utilizeaza numele si conventiile de .CODE, .DATA, .DATA?, .FARDATA, .FARDATA?, .CONST,
segment din limbajul C. .STACK. Sintaxa acestor directive este:
Pentru folosirea directivelor de segment simplificate, se va declara .STACK [ marime ]
un model de memorie pentru program. Acesta specifica modul de alocare Permite definirea unui segment de stiva, unde parametrul marime
implicita a datelor si codului programului respectiv. Sunt posibile specifica numarul de octeti rezervati pentru stiva. Daca nu se specifica,
urmatoarele modele de memorie: se considera implicit o stiva de 1 Ko.
- Mic (SMALL) - Toate datele se incadreaza intr-un singur
segment de 64 Ko si toate portiunile de cod intr-un alt segment de 64 Ko. .CODE [ nume ]
Toate datele si portiunile de cod vor fi adresate prin intermediul unor Specifica inceputul unui segment de cod. Precizarea cimpului
referinte apropiate (NEAR); nume este necesara in cazul in care se doreste utilizarea mai multor
- Mediu (MEDIUM) - Toate datele se incadreaza intr-un singur segmente de cod in fisierul sursa, fiind permisa numai pentru modelele
segment de 64 Ko, iar portiunea de cod poate fi mai mare 64 Ko. (Datele ce pot utiliza mai multe segmente de cod (MEDIUM, LARGE, HUGE).
sunt referite ca NEAR, iar codul ca FAR);
.DATA
- Compact (COMPACT) - Codul se incadreaza intr-un singur
Specifica inceputul unui segment de date, accesibile prin referinta
segment de 64 Ko, iar portiunea de date poate fi mai mare 64 Ko. (Datele
apropiata.
sunt referite ca FAR, iar codul ca NEAR);
Observatie: Pentru a accesa locatiile de memorie din segmentul
- Mare (LARGE) - Atit datele, cit si portiunea de cod pot fi mai
definit prin .DATA, trebuie incarcat explicit registrul segment DS cu
mari 64 Ko. (Ambele sunt referite ca FAR);
simbolul @DATA. Aceasta se realizeaza cu urmatoarele doua
- Urias (HUGE) - Atit datele, cit si portiunea de cod pot fi mai
instructiuni:
mari 64 Ko. (Ambele sunt referite ca FAR); In plus, fata de modelul
mov ax, @DATA
LARGE, modelul HUGE permite siruri de date mai mari de 64 Ko.
mov ds, ax ; Registrul DS indica segmentul de date
Definirea modelului de memorie se face cu ajutorul directivei
; specificat prin .DATA
.MODEL ce are sintaxa:
.MODEL modelmemorie .DATA?
unde modelmemorie poate fi : SMALL, MEDIUM, COMPACT, Specifica definirea unui segment de date neinitializate, accesibile
LARGE sau HUGE. prin referinta apropiata.
.FARDATA Continutul variabilei mesaj de tip sir de caractere se afisaza pe
Specifica definirea unui segment de date , accesibile prin referinta ecran utilizind functia DOS cu codul 40h, printr-o intrerupere cu codul
indepartata (FAR). 21h. Sirurile pot fi de asemenea afisate pe ecran cu functia DOS cu codul
09h.
.FARDATA?
Functia DOS cu codul 4ch este utilizata pentru terminarea
Specifica definirea unui segment de date neinitializate, accesibile
programului si iesirea la sistem.
prin referinta indepartata.
.CONST Exemplu de program in format COM:
Specifica definirea unui segment de date constante. TITLE succes_com
text SEGMENT
Datele definite cu directivele .STACK, .DATA, .DATA? si ASSUME cs: text, ds: text, ss: text
.CONST sunt plasate intr-un grup denumit DGROUP. ORG 100h
Ordonarea segmentelor in fisierul executabil conform conventiei start: jmp inceput
DOS se face cu directiva .DOSSEG . Aceasta conventie este utilizata mesaj DB "Mult succes in utilizarea MASM !", 0dh, 0ah
implicit de compilatoarele C. lmesaj EQU $ - mesaj
inceput:mov bx, 1
Exemplu de program in format EXE: mov cx, lmesaj
TITLE succes_exe mov dx, OFFSET mesaj
DOSSEG mov ah, 40h
.MODEL SMALL int 21h
.STACK 100h mov ax, 4c00h
.DATA int 21h
mesaj DB "Mult succes in utilizarea MASM (TASM) !", 0dh, 0ah text ENDS
lmesaj EQU $ - mesaj ; Lungimea mesajului END start
.CODE
start: mov ax, @DATA ; Se initializeaza registrul DS Programele COM difera de programele EXE in urmatoarele
mov ds, ax ; cu adresa de baza a segmetului de date puncte:
mov bx, 1 1. Directiva .MODEL nu poate fi folosita la definirea segmentelor
mov cx, lmesaj implicite pentru fisiere COM. Cu toate acestea, definirea segmentelor nu
mov dx, OFFSET mesaj este dificila, intrucit este utilizat numai un singur segment;
mov ah, 40h 2. Toate registrele de segment sunt asignate unui aceluiasi segment
int 21h ; Apel functie DOS pentru afisarea unui sir prin utilizarea directivei ASSUME. Aceasta indica asamblorului
; cu lungimea precizata in registrul DX segmentul ce trebuie asociat cu fiecare registru de segment;
mov ax, 4c00h 3. Directiva ORG se utilizeaza pentru a indica inceperea
int 21h ; Iesire in sistem asamblarii de la octetul 256 (100h). Se creaza astfel un spatiu pentru
END start prefixul segmentului de program (PSP), care este automat incarcat in
memorie in momentul executiei;
4. Desi datele programului trebuie incluse in segmentul unic ele nu a. studiul raspunsului programului la diferite seturi de date de
vor fi executate. Se poate "sari" peste ele cu o instructiune jmp (ca in intrare;
exemplu), sau se pot plasa la sfirsit, dupa punctul in care programul b. studiul fisierelor sursa si listing;
revine in sistem. c. utilizarea programului CREF pentru crearea fisierului listing
Tinind cont de cele de mai sus, putem acum prezenta: cu referinte incrucisate;

Procedura generala de dezvoltare a programelor in limbaj de EDITARE TEXTE


asamblare nume.ASM (modul sursa)
nume.REF nume.CRF nume.LST
CREF ASAMBLARE
1. Se foloseste un editor de texte pentru crearea sau modificarea (fisier ( fisier ( MASM, TASM ) (fisier de listare)
modulelor sursa. Prin conventie, acestea au extensia implicita .ASM. text) referinte incrucisate )
nume.OBJ (modul obiect)
2. Se utilizeaza programul MASM (TASM) pentru asamblarea nume.LIB
LIB
fiecarui modul de program. Se pot utiliza optional fisiere de includere (fisier biblioteca)
(fisiere ce sunt incluse in modulul asamblat doar pe durata asamblarii).
LINKEDITARE Apeluri de proceduri
Daca apar erori dupa executarea acestui pas se revine la pasul 1. Pentru externe
fiecare fisier sursa MASM (TASM) creeaza: ( LINK, TLINK )
a. un fisier obiect cu extensia implicita .OBJ; nume.EXE (modul executabil)
DEBUG (DOS)
b. un fisier listing cu extensia implicita .LST; CODEVIEW - CV
c. un fisier de referinte incrucisate cu extensia implicita .CRF. TURBODEBUGGER - TD
Daca se doreste legarea de module scrise in asamblare, cu module EXE2BIN
Depanare (numai format EXE)
scrise intr-un limbaj de nivel inalt, acestea se vor compila in fisiere nume.COM
obiect.
3. Optional, se foloseste LIB pentru editarea legaturilor pentru mai EXECUTIE
(sub MS-DOS)
multe fisiere obiect plasate intr-un singur fisier biblioteca cu extensia
implicita .LIB. Acest lucru se intimpla cind se doreste legarea unor
fisiere obiect standard la mai multe programe. d. utilizarea depanatorului simbolic CV (TD) pentru depanare
4. Se foloseste LINK (TLINK) pentru a combina toate fisierele dinamica. Pentru depanare dinamica se poate utiliza si utilitarul DEBUG
obiect si modulele biblioteca ce formeaza un program in cadrul unui pus la dispozitie de sistemul de operare.
singur fisier executabil care are extensia implicita .EXE. Optional se Sugestiv, procedura de dezvoltare a unui program in limbaj de
poate crea si o harta de alocare a memoriei, cu extensia implicita .MAP. asamblare este prezentata in figura 1.1.
5. Pentru convertirea (daca este necesara) fisierelor executabile in Figura 1.1.
format binar, se foloseste comanda externa EXE2BIN. Aceasta operatie
este necesara pentru programele scrise in format COM (care vor avea Comenzi necesare dezvoltarii unui program
extensia .COM) si se va omite pentru programele scrise in format EXE.
6. Se depaneaza programul pentru depistarea erorilor de logica Sintaxa comenzii de asamblare este urmatoarea :
utilizind una din urmatoarele tehnici:
MASM [optiuni] sursa [,[obiect] [,[listing] [, [referinte_incrucisate]]]] [;]
Exemplu: Daca se doreste adaugarea unui alt fisier obiect, numit
Pentru fisierul sursa SUCCES.ASM, se poate introduce comanda: CERCURI.OBJ si in acelasi timp obtinerea unei listari a procedurilor din
MASM SUCCES ; biblioteca, se poate folosi comanda:
In urma executarii acestei comenzi, va rezulta fisierul LIB GRAF + CERCURI , GRAF.LST
SUCCES.OBJ. Pentru a se asambla acelasi fisier sursa si a se obtine o Editarea legaturilor se face cu ajutorul programului LINK, care
cantitate maxima de informatii necesare in vederea depanarii simbolice a are urmatoarea sintaxa:
acestuia, se va utiliza comanda:
LINK [optiuni] fisier_obiect [, [fisier_executabil] [, [fisier_mapare] [,
MASM /V /Z /ZI SUCCES ; [fisiere_biblioteca]]]] [;]
Exemplu:
Optiunile /V si /Z indica programului MASM sa transmita pe
Consideram ca dorim sa cream un fisier executabil din modulul
ecran in timpul asamblarii informatii suplimentare statistice si despre
unic SUCCES.OBJ, modulul sursa fiind scris in formatul EXE si
eventualele erori de asamblare. Optiunea /ZI indica programului MASM
asamblat cu optiunea /ZI. Programul este depanabil cu COCEVIEW si
sa includa in fisierul obiect informatiile necesare depanatorului simbolic
pentru a realiza acest lucru editarea legaturilor se face cu comanda:
CODEVIEW. Cu aceasta comanda, vor rezulta trei fisiere:
LINK /CO SUCCES ;
SUCCES.OBJ, SUCCES.LST si SUCCES.CRF.
Fisierul rezultat este SUCCES.EXE. El contine informatii simbolice si
Convertirea fisierelor de referinte incrucisate produse de MASM
referitoare la numarul liniilor sursa. Programul executabil obtinut se
din format binar in format text se face cu utilitarul CREF. Sintaxa
poate rula de la linia de comanda DOS sau de sub depanatorul simbolic
comenzii este:
CODEVIEW. Dupa depanarea programului se poate crea o versiune
CREF referinte_incrucisate [, listing_referinte_incrucisate ] [;] finala, fara informatii simbolice. Pentru aceasta se utilizeaza comanda:
Fisierul rezultat are extensia implicita .REF. LINK SUCCES ;
Exemplu: Pentru convertirea fisierului cu referinte incrucisate Aceasta linie de comanda se poate utiliza si cind fisierul sursa a
SUCCES.CRF in fisierul text corespunzator, se va folosi comanda: fost creat in format COM. Totusi, in acest caz, fisierul SUCCES.EXE
CREF SUCCES; rezultat nu este direct executabil. Pentru a putea fi rulat, se mai trece
in urma careia va rezulta fisierul SUCCES.REF. printr-o etapa suplimentara de convertire in format executabil COM.
Fisierele obiect create cu MASM pot fi convertite in fisiere Daca se doreste crearea unui program de dimensiuni mari, denumit
biblioteca cu ajutorul programului bibliotecar LIB. Sintaxa comenzii PICT.EXE, did doua fisiere obiect PICT1 si PICT2 si care apeleaza
este: proceduri externe din fisierul biblioteca GRAF.LIB descris mai sus, se va
LIB bibl_veche [/PAGESIZE: numar] [comenzi] [, [listing] [, [ utiliza comanda:
bibl_noua ]]] [;] LINK /CO PICT1 PICT2 , , , GRAF ;
Exemplu: Sa consideram ca MASM a fost utilizat pentru Este necesar ca fisierul GRAF.LIB sa se afle in directorul curent sau in
asamblarea a doua fisiere sursa ce contin proceduri grafice si ca aceste cel descris prin variabila de mediu LIB. In fisierul sursa, procedurile
proceduri trebuie apelate din citeva programe diferite. Fisierele obiect ce apelate se vor declara externe.
contin procedurile respective sunt PUNCTE.OBJ si LINII.OBJ. Convertirea in format executabil COM se face cu utilitarul
Acestea se vor grupa in fisierul GRAF.LIB, astfel: EXE2BIN, furnizat drept comanda externa de sistemul de operare. Linia
LIB GRAF + PUNCTE + LINII ; de comanda este:
EXE2BIN fisier_executabil [ fisier_binar ]
Exemplu: EXE2BIN SUCCES SUCCES.COM TASM [optiuni] sursa [, obiect] [, listing] [, referinte_incrucisate]
Trebuie retinut ca specificarea extensiei .COM este obligatorie,
in care optiunile cele mai utilizate au urmatoarea semnificatie:
implicita fiind extensia .BIN. De asemenea, fisierul .EXE convertit
/l - genereaza fisier de listare ;
trebuie generat din fisiere sursa si obiect in format COM.
/z - afisaza linia sursa cu mesaj de eroare;
Depanarea programelor se face uzual cu depanatorul simbolic
/ zi - aceeasi semnificatie ca la MASM.
CODEVIEW. Sintaxa liniei de comanda este:
CV [ optiuni ] fisier_executabil [ argumente ] Editarea legaturilor se face cu programul TLINK, care are
Exemplu: Pentru depanarea programului SUCCES.EXE generat urmatoarea sintaxa:
anterior se face comanda:
TLINK [optiuni] fisier_obiect [, fisier_executabil] [, fisier_mapare]
CV SUCCES
[fisiere_biblioteca]
Pentru a fi posibila depanarea simbolica, asamblarea trebuie sa fi
fost facuta cu optiunea /ZI si editarea legaturilor cu optiunea /CO. in care optiunile cele mai utilizate au urmatoarea semnificatie:
Exista anumite optiuni ale CODEVIEW utile in diverse situatii. De /v - ofera informatii simbolice complete pentru TD, numai
exemplu, programele grafice necesita intotdeauna utilizarea optiunii /S. daca asamblarea s-a efectuat cu optiunea /zi;
Astfel depanarea programului grafic CERCURI.COM se va face cu: /t - creaza fisier COM.
CV /V /I /S CERCURI.COM
Optiunile /V si /I specifica utlizarea anumitor facilitati specifice Observatie: Celelalte comenzi sunt identice cu cele oferite de
microcalculatoarelor compatibile IBM-PC. Extensia .COM trebuie pachetul MASM.
specificata explicit, pentru ca cea implicita este .EXE.
Daca se doreste ca depanarea programului sa se faca cu Modul de lucru
depanatorul DEBUG, se va proceda astfel:
a. Se lanseaza DEBUG in executie tastind in linia DOS de 1. Se vor studia directivele pentru definirea si utilizarea segmentelor
comanda numele DEBUG; logice.
b. Se introduce numele programului ce trebuie depanat, ca 2. Se vor edita, asambla si rula programele prezentate in format .EXE
parametru al comenzii N a depanatorului; si .COM.
3. Se va edita, asambla si rula o varianta a programului prezentat
c. Se incarca programul specificat la punctul anterior cu comanda
inlocuind directivele de segment simplificate cu directive nesimplificate
L a depanatorului;
(SEGMENT, ASSUME, ENDS).
d. Se ruleaza apoi programul de depanat sub controlul DEBUG,
4. Se vor obtine si analiza fisierele listing si de referinte incrucisate.
vizualizindu-se rezultatele partiale si valorile curente ale registrelor de
5. Se vor testa cit mai multe dintre optiunile de lucru ale
lucru in punctele critice ale programului.
macroasamblorului MASM (TASM).
Pentru pachetul de programe TASM, a carui utilizare este
6. Se vor rula sub CV sau TD programele realizate.
recomandata, comenzile necesare dezvoltarii unui program au o sintaxa
asemanatoare cu cea a comenzilor din MASM, deosebindu-se insa
Continutul referatului
anumite optiuni, astfel:
Sintaxa comenzii de asamblare este urmatoarea : 1. Listingul programului realizat la punctul 3 de la modul de lucru.
2. Observatiile si comentariile studentului.
Definirea constantelor simbolice
Pentru definirea constantelor se utilizeazá directiva EQU (EQUate)
LUCRAREA NR. 2 al cárei format este:
Descrierea pachetului de programe MASM (II) nume EQU operand
unde nume este numele ce se atribuie operandului operand care poate fi
Scopul lucrárii o constantá, un nume simbolic, o expresie sau un ßir. Constantele
Lucrarea urmáreste familiarizarea studenþilor cu mediul de numerice pot fi íntregi sau reale. Ín cazul constantelor íntregi,
dezvoltare a programelor scrise ín limbaj de asamblare, pus la dispoziþie reprezentarea se poate face ín baza 2, 8, 10 sau 16, indicarea bazei
de cátre macroasamblorul MASM, versiunea 5.00 (sau TASM, versiunea realizändu-se respectiv prin sufixele B, Q, D, H (sau literele mici
3.2). Se prezintá directivele macroasamblorului utilizate pentru definirea corespunzátoare). Dacá indicarea bazei lipseßte, atunci se considerá, ín
datelor, precum ßi exemple de folosire a acestora. mod implicit, cá baza este 10. Ín cazul constantelor alfanumerice, ßirurile
de caractere corespunzátoare se scriu íntre ghilimele sau íntre apostrofuri.
Chestiuni teoretice Pentru fiecare caracter dintr-un ßir alfanumeric de caractere, valoarea
corespunzátoare este codul ASCII al caracterului respectiv.
Directivele pentru definirea datelor
Exemple: ANA EQU 0c2h ;
La asamblare, directivele limbajului de asamblare I8086/I8088 nu ANY EQU ANA ;
produc cod obiect. Ele se adreseazá macroasamblorului, influenÇändu-i char EQU ' A' ; char are valoarea 2041h
modul de lucru. Din acest motiv, directivele se mai numesc ßi char1 EQU 'a125' ; char1 are valoarea 61313235h
pseudoinstrucÇiuni (pseudooperaÇii). Directivele pentru definirea datelor Este permisá ín continuare scrierea unor instrucÇiuni care sá foloseascá
se pot grupa astfel: aceste nume:
- directive pentru definirea constantelor simbolice: EQU; mov al, ANA
- directive pentru definirea variabilelor: DB, DW, DD, DQ, DT; and al, ANY
- directive pentru definirea etichetelor: LABEL; mov cx, char
- directivele STRUC si RECORD. Pentru a forþa un operand sá fie considerat un ßir text ßi nu o
expresie, se utilizeazá operatorul de text literal < >.
Tipuri de date Exemplul 1a: var1 EQU 1 ;
Macroasamblorul MASM, respectiv TASM opereazá cu var2 EQU < var1 + 2 > ; Atribuie etichetei var2
urmátoarele tipuri de date: ; ßirul text "var1 + 2"
Exemplul 1b: var1 EQU 1 ;
Tip date Numár octeti var2 EQU var1 + 2 ; Atribuie etichetei var2
BYTE 1 ; valoarea 3 ( 1 + 2 = 3)
WORD 2 Observaþie: Numele utilizate ín EQU nu pot fi redefinite.
DWORD 4
QWORD 8 Definirea ßi ínitializarea variabilelor
TBYTE 10 Directivele utilizate sunt: DB (Define Byte), DW (Define Word),
De asemenea se utilizeazá NEAR pentru etichete din segmentul curent ßi DD (Define Doubleword), DQ (Define Quadword), DT (Define
FAR pentru etichete din alte segmente.
Tenbytes). La asamblare, pentru o variabilá, se alocá una sau mai multe Operatorul DUP indicá generarea repetatá de factor ori a listei de
locaÇii de memorie conform tipului variabilei. Ín cadrul definirii se poate operanzi ce apare íntre parantezele de dupá cuväntul DUP.
face, ín mod facultativ, ßi iniÇializarea variabilei. Formatul general al Precizám cá datele de tip adresá ce pot fi definite ßi prin directivele
directivei este: DW (adresá relativa) ßi DD (pointer) sunt memorate inversat, adicá la
 lista operanzi  adresa mai mica este memorat octetul mai putin semnificativ al valorii,
[nume_var] {DB | DW | DD | DQ | DT}   [; respectiv la adresa mai mare se memoreazá octetul mai semnificativ al
 factor DUP (lista operanzi)  valorii.
comentariu]
Exemple:
unde: Nume_var Dir Listá operanzi Rezultat (ín cod hexazecimal)
nume_var este numele prin care pot fi referite datele definite.
Acest nume are asociat un tip si o valoare. Tipul rezultá din tipul datei, DATA_B DB 10, 5, 13h, -5, 'A' ; 0A 05 13 FB 41
iar valoarea este adresa la care se va gási ín memorie, ín timpul execuÇiei DATA_W DW 100, 100h, -5, 'AB' ; 64 00 00 01 FB FF 42 41
programului, primul octet rezervat pentru data etichetatá cu numele DATA_D DD 5*20, 0FCFBh, 'DCBA' ; 64 00 00 00 FB FC
respectiv. Un nume este format din maximum 32 caractere alfanumerice, ; 00 00 41 42 43 44
din care primul caracter este o literá sau un caracter special (_, ?, $, @, .). DB 200 DUP (1) ; Defineßte 200 octeti initializati cu 1
Limbajul de asamblare utilizeazá nume rezervate care nu pot fi utilizate DB 50 DUP (1, 0) ; Defineßte 100 octeti initializati
ca etichete. Aceste nume rezervate sunt: mnemonicele instructiunilor ßi ; cu 1,0,1,0, . . .
pseudoinstructiunilor, numele operatorilor logici, numele registrelor ßi ARRAY1 DB 2 DUP (0, 1, 2, ?) ; Defineßte 8 octeti initializati
caracterele $ ßi ?. ; cu 0,1,2,_,0,1,2,_
listá operanzi reprezintá lista unor constante, simboluri sau Rezervarea de spatiu fárá initializare se face cu caracterul ?, ca ín
expresii separate prin virgulá, cu ale cáror valori se vor initializa zonele exemplul:
de date rezervate pentru declaratia respectivá. ALFA DB ?, ?, ? ; Se rezervá 3 octeti íncepänd cu adresa ALFA
factor este un numár care indicá de cíte ori se repetá lista de ARRAY2 DB 100 DUP (?) ; Se rezervá 100 octeti neinitializati
operanzi care urmeazá ín paranteze. ; íncepänd cu adresa ARRAY2
Expresiile utilizate pentru initializarea datelor sunt expresii care BETA DW ?, 0AAh ;
pot fi evaluate ín momentul asamblárii programului. Acestea utilizeazá
ca operanzi constante numerice, alfanumerice ßi nume pentru care Operatorul DUP poate fi utilizat ßi imbricat ca ín exemplele:
macroasamblorul asociazá valori (nume de date, etichete de instructiuni, DB 2 DUP (3 DUP (1)) ; Defineßte 6 octeti initializati cu 1
nume de segmente etc.). Ín particular, drept operand poate fi folosit ßi ARRAY3 DB 2 DUP (0, 2 DUP (1,2), 0, 3) ; Se va genera de 2 ori
caracterul ? care indicá faptul cá zona de date corespunzátoare este ; secventa 0,1,2,1,2,0,3
rezervatá, dar nu ßi initializatá. Ín expresii se pot utiliza operatori
aritmetici (+, -, *, /, MOD), operatori de deplasare (SHR, SHL), operatori Directiva LABEL
logici (NOT, AND, OR, XOR), operatori relationali (EQ, NE, LT, LE, Directiva LABEL se utilizeazá ímpreuná cu variabile sau
GT, GE cu precizarea cá adevárat se reprezintá ca 1, iar fals ca 0), ímpreuná cu etichete de instructiuni. Forma de utilizare a directivei
operatori de conversie de tip (PTR, SHORT, LOW, HIGH, SEG, LABEL este:
OFFSET, LENGTH, SIZE, MASK). nune LABEL tip
a) Utilizarea directivei LABEL pentru variabile Exemplu: ETICH1: mov ax, dx ;
Ín acest caz, nume este numele variabilei, iar tip reprezintá tipul • Prin definirea cu LABEL, caz ín care atributul de distantá al etichetei
acesteia: BYTE, WORD, DWORD etc. Prin utilizarea directivei LABEL poate fi NEAR sau FAR (specificat prin parametrul tip).
se dá posibilitatea accesárii unei aceleiaßi variabile utilizänd douá tipuri Exemplu: ENTRY_POINT LABEL FAR
diferite de definire a acesteia. ETICH2: mov ax, var [bx]
Exemplul 1: BYTE_ARRAY LABEL BYTE Accesul la aceastá instructiune se poate face din alte segmente prin
WORD_ARRAY DW 50 DUP (?) numele ENTRY_POINT, sau din acelaßi segment prin numele ETICH2.
Efectul acestei secvente constá ín asocierea celor douá simboluri
BYTE_ARRAY ßi WORD_ARRAY cu adresa primului octet din cei 100 Operatori pentru atribute
de octeti generati de a doua instructiune. Referirile ulterioare la tabloul
de date specificat se pot face fie prin numele BYTE_ARRAY, Operatori pentru modificarea atributelor
consideränd tabloul ca fiind format din octeti, fie prin WORD_ARRAY, Operatorul PTR schimbá temporar tipul expresiei (care poate fi o
consideränd tabloul ca fiind format din cuvinte: variabilá sau o etichetá) de la tipul initial la tip. Forma de utilizare este:
add al, BYTE_ARRAY[99] ; Aduná la AL al 100-lea octet tip PTR expresie
add bx, WORD_ARRAY [49]; Aduná la BX al 50-lea cuvänt unde tip poate fi unul din urmátoarele nume sau valori:
inc BYTE_ARRAY ; Incrementare pe octet Nume Valoare
inc WORD_ARRAY ; Incrementare pe cuvänt BYTE 1
Exemplul 2: Se considerá urmatoarele declaratii: WORD 2
a1w LABELWORD DWORD 4
a1b DB 100 DUP (?) QWORD 8
Instructiunea: TBYTE 10
mov ax, a1w[6] NEAR 0FFFFh
este echivalentá cu: FAR 0FFFEh
mov ax, a1w + 6 Exemple:
iar instructiunea: inc BYTE PTR [bx] ; Incrementeazá octetul cu adresa ds× 16 + bx
mov bl, a1b[6] mov WORD PTR [si], 1234h ; Íncarcá cuväntul de la adresa ds×
este echivalentá cu: ; 16+si cu constanta1234h
mov bl, a1b + 6. jmp DWORD PTR [bx] ; Salt intersegment la adresa datá de
Observatie: O altá solutie pentru a adresa o datá cu alt tip decät a ; pointerul cu patru octeti a cárui valoare
fost declaratá initial constá ín utilizarea operatorului de conversie PTR. ; este ds× 16+bx
a) Utilizarea directivei LABEL pentru etichete Operatori generatori de valori
Etichetele instructiunilor pot fi definite ín douá moduri: Returneazá valorile de atribut ale operanzilor care urmeazá dupá
• Prin simpla scriere a numelui etichetei, urmatá de caracterul ":", ín fata ei, astfel:
mnemonicei instructiunii. Ín acest caz eticheta are implicit atributul SEG expresie
NEAR, adicá referirile ín alte instructiuni la aceastá etichetá se pot face
numai ín cadrul aceluiaßi segment logic.
Returneaza valoarea de segment a parametrului expresie (eticheta, salfa ENDS
variabila, nume de segment etc.) Instructiunea:
OFFSET expresie Utiliz1 salfa < >
Returneaza valoarea de offset a parametrului expresie (eticheta, rezervá íncepänd de la adresa Utiliz1 9 octeti cu valorile precizate ín
variabila, nume de segment etc.) definitia structurii.
TYPE expresie Instructiunea:
Aplicat unei variabile, TYPE returneazá nunárul de octeti (dimensiunea Utiliz2 salfa < , 44h, 55h >
tipului expresiei: 1 pentru BYTE, 2 pentru WORD etc.); aplicat unei modificá valorile initiale ale cämpurilor doi si trei.
etichete, TYPE returneazá valorile NEAR sau FAR. Definirea unui tablou se face conform exemplului:
LENGTH variabilá TABLOU salfa 10 DUP ( < >)
Returneazá nunárul de elemente (BYTE, WORD, DWORD, QWORD, ce are ca efect copierea de 10 ori a structurii salfa, fará modificarea
TBYTE) ocupate de variabilá. valorilor initiale ale cämpurilor din structura.
Considerám acum urmatoarea declaratie de structura:
SIZE variabilá
alfa STRUC
Returneazá nunárul de octeti ocupat de variabilá.
c1 DW 1234
SIZE variabilá = (LENGTH variabilá) * (TYPE variabilá)
c2 DB 5 DUP ('abc')
alfa ENDS
Directiva STRUC Secventa:
Defineste o structura de date. Structura este o multime de date de utiliz alfa <>
tip eterogen (BYTE, WORD, DWORD etc.). Declaratia de definire a mov al, BYTE PTR utiliz.c1
unei structuri este: are ca efect íncárcarea ín registrul AL a primului octet al cuväntului din
nume_struc STRUC cimpul c1.
[nume_cimp] {DB | DW | DD | DQ | DT } {valoare_initiala | ?} [; Secventa:
comentariu] mov bx, OFFSET utiliz
nume_struc ENDS mov ax, WORD PTR [bx].c2
Tipul unei structuri este dat de numarul de octeti necesari pentru are ca efect íncárcarea ín registrul AX a primilor doi octeti din cimpul c2.
memorarea elementelor structurii.
Directiva STRUC prin ea insasi nu creazá date, ci defineste un tip Ínregistrári de biti. Directiva RECORD
de date. Pentru a crea date de acest tip se utilizeaza sintaxa: Ínregistrárile sunt date pe 8 sau 16 biti, compuse din cämpuri de
[nume] nume_struc < [val_init, , , ] > biti de lungimi variabile, cu semnificatii diferitre. Ele se utilizeaza pentru
unde nume este numele unei variabile tip structura. a obtine o reprezentare compactá a datelor cu numár mic de biti, deci
Exemplu: salfa STRUC realizeazá o ímpachetare a datelor. Definirea ínregistrárii precizeazá
unu DB ? numai structura (modelul) acesteia prin numele asociate cámpurilor ßi
doi DB 0 lungimile lor. Definirea ínregistrárii, ca ßi ín cazul structurilor, nu alocá
trei DB 5 memorie. Dupá definire, numele ínregistrárii devine directivá ßi poate fi
patru DW doi utilizat ín scrierea programelor cu scopul alocárii de memorie pentru
cinci DD doi datele de tip ínregistrare.
Formatul declaratiei de definire a unei ínregistrári este:
unde:
nume_ínregistrare RECORD nume_cämp : lungime [ = initializare]
- variabilá reprezintá un nume optional pentru primul octet sau
[, . . . ]
cuvänt (depinzänd de tipul ínregistrárii) al zonei de memorie alocate;
unde:
- nume_ínregistrare este cel folosit ín definitia ínregistrárii;
- numele cämpurilor nume_cämp sunt unice;
- < [ expresie ] [ , . . . ] > specificá o listá, posibil vidá, de
- lungime poate fi o constantá sau o expresie care se evalueazá la
initializári ale cämpurilor sau modificári optionale (reinitializári ale
o constantá íntreagá care apartine multimii {1, 2, . . . , 16} ßi specificá
cämpurilor initializate). Cämpurile care nu sunt mentionate ín listá rámän
numárul de biti (lumgimea) ai cämpului; suma lungimilor tuturor
cu valorile implicite definite initial. (De exemplu, pentru ínregistrarea
cämpurilor trebuie sá fie mai micá sau egalá cu 16;
definitá anterior, < > retine valorile din definitie; < 3 > modificá valoarea
- initializare (optionalá) serveßte ca valoare implicitá a
primului cämp ín 3; < , 5 > lasá primului cämp valoarea din definitie,
cämpului. Valoarea íntreagá a cämpului initializare trebuie sá se poatá fixeazá valoarea 5 pentru al doilea cämp, iar cel de-al treilea cämp
reprezenta cu numárul de biti ai cämpului respectiv. rámäne nemodificat etc.);
- [ , . . . ] indicá repetarea optionalá a lui nume_cämp : lungime - expresie este o expresie constantá sau caracterul ? (pentru valori
[ = initializare]. neinitializate);
- factor DUP ( < [ expresie ] [ , . . . ] > ), unde factor este un
MOD REG RM numár, specificá numárul de copii ale ínregistrárii care trebuie alocate.
Exemple:
a) Considerám urmátoarea declaratie:
xa1 xa2 xa3
Exemple:
a) OCTET2 RECORD MOD : 2, REG : 3, RM : 3 0 0 0 1 1 1 1 1 1 1 0 0 0 0 1 1
Aceastá declaratie permite ímpártirea unui octet ín 3 cämpuri cu numele 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
MOD cu lungimea de 2 biti, REG cu lungimea de 3 biti ßi RM cu
ralfa RECORD xa1 : 3, xa2 : 6, xa3 : 7
lungimea de 3 biti, ca in figura 2.1.
Fie urmátorul exemplu de utilizare a acestei ínregistrári:
Figura 2.1.
Utiliz3 ralfa 10 DUP ( < 0, 63, 67 > )
b) OCTET2 RECORD MOD : 2 = 2, REG : 3 = 3, RM : 3 = 3 Aceastá instructiune alocá memorie pentru 10× 2 octeti, fiecare pereche
Se defineßte o ínregistrare cu aceeaßi structurá ca mai sus, dar cu de octeti fiind initializatá cu valoarea 63*2**7 + 67, figura 2.2.
precizarea valorilor initiale ale cämpurilor. Figura 2.2
Dupá definire, numele ínregistrárii nume_ínregistrare poate fi b) Fie definitia:
utilizat ca directivá pentru alocarea de memorie ßi initializarea rbeta RECORD xb1 : 8 = 'A', xb2 : 4 = 3, xb3 : 4
cämpurilor ínregistrárilor. Declaratia de alocare de memorie ßi initializare ín care s-au definit 3 cämpuri:
(reinitializare) a cämpurilor unei ínregistrári este: xb1 (8 biti) cu valoarea initiala 'A' = 41h
xb2 (4 biti) cu valoarea initiala 3
 < [ expresie ] [, . . . ] >  xb3 (4 biti) neinitializat
[variabilá] nume_ínregistrare  
 factor DUP ( < [expresie ] [, . . . ] >)  Utilizarea ínregistrárii rbeta sub forma:
Utiliz4 rbeta < , 3, 15 > shr ax, cl
conduce la alocarea ín memorie a unei perachi de octeti care contin ßi are ca efect selectarea cämpului x2 din cei 16 biti care formeazá
respectiv valorile 'A' si 3*2**4 + 15. ínregistrarea, urmatá de aducerea bitilor care formeazá acest cämp pe
Numele fiecárui cämp din ínregistrare are asociatá o valoare egalá pozitiile cele mai putin semnificative.
cu numárul de deplasári la dreapta necesare pentru a se aduce cämpul
respectiv ín bitii cei mai putin semnificativi din octetul sau perechea de Exemple de programe ce utilizeazá directivele de definite a datelor
octeti ce formeazá ínregistrarea. Programul 2.1.
Numele cämpurilor unei ínregistrári de biti pot apare ín title af_EQU
instructiuni singure, sau ímpreuná cu operatorii WIDTH sau MASK. dosseg
Expresia, .model small
WIDTH nume_cämp .stack 100h
are ca valoare numárul de biti din cämpul respectiv, iar expresia : .data
MASK nume_cämp equ_sir EQU " Acest text se afla intr-o directiva EQU $ "
are ca valoare masca necesará pentru selecterea cämpului respectiv. mesaj DB equ_sir
De exemplu, consideränd declaratia ínregistrárii rbeta, valorile .code
diferitelor expresii prezentate anterior sunt: ORG 100h
start: mov ax, @data
nume_cämp Valoare asociatá WIDTH MASK Valoare initiala mov ds, ax ; Incarca DS cu adresa de baza a
xb1 0008 0008 FF00 4100 ; segmentului de date
xb2 0004 0004 00F0 0030 lea dx, mesaj ; Incarca DX cu offsetul lui mesaj
xb3 0000 0004 000F 0000 mov ah, 9
int 21h ; Apel DOS pentru afisarea unui sir terminat cu $
Referirile la elementele unei ínregistrári se fac utilizänd expresii mov ax, 4c00h ; Iesire in sistem
care contin numele cämpurilor ßi/sau operatorii MASK ßi WIDTH. Sá int 21h
considerám, de exemplu, urmátoarea declaratie de ínregistrare: end start
beta RECORD x1 : 3, x2 : 6, x3 : 7
ßi o utilizare a acesteia de forma: Programul 2.2.
utiliz_beta beta < 2, 5, 67 > title Definire si initializare date
Fie secventa de instructiuni: ;Se prezinta exemple de definire si initializare a datelor
mov ax, utiliz_beta CR EQU 0dh ; Retur cursor
and ax, MASK x2 ; Se selecteazá bitii din cämpul x2 LF EQU 0ah ; Linie noua
mov cl, WIDTH x3 ; Incarcá CL cu lungimea cämpului x3 far_label LABEL FAR
shr ax, cl ; Deplasare dreapta a registrului AX cu (CL) biti code SEGMENT ; Numele segmentului de cod
Aceasta este echivalentá cu urmátoarea secventa de instructiuni: ASSUME cs: code
mov ax, utiliz_beta ASSUME ds: t_data
and ax, 0001111110000000b ASSUME ss: stiva ; Asignarea segmentelor
mov cl, 7 exit PROC NEAR ; Se defineste o procedura
mov ah, 4ch ; Revenire in MS DOS end START ; Sfirsitul programului
int 21h Programul 2.3.
exit ENDP ; Sfirsitul procedurii title INREG.ASM
near_label LABEL NEAR ; INREG realizeaza operatii cu structuri de date de tip inregistrari de biti
; Modulul principal incepe de la locatia START ; (RECORD)
; Initializare registre segment ASSUME cs:INREG, ds:INREG, ss:STIVA
START: mov ax, t_data ; Adresa lui t_data in AX STIVA SEGMENT STACK
mov ds, ax ; Se initializeaza reg. DS cu t_data DB 100 DUP (0)
mov ax, stiva ; Adresa lui stack in ax STIVA ENDS
mov ss, ax ; Se initializeaza reg. SS cu stiva INREG SEGMENT
mov sp, OFFSET s_data ; Stabileste SP START:
call NEAR PTR exit ; Revenire in MS DOS mov ax, cs
code ENDS ; Sfirsitul segmentului de cod mov ds, ax ; Se incarca registrul DS cu adresa de
; Segmentul de date ; baza a segmentului de date
t_data SEGMENT mov ax, STIVA
; Definire variabile cu constante mov ss, ax
doctet1 DB 55h ; Constanta hexazecimala 55 mov si, 2
doctet2 DB 101101b ; Constanta binara 101101 mov ax, TAB[si] ; Incarca AX cu adresa celui de-al treilea
doctet3 DB 'sir test' ; Caractere ASCII incluse intre ghilimele ; cuvint din TAB
doctet4 DB 077q ; Constanta octala 77 mov dx, ax ; DX = ffffh
; Definire variabile cu tipuri mov cl, TIP ; Incarca CL cu valoarea cimpului TIP
cuvint DW 0ffffh ; 2 octeti ; (0Dh = 13 = 6 + 7)
cuv_dub DD 0ffffffffh ; 4 octeti shr ax, cl ; Deplaseaza dreapta pe AX cu TIP biti
dqword DQ ? ; 8 octeti neinitializati mov bx, ax ; BX = 0007h
dtword DT ? ;10 octeti neinitializati and dx, MASK COD ; MASK COD = 1f80h
; Definire variabile cu etichete mov si,1
ind_near DW near_label ; Indicator al unei etichete and TAB[si], NOT MASK TIP ; MASK TIP = e000h
; definite ca near mov si,0
ind_far DD far_label ; Indicator al unei etichete and TAB[si], NOT MASK COD
; definite ca far and TAB[si], NOT MASK ADR ; MASK ADR = 007fh
zona DB 10 DUP (0) ; 10 octeti initializati cu 0 or TAB[si], MASK COD
t_data ENDS ; Sfirsitul segmentului de date mov ax, 5
; Segmentul de stiva mov cl, TIP
stiva SEGMENT STACK shl ax, cl
DB 256 dup(?) ; Defineste marimea stivei (256 octeti) and TAB[si], NOT MASK TIP
s_data EQU $ ; Defineste virful stivei or TAB[si], ax
stiva ENDS ; Sfirsitul segmentului de stiva mov ax, 4c00h ; Iesire in sistem
int 21h mov cx, ax
TAB DW 3 DUP (0ffffh) shr bx, cl ; Deplaseaza dreapta pe AX cu (TIP) biti
rrr RECORD TIP : 3, COD : 6, ADR : 7 mov bx, TAB ; BX = ffffh
INREG ENDS mov cl, WIDTH COD ; WIDTH COD = 6
END START shr bx, cl ; BX = 03ffh
Programul 2.4. mov si, 1
title INREG1.ASM and TAB[si], NOT MASK TIP ;
; INREG1 realizeaza operatii cu structuri de date de tip inregistrari de mov si,0
; biti (RECORD) and TAB[si], NOT MASK COD ;
; and TAB[si], NOT MASK ADR ;
ASSUME cs:INREG, ds:DATA, ss:STIVA or TAB[si], MASK COD ;
DATA SEGMENT mov ax, 5
TAB DW 3 DUP (0ffffh) mov dx, utiliz2_rrr ; Se incarca DX cu inregistrarea
rrr RECORD TIP:3=011b, COD:6=3, ADR:7=3 ; utiliz2_rrr (DX = 26c3h)
utiliz1_rrr rrr <3,7,0111b> ; Prima utilizare a inregistrarii rrr mov cl, COD ; CL = 7
utiliz2_rrr rrr <1,13,67> ; A doua utilizare a inregistrarii rrr and dx, MASK COD ; DX = 0680h
DATA ENDS shr dx, cl ; In DX va rezulta valoarea
STIVA SEGMENT STACK ; cimpului COD (COD = 13)
DB 100 DUP (0) mov cl, dl ; CL = 13
STIVA ENDS shl ax, cl ; AX = a000h
INREG SEGMENT and TAB[si], NOT MASK ADR ;
START: xor ax, TAB[si] ; AX = 5f80h
mov ax, DATA mov ax, 4c00h ; Iesire in sistem
mov ds, ax ; Se incarca registrul DS cu adresa de int 21h
; baza a segmentului de date INREG ENDS
mov ax, STIVA END START
mov ss, ax
mov si, 2
mov ax, TAB[si] ; Incarca AX cu adresa celui de-al Modul de lucru
; treilea cuvint din TAB: AX = ffffh
1. Se vor studia directivele pentru definirea si initializarea datelor.
mov bx, ax ; BX = ffffh
2. Se vor edita, asambla si rula cele patru programe prezentate.
mov dx, utiliz1_rrr ; Incarca DX cu inregistrarea
3. Se vor obtine si analiza fisierele listing si de referinte incrucisate.
; utiliz1_rrr (DX = = ffffh)
4. Se vor rula sub CV sau TD programele realizate in modul pas cu pas.
mov cl, TIP ; Incarca CL cu valoarea
; cimpului TIP (CL =13)
Continutul referatului
and dx, MASK TIP ; and (DX, e000h)
shr ax, cl ; Deplaseaza dreapta pe AX cu TIP biti 1. Listingurile programelor realizate.
2. Observatiile si comentariile studentului.
La lansarea programului DEBUG, registrele si indicatorii pentru
programul care se depaneaza sunt initializate cu urmatoarele valori:
LUCRAREA NR. 3 - registrele segment ( CS:, DS:, ES: si SS: ) sunt pozitionate la
inceputul memorei libere; adica primul segment dupa sfirsitul programului
Testarea ßi depanarea programelor utilizänd DEBUG.
programul DEBUG - registrul pointer de instructiuni (IP) este pozitionat la adresa
hexazecimala 0100H.
Scopul lucrárii - registrul SP este pozitionat la sfirsitul segmentului de stiva sau la
Lucrarea urmareßte familiarizarea studenþilor cu facilitáþile oferite de inceputul portiunii tranzitorii a programului incarcat.
programul de testare ßi depanare a programelor, ín format .EXE sau .COM, - restul registrelor (AX, BX, CX, DX, BP, SI si DI ) sunt initializate
oferit de DOS ßi denumit DEBUG. cu 0. Daca se apeleaza totusi programul DEBUG cu un specificator de
Programul DEBUG permite depistarea erorilor ßi eliminarea acestora fisier, registrul CX contine lungimea fisierului, in octeti. Daca fisierul este
din fißierele obiect executabile. DEBUG eliminá necesitatea reasamblarii mai mare de 64K, lungimea este continuta in registrele BX : CX.
unui program pentru a vedea efectul unor modificári minore ín cadrul - indicatorii sunt stersi.
acestuia. El permite modificarea conþinutului unui fißier sau a conþinutului
registrelor interne ale UCP ßi reexecutarea imediatá a programului pentru a 2. Comenzile DEBUG
verifica efectul schimbárilor fácute.
Urmatoarele informatii se aplica tuturor comenzilor DEBUG :
Toate comenzile DEBUG pot fi abandonate ín orice moment taständ
- o comanda este compusa dintr-o singura litera, in mod uzual urmata
Ctrl+C. Secvenþa Ctrl+S suspendá afißarea, permiþänd analiza valorilor
de unul sau mai multi parametri.
afißate. Apasarea oricárei taste diferite de Ctrl+C sau Ctrl+S reporneßte
- comenzile si parametrii pot fi introduse cu litere mari, cu litere mici
afißarea.
sau cu combinatii ale acestora.
- comenzile si parametrii pot fi separati cu delimitatori. Acestia sunt
1. Lansarea ín execuþie a programului DEBUG
obligatorii numai intre doua valori hexazecimale consecutive. Astfel
Pentru a lansa in executie programul DEBUG, din DOS, se tasteaza: urmatoarele comenzi sunt echivalente:
- dcs:100 110
DEBUG [ [unitate:] [cale] nume-fisier [parametrii] ]
- d cs:100 110
Daca nu se introduce nume-fisier , se poate lucra fie cu continutul - d,cs:100,110
memoriei curente, fie se incarca un fisier in memorie utilizind comenzile N - pentru a termina o comanda se tasteaza CTRL-BREAK.
(Name) si L (Load). Optional, numele fisierului poate fi insotit de o serie de - comenzile sunt efective numai dupa actionarea tastei ENTER.
parametri ce vor fi transferati programului incarcat de pe disc (necesari - in timpul programului DEBUG se pot utiliza functiile de editare
pentru fisierul ce urmeaza a fi testat). linie din DOS.
Observatie: Nu este indicat sa se relanseze in executie un program In continuare se prezinta lista comenzilor DEBUG:
dupa ce mesajul urmator este afisat: "Program terminated normally". Este
necesara reincarcarea programului cu comenzile N si L pentru rularea A [adresa] - Asamblarea unei secvente de instructiuni;
corespunzatoare a acestuia. C interval adresa - Compararea a doua zone de memorie;

1
D [interval] - Afisarea continutului unei zone de memorie; utilizeaza segmentul implicit DS pentru toate comenzile, cu exceptia
E adresa [lista] - Modificarea continutului memoriei; comenzilor A, G, L, T, U si W, pentru care segmentul implicit este CS.
F interval lista - Umplerea unei zone de memorie; Ex. : CS:0100 sau 04BA:0100
G [=adresa [adresa ...]] - Executia programului (cu puncte de oprire); interval - Intervalul poate fi specificat in doua moduri:
H valoare1 valoare2 - Adunare/scadere hexazecimala; a) adresa adresa (ex.: CS:100 110);
I adresa_port - Citire si afisare port de intrare; b) adresa L valoare (ex.: CS:100 L 10). Aceasta varianta nu
poate fi utilizata daca urmeaza o alta valoare hexazecimala, intrucit aceasta
L [adresa [unitate sector nr_sect]] - Incarcare fisier sau sectoare
ar putea fi interpretata ca cea de-a doua adresa a intervalului.
absolute de pe disc;
lista - O serie de octeti sau siruri. (ex.: CS:100 42 45 52 54 41).
M interval adresa - Transfer bloc de memorie;
sir - Orice numar de caractere incluse intre ghilimele (' ' sau " ").
N [nume_cale ][lista_arg] - Asignare nume fisier;
O adresa_port octet - Inscriere octet in portul de iesire; Comanda A (Assemble)
P [=adresa] [numar] - Executa o bucla sau subrutina; Scop: Asambleaza mnemonicele 8086/8087 direct in memorie.
Q - Iesire din DEBUG; Format: A [adresa]
R [nume_registru] - Afisarea si eventual modificarea registrelor; Comentarii: Toate valorile numerice pentru comanda A se introduc
S interval lista - Cautare sir de caractere; hexazecimal (1-4caractere). Instrunctiunile in limbaj de asamblare pe care
T [=adresa][valoare] - Executa programul instructiune cu instructiune; le introduceti sunt asamblate in memorie la adrese succesive, cu adresa de
U [interval] - Dezasamblare instructiuni; inceput specificata de parametrul adresa din comanda. Daca nu se specifica
W [adresa [unitate sector nr_sect]] - Scriere fisier sau sectoare nici o adresa, instructiunile sunt asamblate la adresa CS: 100, daca nu s-a
absolute pe disc. mai utilizat nici o comanda A anterior, sau la urmatoarea adresa dupa
ultima instructiune asamblata cu o comanda A anterioara. Pentru a termina
Parametrii comenzilor DEBUG introducerea instructiunilor se tasteaza ENTER. Sunt incluse si doua
pseudo-instructiuni : DB si DW. Sunt permise toate modurile de adresare
Toate comenzile DEBUG, cu exceptia lui Q, accepta parametri. indirecta prin registre.
Semnificatia parametrilor utilizati este urmatoarea: Exemple: - A200
unitate - O cifra hexazecimala care indica unitatea de disc utilizata 0156:0200 xor ax,ax
pentru citire sau scriere. Valorile valide sunt 0-3, unde 0=A:, 1=B:, 2=C:, 0156:0202 mov [bx],ax
3=D: . 0156:0204 ret
octet - O valoare de doua cifre hexazecimale. 0156:0205
sector - O valoare formata din 1-3 cifre hexazecimale care indica
Comanda C (Compare)
numarul sectorului logic de pe disc.
nr_sect - Numarul de sectoare de disc ce vor fi inscrise sau citite. Scop: Compara continutul unei zone de memorie specificata prin interval
valoare - O valoare hexazecimala de pina la 4 cifre. cu o zona de aceeasi dimensiune incepind de la adresa specificata.
adresa - Reprezinta o adresa fizica, formata dintr-un registru Format: C interval adresa
segment alfabetic (sau o adresa de segment de 4 cifre hexazecimale) plus o Comentarii: Daca se gasesc octeti diferiti, se afiseaza adresa si continutul
valoare de offset. Daca se omite adresa sau numele segmentului, se lor in formatul:
adresa1 octet1 octet2 adresa2
2
unde 1 si 2 se refera la cele doua zone comparate. Comanda F (Fill)
Intervalul poate fi specificat in doua moduri: Scop: Umple o zona de memorie specificata prin interval cu valorile din
- prin adresa de inceput si adresa de sfirsit; lista specificata.
- prin adresa de inceput si lungimea acestuia. Format: F interval lista
Exemple: - C 1000,101F 2000 ; Cei 32 octeti de memorie incepind de Comentarii: Daca intervalul contine mai multi octeti decit numarul de
; la adresa DS:1000 valori specificate in lista, lista va fi utilizata repetitiv pina la umplerea zonei
- C 1000 L20 2000 ; sunt comparati cu 32 octeti de de memorie. Daca lista contine mai multe valori decit numarul de octeti din
; memorie de la adresa DS:2000. interval, valorile suplimentare sunt ignorate.
Exemple: - F 0156:100 200 ff
Comanda D ( Dump ) - F 0156:100 L5 "XYZ" 8D ; sunt introduse in
Scop: Afiseaza continutul unei zone de memorie. ; memorie 5 caractere.
Format: D [interval]
Comentarii: Daca nu se specifica intervalul, comanda D afiseaza 128 Comanda G ( Go )
octeti de la prima adresa (DS:100), dupa adresa afisata de precedenta Scop: Executa programul curent din memorie. Opreste executia la o
comanda D. Afisarea se face in doua parti: adresa specificata (break-point) si afiseaza registrele, indicatorii si
1. Portiunea hexazecimala. Fiecare octet este afisat in cod hexazecimal. instructiunea de la adresa unde executia a fost oprita.
2. Portiunea ASCII. Octetii sunt afisati in cod ASCII. Caracterele Format: G [=adresa [adresa ...]]
neafisabile sunt notate ptintr-un punct (.) in portiunea ASCII. Comentarii: Executia programului incepe cu instructiunea curenta, a carei
Exemple: - D cs:100 10 adresa este determinata de perechea de registre CS:IP, cu exceptia cazului
cind s-a introdus parametrul =adresa (= este obligatoriu). Se pot specifica
Comanda E (Enter) pina la zece adrese de breakpoint (dar, numai adrese continind primul bait
Scop: Comanda E are doua moduri de operare: al unei instruciuni 8086), in orice ordine. Programul DEBUG inlocuieste
-inlocuieste continutul unuia sau mai multor octeti, incepind cu codul instructiunii de la adresa de breakpoint cu un cod de intrerupere.
adresa specificata, cu valorile continute in lista; Daca la executia programului se intilneste oricare din aceste adrese,
- afiseaza si permite modificarea octetilor de memorie in mod executia este oprita,se afiseaza registrele si indicatorii, iar adresele se refac
secvential. cu codurile de instructiuni originale. Daca se tasteaza comanda G din nou
Format: E adresa [lista] dupa un breakpoint, executia programului continua cu instructiunea
Comentarii: Daca lipseste lista, comanda E asteapta urmatoarele actiuni: urmatoare dupa breakpoint. Daca la executie nu se intilneste niciuna din
- sa se inlocuiasca baitul de la adresa cu o noua valoare; adrese, codurile instructiunilor respective nu sunt restaurate.
- sa se apese tasta " Space" pentru a avansa la urmatorul bait; Exemple: - G = 100
- sa se tipareasca o liniuta (-) pentru a reveni la baitul precedent; - G = 100 124
- sa se actioneze tasta ENTER pentru a termina comanda E. - G = 100 1EF 208
Exemple: - E ds:100 f3 "xyz" 8d ;lista Comanda H ( Hex )
- E ds:100 Scop: Realizeaza suma si diferenta hexazecimala a celor doi parametrii
0BAC:0100 F3.00 DF.55 specificati.

3
Format: H valoare1 valoare2 Format: M interval adresa
Exemple: - H 12A7 119E Comentarii: Suprapunerea partiala a celor doua zone de memorie nu
2445 0109 conduce la pierderea datelor.
Exemple: - M CS:100 110 500 ;Cei 17 octeti de la CS:100 la
Comanda I ( Input )
; CS:110 sunt mutati in zona de
Scop: Executa o operatie de intrare de la un port specificat si afiseaza data
; memorie incepind de la DS:500.
citita.
Format: I adresa_port Comanda N (Name)
Exemple: - I 2f8 Scop: Stabileste numele fisierelor.
6B
Format: N nume_fisier [nume_fisier...]
Comentarii: Comanda N asigneaza un nume de fisier pentru o comanda
Comanda L ( Load )
ulterioara L sau W. Numele fisierului poate include si calea in care se
Scop: Incarca un fisier sau sectoare absolute de pe disc in memorie.
gaseste acesta.
Format: L [adresa [unitate sector nr.sect ]]
Comentarii: Numarul maxim de sectoare absolute care pot fi incarcate cu
Comanda O (Output)
o singura comanda L este 80H pentru cazul unitate sector nr.sect. Numele
Scop: Trimite un octet de date la un port de iesire specificat
unitatii este numeric ( 0=A; , 1=B; , 2=C; etc. )
Format: O adresa_port octet
Exemple: - L fc3:100 1 0f 6d ;Datele se incarca de pe discul B si sunt Exemple: - O 2f8 6f ;Transmite octetul 6f la portul de iesire 2f8.
; plasate in memorie incepind de la
; adresa fc3:100. Comanda P (Proceed)
; Se transfera 6dh (109) sectoare Scop: Executa o bucla, o intrerupere software, sau un apel de subrutina
; consecutive, incepind cu adresa de complet.
; sector relativa 0fh(15) (al16-lea sector Format: P [=adresa ] [numar]
; de pe disc). unde: adresa este locatia primei instructiuni ce va fi executata; numar
- N nume-fisir ; Fisierul specificat prin comanda N este reprezinta numarul de instructiuni ce se executa.
; incarcat de pe Comentarii: Daca adresa este omisa, executia incepe de la adresa
-L ;unitatea implicita si plasat in memorie specificata prin registrele CS:IP. Daca instructiunea de la adresa nu este o
; incepind cu adresa CS:100 intrerupere software, un apel de subrutina sau o bucla, comanda P lucreaza
exact ca si comanda T (Trace). Daca parametrul numar este omis, se
Daca fisierul are o extensie .exe, acesta trebuie relocatat la adresa de executa o singura instructiune.
incarcare specificata in hederul fisierului .exe. Parametrul adresa este Exemple: - P = 143F ; Executa o subrutina care este apelata cu
intotdeauna ignorat pentru fisiere .exe. ; o instructiune call aflata la adresa CS:143F.
Comanda M (Move) Comanda Q (Quit)
Scop: Muta continutul locatiilor de memorie specificate in interval in Scop: Termina programul DEBUG.
locatiile incepind de la adresa specificata. Format: Q
4
Comentarii: Fisierul care contine programul cu care s-a lucrat in memorie, Comanda S(Search)
nu este salvat. Trebuie utilizata comanda W inainte de a executa comanda Scop: Cauta intr-o zona de memorie un sir de octeti specificat in lista.
Q, pentru a salva intr-un fisier programul depanat. DEBUG transfera Format: S interval lista
controlul interpretorului de comenzi. Comentarii: Toate sirurile gasite in memorie sunt indicate prin afisarea
Exemple: -Q adreselor de inceput ale acestora.
C:\> Exemple: - S CS:100 110 41 "AB" 5E ;Se cauta un sir de 4 octeti.

Comanda R (Register) Comanda T (Trace)


Scop: Comanda are 3 functii: Scop: Executa una sau mai multe instructiuni incepind cu instructiunea de
- Afiseaza continutul hexa al unui singur registru, cu posibilitatea la adresa indicata de CS:IP, sau de la =adresa (= este obligatoriu). Implicit
optionala de a modifica continutul. se executa o singura instructiune, dar se pot executa mai multe cu
- Afiseaza continutul hexa al tuturor registrelor, plus starea parametrul valoare. Afiseaza continutul tuturor registrelor si indicatorilor
indicatorilor (ordonati alfabetic) si urmatoarea instructiune de executat. dupa fiecare instructiune executata.
- Afiseaza cei 8 indicatori ( nume compuse din doua litere) cu Format: T [=adresa] [valoare]
posibilitatea optionala de a modifica acesti indicatori. Comentarii: Afisarea cauzata de comanda T continua pina cind se executa
Format: R [nume_registru] valoare instructiuni.
Comentarii: Daca nu se tasteaza un nume-registru, comanda R afiseaza Exemple: - T10
continutul tuturor registrelor si fanioanelor. Daca se tasteaza un
nume-registru (AX, BX, CX, DX, SP, BP, SI, DI, DS, ES, SS, CS, IP) Comanda U (Unassemble)
atunci se afiseaza valoarea hexa a acestuia si se poate introduce o noua Scop: Translateaza continutul memoriei in instructiuni (dezasambleaza
valoare. Daca se tasteaza F ca nume-registru se afiseaza fiecare fanion cu
instructiunile) si afiseaza impreuna cu instructiunile si valorile hexa ale
un cod alfabetic format din doua caractere. Fanioanele sunt listate in
adreselor.
continuare cu codurile lor pentru SET si CLEAR:
Format: U [interval]
Fanion Set Clear Comentarii: Daca se tasteaza comanda U fara interval (sau cu intervalul
Overflow OV NV specificat printr-o singura adresa) se dezasambleaza 20H octeti.
Direction DN UP Exemple: - U CS:100 L6
Interrupt EI DI
Sign NG PL Comanda W (Write)
Zero ZR NZ Scop: Scrie programul depanat pe disc.
Auxiliary Carry AC NA
Format: W [adresa [unitate sector nr.sect.] ]
Parity PE PO
Comentarii: Daca nu se utilizeaza parametrii cu comanda W, registrele
Carry CY NC
BX:CX trebuie sa contina deja numarul de baiti care se scriu. Daca nu se
Noile valori pentru fanioane se pot introduce in orice ordine. specifica adresa, fisierul este scris incepind de la CS:100. Fisierul trebuie
Exemple: - RF denumit fie cu comanda initiala de lansare DEBUG, fie cu comanda N.
NV UP DI NG NZ AC PE NC - CY EI Programul depanat este scris peste fisierul original care a fost incarcat in

5
memorie sau intr-un fisier nou daca numele definit in blocul de control nu END START
exista pe disc. Daca se specifica parametrii, atunci fisierul este scris Prima etapa in procesul de verificare/corectare consta in apelarea
incepind cu sectorul specificat si se continua pina la scrierea nr.sect. programului DEBUG din DOS, utilizind comanda:
specificate. DEBUG PTEST.EXE
Exemple: - W CS:100 1 37 2B Comanda presupune ca ptest.exe este prezent in directorul curent si
ca DEBUG.COM este accesibil fie direct fie prin utilizarea anterioara a
Mesaje de eroare comenzii SET PATH.
BF - Valoare gresita pentru un fanion; In continuare se poate utiliza comanda D, fara parametru de adresa,
BP - Prea multe puncte de oprire (breakpoints) (s-au specificat mai intrucit programul ptest va fi incarcat la adresa implicita CS:0100.
mult de 10 breakpoints ca parametrii ai comenzii G); De asemenea, se poate utiliza comanda U.
BR - Nume incorect de registru; Pentru executia programului in modul TRACE, intrucit programul se
termina normal, putem furniza al doilea parametru din comanda P oricit de
DF - S-au tastat doua valori pentru un fanion.
mare pentru a fi siguri ca s-a terminat de executat intregul program.
Exemplul 3.1 Intrucit programul directioneaza propria lui iesire la imprimanta,
aceasta va aparea in cadrul iesirii cu TRACE. O linie noua ("line feed") se
TITLE ptest
genereaza dupa executia celei de-a treia instructiuni (int 21h), un retur de
;Acest program transmite date ASCII in domeniul 41h - 7Fh la portul
car dupa cea de-a cincea instructiune (int 21h), si un singur caracter, A ,
imprimantei paralele.
dupa a noua instructiune (int 21h). Dupa aceea, programul executa bucla
;Registre utilizate: AX, CL, DL
formata din instructiunile de la adresele de OFFSET 0110h si 0112h. Nici o
;Parametrii transferati : niciunul tiparire nu apare in cadrul acestei bucle, desi registrul DL este incrementat
TEXT SEGMENT ; Defineste segmentul de cod prin domeniul cerut al codului ASCII. Evident, bucla nu revine la INT 21h,
ASSUME CS:TEXT, DS:TEXT, SS:TEXT responsabila de apelul DOS care genereaza iesirea caracterului la
ORG 100h ; imprimanta!
START: mov AH,05h ; Codul functiei de iesire la imprimanta Se poate rezolva usor aceasta problema in cadrul programului
mov DL, 0Ah ; Initial se genereaza DEBUG, fara a reveni in macroasamblor. Trebuie doar sa modificam
int 21h ; "line feed" instructiunea LOOP de la adresa de OFFSET 0114h. Pentru aceasta se
mov DL, 0Dh ; Apoi se genereaza un utilizeaza comanda:
int 21h ; retur de car A 114
mov DL, 41h ; Primul caracter de tiparit este A Se afiseaza:
mov CL,3Eh ; Numarul de caractere de tiparit CS:0114 ....
mov AH,05h ; Stabileste codul functiei si apoi se introduce:
int 21h ; tipareste caracterul loop 110 <Enter>
imp: inc DL ; Pregateste noul caracter Acum se poate utiliza din nou comanda P.
loop imp ; Revine in bucla
Se iese din DEBUG, se incarca macroasamblorul si se fac
mov AL,00h ; Stabileste codul de revenire
schimbarile necesare in codul sursa. Altfel, putem scrie direct codul
mov AH,4Ch ; si codul functiei
modificat in fisierul ptest.exe utilizind comanda W din DEBUG. Dar, acest
int 21h ; pentru revenire in DOS
TEXT ENDS
6
procedeu rapid nu va conduce la reflectarea modificarilor efectuate si in ;
DOSSEG
codul sursa!
.MODEL SMALL
Exemplul 3.2 .STACK 100h
title TipChar .DATA
; Programul urmator afiseaza si tipareste caractere pe masura ce acestea select DB 'Doriti afisare/tiparire (A/T)?$'
; sunt tastate. Daca se tasteaza <CR>, programul trimite secventa <CR> Mesaj DB 13, 10, 'Program pentru tiparirea/afisarea unui mesaj', 13, 10
; <LF> la ecran si imprimanta. Programul se termina cind se tasteaza lung_mesaj EQU $-Mesaj
; caracterul '$'. .CODE
; START:
ASSUME CS : r mov ax, @DATA
ASSUME ES : nothing mov ds, ax
r SEGMENT PARA mov dx, OFFSET select
;
print_char MACRO char ; Trimite un caracter la mov ah, 9 ; Functie DOS de afisare a unui
mov DL,char ; imprimanta ; sir terminat cu caracterul $
mov AH,05h int 21h
int 21h mov ah, 1 ; Asteapta un caracter de la tastatura
ENDM int 21h
; cmp al, 'a' ; S-a tiparit a pentru afisare pe ecran ?
start: mov AH,01h ; Citeste cu ecou un
int 21h ; caracter de la tastatura jz Afisare_ecran
print_char AL ; Tipareste caracterul cmp al, 'A' ; S-a tiparit A pentru afisare pe ecran ?
cmp AL,'$' ; Este '$' ? jnz Tipar_imprim
je exit ; Da, se termina programul Afisare_ecran:
cmp AL,0Dh ; Este <CR> ? mov bx, 1 ; Comanda afisarea pe ecran
jne start ; Nu, se reia citirea jmp AFIS
print_char 0Ah ; Trimite <LF> la imprimanta Tipar_imprim:
mov AH,02h mov bx, 4 ; Comanda imprimanta
mov DL,0Ah AFIS: mov ah, 40h ; Functie DOS de afisare a unui sir al
int 21h ; Trimite <LF> la ecran ; carui numar de caractere este precizat
jmp start ; in registrul CX
exit: mov AH,4Ch mov cx, lung_mesaj ; Numarul caracterelor ce
int 21h ; Sfirsit program ; trebuie tiparite/afisate
r ENDS mov dx, OFFSET Mesaj
END start int 21h
Exemplul 3.3 SF: mov ax, 4c00h ; Iesire in sistem
title IMPRIM.ASM int 21h
; IMPRIM - permite transmiterea unui mesaj la imprimanta sau pe ecran END START

7
int 21h
Exemplul 3.4 SF: mov ax, 4c00h ; Iesire in sistem
int 21h
title INTERACT.ASM END START
; INTERACT - este un program interactiv, permitind afisarea unui mesaj ;
dorit pe ecran
;
DOSSEG Modul de lucru
.MODEL SMALL
1. Se vor studia comenzile programului DEBUG.
.STACK 100h
2. Se vor edita, asambla ßi rula cele patru programe prezentate.
.DATA
3. Se vor obtine ßi analiza fißierele listing ßi de referinþe íncrucißate.
Timp DB 'Suntem dupa ora 12 (Y/N) ?$'
4. Se vor rula ßi depana utilizänd DEBUG programele realizate.
mes1 LABEL BYTE
DB 13, 10, "Buna dimineata, ROMANIA!", 13, 10, '$'
Conþinutul referatului
mes2 LABEL BYTE
DB 13, 10, "Buna ziua, ROMANIA!", 13, 10, '$' 1. Listingurile programelor realizate.
.CODE 2. Observaþiile ßi comentariile studentului.
START:
mov ax, @DATA
mov ds, ax
mov dx, OFFSET Timp
mov ah, 9 ; Functie DOS de afisare a unui sir
; terminat cu caracterul $
int 21h
mov ah, 1 ; Asteapta un caracter de la tastatura
int 21h
cmp al, 'y' ; S-a tiparit y pentru "dupa amiaza?"
jz dupa_prinz
cmp al, 'Y' ; S-a tiparit Y pentru "dupa amiaza?"
jnz dimineata
dupa_prinz:
mov dx, OFFSET mes2
jmp AFIS
dimineata:
mov dx, OFFSET mes1
AFIS: mov ah, 9 ; Functie DOS de afisare a unui sir
; terminat cu caracterul $

8
Exemple:
mov bx, 7a2h ; Íncarcá registrul BX cu valoarea 7a2h
LUCRAREA NR. 4
alfa: mov beta [bx][di], al ; Transferá octetul din AL la
Grupul instrucþiunilor de transfer de date ; adresa OFFSET beta+BX+DI
Scopul lucrárii ; ín segmentul de date asociat
Lucrarea urmáreßte familiarizarea studenþilor cu noþiunile primare ; variabilei beta
ale limbajului de asamblare al microprocesoarelor I8086/I8088, precum xchg bl, cl ; Interschimbá conþinutul registrelor BL ßi CL
ßi grupul instrucþiunilor de transfer de date. Dupá prezentarea formatului gama: popf ; Reface din stivá conþinutul registrului de flaguri F
general extren al instrucþiunilor, se prezintá, pe scurt, instrucþiunile din
grupul instrucþiunilor de transfer de date, dupá care urmeazá o serie de Descrierea setului de instrucþiuni ale microprocesoarelor
exemple care sá evidentieze modul de utilizare al acestora. I8086/I8088
Pentru prezentarea setului de instrucþiuni ale microprocesoarelor
Chestiuni teoretice I8086/I8088 utilizám urmátoarele notaþii:
Formatul general (extern) al instrucþiunilor Numele registrelor din UCP I8086/I8088 :
Instrucþiunile microprocesoarelor I8086/I8088, scrise ín limbaj de • AX, BX, CX, DX - registre generale de 16 biþi;
asamblare, au formatul tipic acestor limbaje, constituit din mai multe • AH, AL, BH, BL, CH, CL, DH, DL - registre generale de 8 biþi;
cämpuri: • SP, BP, SI, DI - registre de 16 biþi;




• CS, DS, SS, ES - registre de segment;
Mnemonica codului
[Eticheta: ]
de operatie
 Operand  [; Comentariu ] • F (PSW) = x x x OF DF IF TF | SF ZF x AF x PF x CF - registrul de
 
 Operand1, Operand2  flaguri.
unde parantezele drepte [ ] aratá cá elementele incluse pot apare sau nu ín Referiri generale:
mod facultativ, iar acoladele { } indicá faptul cá numai un element din • A - acumulator (AX sau AL sau AH, funcþie de context);
cele scrise pe verticalá poate apare íntr-o instrucþiune datá. • R - registru oarecare de uz general: R8 - registru de 8 biþi, R16 - registru
Cämpul Eticheta este opþional, iar cänd apare este un identificator de 16 biþi;
cáruia i se asociazá adresa primului octet al instrucþiunii respective. • M - operand din memorie: M8, M16, M32 unde indicele 8, 16, 32
Mnemonica codului de operaþie este numele simbolic al precizeazá lungimea ín biþi pentru operanzi cu 1, 2, respectiv 4 octeþi;
instrucþiunii sau al unui grup de instrucþiuni; apare obligatoriu ín orice • SR - registru segment oarecare: CS, DS, SS, ES;
instrucþiune. • nume_reg - conþinutul numeric al registrului indicat de nume (sursá sau
Cämpul operanzi poate conþine doi operanzi, unul sau niciunul, ín destinatie);
funcþie de tipul instrucþiunii. Cänd existá doi operanzi, primul este • DATA - operand numeric imediat: DATA8, DATA16 - operand
operandul destinaþie, iar cel de-al doilea, operandul sursá. Operanzii numeric pe 8, respectiv 16 biti;
identificá datele asupra cárora acþioneazá instrucþiunea, modul de
• DEPL - deplasament (offset) de adresá: DEPL8, DEPL16 - deplasament
adresare ßi alte informaþii auxiliare. pe 8, respevtiv 16 biti;
Cämpul Comentariu este opþional. Acesta serveßte pentru creßterea
• (EA) - octetul cu adresa de offset egalá cu EA;
inteligibilitáþii programului. La asamblare, textul comentariului este
ignorat de cátre asamblor. • (EA + 1, EA) - cuväntul cu adresa de offset egalá cu EA;
1
• [ nume_reg ] - octetul adresat indirect prin registrul indicat; mov R16, SR ; R16 <--- SR
• (nume_ reg + 1, nume_reg ) - cuväntul adresat indirect prin registrul mov R8, DATA8 ; R8 <--- DATA8
indicat; mov M8, DATA8 ; M8 <--- DATA8
• SRC - notatie generalá pentru o sursá de date: DATA, DATA8, mov R16, DATA16 ; R16 <--- DATA16
DATA16, (EA), (EA+1, EA), nume_reg, [nume_reg]; mov M16, DATA16 ; M16 <--- DATA16
mov R8, M8 ; R8 <--- M8
• DST - notatie generalá pentru o destinatie a datelor: nume_reg,
mov M8, R8 ; M8 <--- R8
[nume_reg], (EA), (EA+1, EA);
mov R16, M16 ; R16 <--- M16
• EA - adresa efectivá; FA - adresa fizicá. mov M16, R16 ; M16 <--- R16
mov SR, M16 ; SR <--- M16 ; (SR nu poate fi CS)
Instrucþiuni pentru trasnferul datelor mov M16, SR; M16 <---SR
Ín aceastá categorie se íncadreazá urmátoarele tipuri de Observaþii:
instrucþiuni: instrucþiuni de transfer de tip "clasic", instrucþiuni pentru a. Nu este permisá execuþia unei instrucþiuni MOV de forma:
íncárcarea adreselor ßi instrucþiuni pentru transferul valorilor
mov SR, DATA16 ; Incarcá un registru segment cu un
indicatorilor de condiþie.
; operand imediat.
1o. Instrucþiuni de transfer de tip "clasic" b. Nu se pot transfera direct date íntre douá locaþii de memorie sau íntre
Ín categoria instrucþiunilor de transfer de tip "clasic" se íncadreazá douá registre segment.
urmátoarele instrucþiuni:
mov DST, SRC Moduri de adresare a memoriei
push SRC Microprocesoarele I8086/I8088 permit ßase moduri diferite de
pop DST specificare a adreselor: adresare imediatá, adresare directá, adresare
xchg DST, SRC indirectá prin registre, adresare bazatá, adresare indexatá ßi adresare
xlat bazatá-indexatá.
a) Efectul instrucþiunii MOV este de a transfera valoarea desemnatá de
sursa SRC la destinaþia DST. Operanzii instrucþiunii MOV pot avea Adresarea imediatá
lungimea de 8 sau 16 biti ßi aceßtia pot fi: registre generale, conþinutul Operandul (data) este specificat ín instrucþiune, dupá codul
unor locaþii de memorie sau date imediate. In urma execuþiei operaþiei operaþiei.
MOV se modificá numai conþinutul operandului destinaþie, conþinutul Exemple:
operandului sursá rámänänd nemodificat. De asemenea, instrucþiunea data_segment SEGMENT
MOV nu afecteazá indicatorii de condiþie. Formele admise de aw DW 'AB'
instrucþiunea MOV sunt: data_segment ENDS
mov al, 5
mov R8, R8 ; R8 <--- R8 mov ax, OFFSET aw; Valoarea operandului este adresa
mov R16, R16 ; R16 <--- R16 ; relativá a parametrului aw
mov SR, R16 ; Continutul unui registru de 16 biti se mov ax, data_esgment ; Valoarea operandului este
; transferá íntr-un registru segment (SR ; adresa segmentului de date,
; nu poate fi CS) mov ds, ax ; data_segment
2
Adresarea directá Adresarea indexatá
Operandul este conþinutul unui registru specificat ín instrucþiune Adresarea indexatá utilizeazá registrele SI ßi DI ímpreuná cu un
sau conþinutul locaþiei (locaþiilor) de memorie de la adresa efectivá a nume de variabilá pentru a adresa date de tip tablou (vector). Aceste
numelui (variabilei) precizate ín instrucþiune. registre sunt folosite ca un index faþá de adresa de offset reprezentatá prin
Exemple: numele variabilei. Conþinulul registrului utilizat ca index specificá un
mov bx, ax ; Íncarcá BX cu continutul registrului AX deplasament pe un octet faþá de adresa de offset a variabilei. Registrul de
mov al, dl ; segment considerat implicit este registrul DS.
mov ax, aw ; Íncarcá AX cu continutul cuväntului de la Exemple:
; adresa aw mov si, 0 ; Íncarcá indexul sursei cu 0
mov aw + 2, ax ; (aw +2) = AL, (aw + 3) = AH mov di, 0 ; Íncarcá indexul destinatiei cu 0
Adresarea indirectá prin registre mov ax, sirsursa[si] ; Íncarcá AX cu primul element al lui sirsursa
Adresa efectivá a operandului este conþinutá íntr-unul din mov sirdest[di], ax ; Memoreazá AX ín primul element al lui sirdest
registrele de bazá BX, BP sau ín registrele index SI sau DI. Pentru Cum elementele succesive ale sirului au adresele de offset 0,2,4,6,8,...,
adresarea unei locaþii de memorie, mai intäi trebuie íncárcat íntr-un atunci:
registru adresa de offset a operandului, ßi apoi, vom utiliza numele mov si, 6 ; Íncarcá indexul sursei cu 6
registrului ín paranteze drepte ca operand. mov di, 6 ; Íncarcá indexul destinatiei cu 6
Exemple: mov ax, sirsursa[si] ; Íncarcá AX cu al 4-lea element al lui sirsursa
mov bx, OFFSET aw ; Íncarcá BX cu adresa de offset a parametrului aw mov sirdest[di], ax ; Memoreazá AX in al 4-lea element al lui
mov ax, [bx] ; Aceste douá instructiuni sunt echivalente cu ; sirdest
mov [bx + 2], ax ; ultimele douá instructiuni din exemplul anterior
Adresarea bazatá-indexatá
Adresarea bazatá Ín instrucþiune apar atät registrele de bazá, cät ßi index utilizate ßi,
Adresarea bazatá este similará adresárii indirecte prin registru, cu opþional, un deplasament. Adresa fizicá rezultá pe baza adresi de segment
excepþia faptului cá ín aceastá situaþie se pot utilza numai registrele de implicatá ín instrucþiune, adresa efectivá a operandului ín cadrul
bazá BX ßi BP, iar la conþinutul acestora se poate aduna un deplasament segmentului fiind suma dintre conþinutul registrului de bazá, conþinutului
pe 8 sau 16 biþi. Dacá drept registru de bazá se utilizeazá registrul BX, registrului index ßi deplasamentul conþinut ín instrucþiune. Registrul de
atunci se considerá implicit, ca registru de segment, registrul DS, iar dacá bazá este cel ce dicteazá registrul segment considerat implicit. Acest tip
drept registru de bazá se utilizeazá registrul BP, atunci se considerá de adresare este util pentru a realiza accesul la structurile de date create
implicit, ca registru de segment, registrul SS. De obicei, adresarea bazatá ín stivá sau, accesul la elementele unui vector de ínregistrári. Ín acest
se utilizeazá pentru a referi elementele unei structuri pentru care adresa ultim caz, ín registrul de bazá se íncarcá adresa de ínceput a vectorului,
de ínceput este conþinutá ín registrul de bazá, iar adresa relativá ín cadrul ín registrul index se íncarcá adresa relativá ín vector a ínregistrárii
structurii apare explicit ín instrucþiune. referite, iar ín instrucþiune apare adresa relativá a elementului referit din
Exemplu: ínregistrare.
mov bx, OFFSET structura ; Íncarcá BX cu adresa de bazá a Exemple:
; structurii array DB 100 DUP (55h)
mov al, [bx + 5] ; Íncarcá AL cu continutul de la adresa mov bx, OFFSET array
BX+5 (al 5-lea octet al structurii structura) mov si, 2
3
mov ax, WORD PTR [bx] [si] ; Íncarcá AX cu continutul de dar nu se poate executa o instrucþiune
; la adresa BX + SI pop cs.
mov ax, WORD PTR [bx + si] ; Íncarcá AX cu continutul de
; la adresa BX + SI c) Instrucþiunea XCHG are ca efect interschimbarea conþinutului sursei
mov al, [bx] [si] [50] ; Íncarcá Al cu al 53-lea octet al cu cel al destinaþiei. Instrucþiunea poate fi folositá sub forma:
; sirului array XCHG R8, R8 ; R8 <----> R8
mov al, [bx + si + 50] ; Íncarcá Al cu al 53-lea octet al XCHG R8, M8 ; R8 <----> M8
; sirului array XCHG R16, R16 ; R16 <----> R16
XCHG R16, M16 ; R16 <----> M16
b) Instrucþiunile PUSH ßi POP sunt instrucþiuni de lucru cu stiva.
Observaþie: Nu se pot utiliza drept operatori registrele de segment.
Instrucþiunea:
PUSH SRC ; SP <--- SP - 2, (SP + 1, SP) <--- SRC d) Instrucþiunea XLAT (Translate Byte to AL) translateazá (converteßte)
transferá ín värful stivei cuväntul precizat prin operandul SRC. Se poate valoarea lui AL, adicá o ínlocuießte cu un octet dintr-un tabel a cárui
utiliza sub forma: adresá de ínceput se aflá ín registrul BX. Indexul ín acest tabel este
push R16 ; Salveazá pe stivá continutul unui registru de 16 tocmai valoarea lui AL ( AL <--- [BX + AL])
; biti, R16
push M16 ; Salveazá pe stivá continutul locatiei de 2o. Instrucþiuni pentru íncárcarea adreselor
; memorie avänd adresa relativá precizatá ín Existá patru instrucþiuni pentru íncárcarea adresei unui operand
; instructiune (nume, variabilá, expresie):
push SR ; Salveazá pe stivá continutul unui registru MOV R16, OFFSET operand
; segment LEAR16, operand ; LEA - Load Effective address
La fiecare salvare pe stivá, indicatorul SP se decrementeazá cu 2. LDSR16, adresa_pointer ; LDS - Load Data Segment register
Instrucþiunea: LES R16, adresa_pointer ; LES - Load Extra Segment register
a) Ca efect al execuþiei instrucþiunii:
POP DST ; DST <--- (SP + 1, SP), SP <--- SP + 2
lea R16, operand
reface din värful stivei cuväntul precizat ín operandul DST. Se poate se íncarcá ín registrul R16, adresa relativá a operandului ce apare ín
utiliza sub forma: instrucþiune. Aceastá instrucþiune este mai puternicá decät instrucþiunea
pop R16 ; Reface din stivá continutul unui registru de 16 mov R16, operand
; biti, R16 deoarece permite ßi utilizarea unor registre de bazá ßi index ín formarea
pop M16 ; Reface din stivá continutul locatiei de memorie adresei.
; avänd adresa relativá precizatá ín Exemple: nume DB 100
instructiune lea bx, nume ; Íncarcá BX cu adresa de offset
pop SR ; Reface din stivá continutul unui registru ; a operandului nume
; segment (SR nu poate fi CS) Aceastá instructiune este echivalentá cu instrucþiunea:
La fiecare extragere din stivá, indicatorul SP se incrementeazá cu 2. mov bx, OFFSET nume
Observaþie: Se poate executa o instrucþiune Instrucþiunea:
push cs ; Salvare registru segment de cod mov ax, OFFSET table[si]
4
este o instrucþiune invalidá, pe cänd instrucþiunea: Exemple de programe ce utilizeazá instrucþiunile de transfer de date
lea ax, table[si]
Programul 4.1.
are ca efect íncárcarea ín AX a offsetului operandului table + si.
title Instructiuni de transfer
b) Ca efect al execuþiei instrucþiunilor:
; Se prezinta exemple de utilizare a instructiunilor MOV
lds R16, operand
les R16, operand code SEGMENT ; Numele segmentului de cod
se íncarcá ín registrul DS, respectiv ES ßi ín registrul R16 specificat ín ASSUME cs: code, ds: t_data, ss: stiva ; Asignarea segmentelor
instrucþiune, adresa aflatá ín memorie la adresa efectivá a operandului START: ; Modulul principal incepe de la
referit ín instrucþiune. Cei patru octeþi aflaþi ín memorie la aceastá adresá locatia START
sunt interpretaþi ca o adresá de tip pointer. Astfel valoarea conþinutá ín mov ax, t_data ; Adresa lui t_data in ax
primii doi octeþi (componenta de offset) se íncarcá ín registrul R16, iar mov ds, ax
valoarea conþinutá ín urmátorii doi octeþi (componenta de segment) se mov ax, stiva ; Adresa lui stack in ax
íncarcá ín registrul DS, respectiv ES. mov ss, ax
mov sp, OFFSET s_data ; Stabileste SP
; Transfer imediat de date in registre
3o. Instrucþiuni pentru transferul valorilor indicatorilor de condiþie
mov ax, 0ffffh
a) LAHF ; Load AH from Flags
mov bl, '0' ; Codul ASCII pe 8 biti al lui 0 trece in reg. BL
Íncarcá ín registrul AH octetul inferior al registrului F, astfel:
; Transfer registru - registru (16 biti)
mov bx, ax
AH SF ZF x AF x PF x CF Flow mov cx, bx
mov dx, cx
b) SAHF ; Store AH in Flags ; Transfer registru - registru (8 biti)
Íncarcá ín octetul inferior al registrului F, registrul AH , astfel: mov al, 0 ; Data 0 trece in registrul AL
mov bl, al
mov cl, bl
Flow SF ZF x AF x PF x CF AH mov dl, cl
; Transfer registru - memorie
c) Instruþtiunea PUSHF (PUSH Flags) salveazá ín stivá valorile mov ax, cuvint ; Continutul locatiei cuvint
indicatorilor de condiþie: ; trece in reg. AX
mov dl, BYTE PTR cuvint2
SP <-- SP - 2; (SP + 1) <-- Fhigh, (SP ) <--- Flow. ; Transfer din memorie cu adresare indirecta
d) Instrucþiunea POPF (POP Flags) reface din stivá valorile indicatorilor mov bx, OFFSET octet1 ; Adresa de offset a variabilei
de condiþie: ; octet1 trece in reg. BX
Flow <--- (SP ), Fhigh <--- (SP + 1); SP <--- SP + 2. mov al, [bx]
; Transfer memorie - memorie (trebuie utilizat un registru in doua etape)
Observaþie: Instrucþiunile LAHF ßi PUSHF nu afecteazá indicatorii de mov bx, cuvint2
condiþie, iar instrucþiunea SAHF nu afecteazá flagurile TF, IF, DF ßi OF. mov ax, cuvint
mov cuvint2, ax
5
mov bx, cuvint2 mov bp, 0ah
mov cx, SIZE cuvint ; Marimea operandului (CX = 2) mov ds:TAB[bp], 1 ; Se incarca in TAB[10] valoarea 1
mov ah, 4ch ; Revenire in MS-DOS ; Transferuri
int 21h mov ah, TAB+7 ; AH = 12 (0ch)
code ENDS ; Sfirsitul segmentului de cod mov cx, WORD PTR TAB+8 ; CX = fffeh
t_data SEGMENT ; Segmentul de date lea di, TAB[bx+si+3] ; Incarca pe DI cu adresa
cuvint dw 0ffffh ; efectiva a lui TAB[10]
cuvint2 dw 0f0fh mov [di], 258 ; (TAB+11, TAB+10) = 0102h
octet1 db 55h mov ax, [di] ; AX = 0102h
t_data ENDS ; Sfirsitul segmentului de date mov al, [di+1] ; AX = 0101h
stiva SEGMENT STACK ; Segmentul de stiva mov [di+2], ah
DB 256 DUP (?) ; Defineste spatiul stiva ; Permutari
s_data EQU $ ; Defineste virful stivei xchg si, di
stiva ENDS ; Sfirsitul segmentului de stiva xchg ah, [si] ; AX = 0201h
end START ; Sfirsitul programului xchg bx, [si] ; BX = 0101h
mov ax, 4c00h ; Iesire in sistem
Programul 4.2. int 21h
title TRANSFD.ASM DATATRN ENDS
; TRANSFD realizeaza transferuri de date de tip registru-registru, END START
; registru-operand imediat, memorie-operand imediat, registru-memorie
Programul 4.3.
ASSUME cs:DATATRN, ds:DATATRN, ss:STIVA
title ERR.ASM
STIVA SEGMENT STACK
; ERR prezinta exemple de erori de adresare si de incompatibilitate a
DB 50 DUP (0)
; tipurilor de operanzi. Erorile sunt semnalate de MASM (TASM) prin
STIVA ENDS
; mesaje de eroare corespunzatoare.
DATATRN SEGMENT ;
TAB DB 16 DUP (0) ASSUME cs: ZZZ, ds:TAB, cs:STIVA
START: TAB SEGMENT ; Segmentul de date
mov ax, cs ; Segmentele de date si de cod sunt comune ARRAY DB 16 DUP (55)
mov ds, ax ; Se incarca registrul DS cu adresa de baza a GAMA EQU 99h
; segmentului de date TAB ENDS
mov ax, STIVA STIVA SEGMENT STACK ; Segmentul de stiva
mov ss, ax DB 100 DUP (0)
; Incarcari imediate STIVA ENDS
mov bx, 3 ZZZ SEGMENT ; Segmentul de cod si date
mov si, 4 START: mov ax, TAB
mov TAB[bx][si],12 ; Se incarca in TAB[7] valoarea 12 START1: mov ax, WORD PTR TAB
mov WORD PTR TAB[bx][si+1], 65534 mov ax, ds : WORD PTR TAB
; (TAB+9, TAB+8) = fffeh mov ds, 55h
6
mov ds, ax ; la tastatura
mov cl, GAMA DOSSEG
mov cl, ds : GAMA .MODEL SMALL
mov dl, BETA .STACK 100h
mov al, ALFA .DATA
mov al, ds : ALFA lung_max_sir EQU 1000
mov al, ARRAY sir_init DB lung_max_sir DUP (?)
mov al, ds : ARRAY sir_reversat DB lung_max_sir DUP (?)
mov al, BYTE ALFA .CODE
mov al, BYTE PTR ALFA START: mov ax, @DATA
mov al, cs : BYTE PTR ALFA mov ds, ax
mov al, ds : BYTE PTR ALFA mov ah, 3fh ; Functie DOS de comanda - citire periferic
mov al, BYTE PTR START mov bx, 0 ; Comanda - intrare standard
mov al, ds : BYTE PTR START mov cx, lung_max_sir
mov al, WORD PTR ALFA mov dx, OFFSET sir_init
mov ax, WORD PTR ALFA int 21h
mov al, OFFSET ALFA and ax, ax ; S-a citit vreun caracter ?
mov ax, OFFSET ALFA jz GATA ;
ALFA: mov al, BYTE PTR 2 mov cx, ax ; Transfera lungimea sirului in CX
lea di, TAB push cx ; Salveaza in stiva lungimea sirului
mov di, TAB mov bx, OFFSET sir_init
lea di, ARRAY[di+bx+5] mov si, OFFSET sir_reversat
mov si, OFFSET ARRAY add si, cx
lds si, ARRAY dec si
lds si, TAB BUCLA_REVERSARE:
lds si, TAB[ARRAY] mov al, [bx] ; Preia urmatorul caracter
lds si, ds : ARRAY mov [si], al ; Memoreaza caracterele in ordine inversa
lds si, DWORD PTR ARRAY inc bx
mov si, ZZZ dec si ;
mov ax, 4c00h ; Iesire in sistem loop BUCLA_REVERSARE
int 21h pop cx ; Reface lungimea sirului
BETA EQU 777h mov bx, 1 ; Comanda afisarea pe ecran
ZZZ ENDS AFIS: mov ah, 40h ; Functie DOS de afisare a unui sir
END START1 mov dx, OFFSET sir_reversat
int 21h
Programul 4.4. GATA: mov ax, 4c00h ; Iesire in sistem
title REVERS.ASM int 21h
; REVERS - permite inversarea ordinei caracterelor unui sir introdus de END START
7
Programul 4.5.
title NRBITI.ASM
; NRBITI - determina numarul bitilor care au valoarea 1 dintr-o zona de
; memorie
DOSSEG
.MODEL SMALL
.STACK 100h
.DATA
zona DW 1234h
.CODE
START:
mov ax, @DATA
mov ds, ax
mov cx, 8*SIZE zona ; Incarca CX cu numarul de biti
; dintr-un cuvint (16)
xor bx, bx ; BX = 0
clc ; CF = 0
mov ax, [zona] ; Incarca AX cu cantitatea din zona
bucla: rcl ax, 1 ; Bucla pentru calculul numarului de biti
; adc bx, 1
adc bx, 0 ; Reg. BX contorizeaza bitii 1 din
; cuvintul din zona
loop bucla
; sub bx, 8*SIZE zona
SF: mov ax, 4c00h ; Iesire in sistem
int 21h
END START
Modul de lucru
1. Se vor studia instrucþiunile de transfer al datelor.
2. Se vor edita, asambla ßi rula cele cinci programe prezentate.
3. Se vor obþine ßi analiza fißierele listing ßi de referinþe íncrucißate.
4. Se vor rula sub TD programele realizate ín modul pas cu pas.
5. Se va depana ßi apoi se va asambla ßi rula programul 4.3.

Conþinutul referatului
1. Listingurile programelor realizate.
2. Observaþiile ßi comentariile studentului.
8
b. Operatiile se executá cu operanzi pe 8 sau 16 biti, cu sau fárá semn.
Numerele fárá semn sunt interpretate ín notatie binará, iar numerele cu
semn, ín complement fatá de 2.
LUCRAREA NR. 5 c. Instructiunile ADD ßi SUB se utilizeazá pentru efectuarea
Grupul instrucþiunilor aritmetice. calculelor ín simplá precizie, adicá operanzii sunt reprezentati pe cite un
Grupul instrucþiunilor logice cuvänt. Dacá pentru reprezentarea operanzilor se utilizeazá mai multe
Scopul lucrárii cuvinte spunem cá avem o reprezentare multiplá precizie. Pentru
Lucrarea prezintá succint douá dintre grupurile de instructiuni ale efectuarea de calcule multiplá precizie se utilizeazá instructiunile ADC ßi
limbajului de asamblare al microprocesoarelor I8086/I8088 ßi anume SBB.
grupul instructiunilor aritmetice ßi grupul instructiunilor logice. Dupá o 1.1.2. Alte instructiuni ce au legaturá cu adunarea ßi scáderea binará
scurtá prezentare a sintaxei acestor instructiuni, urmeazá o serie de a) Instructiuni de incrementare ßi decrementare
exemple care sá evidentieze modul de utilizare al acestora. INC DST ; INCrement
1. Grupul instructiunilor aritmetice (DST) <---- (DST) + 1
1.1. Aritmetica binará Se aduná 1 la continutul singurului operand, rezultatul depunändu-se
1.1.1. Adunarea ßi scáderea binará ínapoi ín operand.
DEC DST ; DECrement
Instructiunile pentru adunarea ßi scáderea binará sunt urmátoarele:
(DST) <---- (DST) - 1
ADD DST, SRC ; (DST) <--- (DST) + (SRC)
Se scade 1 din continutul singurului operand, rezultatul depunändu-se
ADC DST, SRC ; (DST) <--- (DST) + (SRC) + (CF)
ínapoi ín operand. Forme de utilizare:
SUB DST, SRC ; (DST) <--- (DST) - (SRC) inc | dec R ; Se incrementeazá | decrementeazá continutul
SBB DST, SRC ; (DST) <--- (DST) - (SRC) - (CF) ; registrului general R unde R poate fi R8 sau R16
Pentru instructiunile ADD ßi ADC sunt permise urmátoarele tipuri inc | dec M ; Se incrementeazá | decrementeazá continutul
de operanzi: ; locatiei de memorie adresata prin M, unde M
add | adc R8, R8 ; R8 <--- R8 + R8 | + CF ; poate fi M8 sau M16.
add | adc R8, M8 ; R8 <--- R8 + M8 | + CF Observatii:
a. Instructiunile INC ßi DEC nu afecteazá flagul CF;
add | adc M8, R8 ; M8 <--- M8 + R8 | + CF
b. Instructiunile INC ßi DEC se executá modulo valoarea lui R sau M.
add | adc R16, R16 ; R16 <--- R16 + R16 | + CF
b) Instructiuni de negare
add | adc R16, M16 ; R16 <--- R16 + M16 | + CF
NEG DST ; NEGate
add | adc M16, R16 ; M16 <--- M16 + R16 | + CF DST <--- (DST)2 = - (DST)
add | adc R8, DATA8 ; R8 <--- R8 + DATA8 | + CF Schimbá semnul operandului DST, sau, altfel spus realizeazá
add | adc M8, DATA8 ; M8 <--- M8 + DATA8 | + CF complementarea aritmeticá a acestuia. Forme de utilizare:
add | adc R16, DATA16 ; R16 <--- R16 + DATA16 | + CF neg R ; Se schimbá semnul continutului registrului
add | adc M16, DATA16 ; M16 <--- M16 + DATA16 | + CF ; general R, unde R poate fi R8 sau R16
Observaþii: neg M ; Se schimbá semnul continutului locatiei de
a. Pentru instructiunile SUB ßi SBB sunt permise aceleaßi tipuri de ; memorie adresata prin M, unde M poate fi M8
operanzica ßi la instructiunile ADD ßi ADC; ; sau M16.
1
c) Instructiuni de comparare numere fárá semn. Forme de utilizare:
CMP DST, SRC ; CoMPare mul R8 ; (AH, AL) <--- AL * R8
(DST) - (SRC) mul M8 ; (AH, AL) <--- AL * M8
Se compará, prin scádere, continutul operandului sursá cu continutul mul R16 ; (DX, AX) <--- AX * R16
operandului destinatie, fárá modificarea operanzilor ßi fárá depunerea mul M16 ; (DX, AX) <--- AX * M16
rezultatului, dar cu pozitionarea corectá a indicatorilor de conditie. Sunt b) IMUL SRC; Integer MULtiply accumulator by register or memory
posibile urmátoarele forme de utilizare: Instructiunea IMUL are aceleaßi forme ca ßi instructiunea MUL,
cmp R8, R8 ; Se compará continutul a douá registre gnerale pe 8 biti deosebirea dintre cele douá instructiuni conständ ín faptul cá IMUL
cmp R16, R16 ; Se compará continutul a douá registre gnerale pe 16 opereazá asupra unor operanzi cu semn.
; biti c) DIV SRC ; DIVide, unsigned
cmp R8, M8 ; Se compará continutul unui registru gneral pe 8 biti cu Operandul deímpártit, adicá continutul registrului AX pe 16 biti
; continutul unei locatii de memorie adresatá prin M8 sau al perechii (DX, AX) pe 32 biti se ímparte la continutul operandului
cmp R16, M16; Se compará continutul unui registru gneral pe 16 biti sursá pe 8, respectiv16 biti, rezultatul depunändu-se ín registrului AL pe
; cu continutul unei locatii de memorie 8 biti sau AX pe 16 biti, iar restul ín registrul AH pe 8 biti, respectiv ín
cmp R8, DATA8 ; Se compará continutul unui registru pe 8 biti DX pe 16 biti. Operanzii sunt considerati numere fárá semn. Forme de
; cu un operad imediat pe 8 biti utilizare:
cmp R16, DATA16 ; div R8 ; AL <--- AX / R8 = cät ; AH <--- (AX) MOD (R8) = rest
cmp M8, DATA8 ; div M8 ; AL <--- AX / M8 = cät ; AH <--- (AX) MOD (M8) = rest
cmp M16, DATA16 ; div R16 ; AX <--- (DX,AX) / R16 = cät
Observatie: Instructiunnea CMP este urmatá, de obicei, de o instructiune ; DX <--- (DX, AX) MOD (R16) = rest
de salt conditionat, care testeazá bistabilii de conditie pentru a verifica div M16 ; AX <--- (DX,AX) / M16 = cät
dacá relatia din conditia testatá a fost satisfácutá. Starea bistabililor de ; DX <--- (DX, AX) MOD (M16) = rest
conditie trebuie interpretata diferit, dupá cum ceea ce se compará sunt b) IDIV SRC ; Integer DIVide, signed
numere fárá semn, sau numere cu semn. Astfel, dacá numerele sunt fárá Instructiunea IDIV are aceleaßi forme ca ßi instructiunea DIV,
semn: deosebirea dintre cele douá instructiuni conständ ín faptul cá IDIV
CF = 0 ßi ZF = 0, dacá (DST) > (SRC) opereazá asupra unor operanzi cu semn. Restul are acelaßi semn ca ßi
CF = 0 ßi ZF = 1, dacá (DST) = (SRC) deímpártitul.
CF = 1 ßi ZF = 0, dacá (DST) < (SRC) Observatie: Instructiunile de ínmultire ßi ímpártire sunt cele mai lente
Pentru numere cu semn: instructiuni executate de microprocesoarele I8086/I8088. Din acest
SF = OF, dacá (DST) > (SRC) motiv, ori de cäte ori este posibil, este de preferat ínlocuirea acestor
ZF = 1, dacá (DST) = (SRC) operatii prin secvente echivalente care sá foloseascá numai operatii de
SF ≠ OF, dacá (DST) < (SRC) adunare ßi de deplasare.

1.1.3. Inmultirea ßi ímpárþirea binará 1.1.4. Instrucþiuni pentru extinderea semnului operandului
a) MUL SRC; MULtiply accumulator by register or memory, unsigned Pentru a da posibilitatea efectuárii unor operatii de ímpártire IDIV
Continutul operandului sursá pe 8 sau 16 biti este ínmultit cu corecte, pentru "ajustarea" lungimii operanzilor (cu semn) se utilizeazá
continutul registrului AL sau AX, rezultatul pe 16 sau 32 biti fiind depus douá instructiuni pentru extinderea semnului operandului, astfel:
ín AX, respectiv ín perechea (DX, AX). Operanzii sunt considerati a) CBW ; Convert Byte to Word
2
Realizeazá conversia octetului cu semn continut ín registrul AL, ín 1.2.2. Aritmetica BCD neímpachetatá
cuväntul cu semn continut ín registrul AX prin extinderea bitului de O altá reprezentare a numerelor decät cea binará ßi ín cod BCD
semn al registrului AL la toti bitii registrului ímpachetat este reprezentarea ín cod BCD neímpachetat, continänd
AH, astfel: dacá AL7 = 0, atunci AH = 0, iar dacá AL7 = 1, atunci AH = numai o cifrá pe octet. Cifrá este continutá ín cei mai putin semnificativi
ffh. 4 biti ai octetului, restul bitilor neinfluentänd valoarea numárului
b) CWD ; Convert Word to Double word reprezentat. Cel mai uzual exemplu de reprezentare ín cod BCD
Realizeazá conversia cuväntului cu semn continut ín registrul AX, neímpachetat este codul ASCII ín care, pentru reprezentarea cifrelor, cei
ín dublul-cuvänt cu semn continut ín registrele (DX, AX) prin extinderea mai semnificativi 4 biti au valoarea 0011. La efectuarea operatiilor de
adunare, scádere, ínmultire ßi ímpártire cu operanzi ín format BCD
bitului de semn al registrului AX la toti bitii registrului DX, astfel: dacá
despachetat (ín cod ASCII) sunt necesare urmátoarele corectii, astfel:
AX15 = 0, atunci DX = 0, iar dacá AX16 = 1, atunci DX = ffffh.
a) AAA ; ASCII Adjust after Addition
Observatie: Instructiunile CBW ßi CWD nu afecteazá indicatorii de
Instructiunea realizeazá corectia zecimalá a rezultatului obtinut, ín
conditie. registrul AL, dupá adunarea a doi operanzi ín format BCD neímpachetat.
1.2. Aritmetica BCD Rezultatul corect, ín format BCD neímpachetat este depus ín registrele
1.2.1. Aritmetica BCD ímpachetatá AH ßi AL.
Reprezentarea ín cod BCD a numerelor íntregi presupune b) AAS ; ASCII Adjust after Subtraction
utilizarea unei codificári pe 4 biti a fiecárei cifre zecimale. Reprezentarea Instructiunea realizeazá corectia zecimalá a rezultatului obtinut, ín
BCD ímpachetatá realizeazá depunerea a douá cifre zecimale íntr-un registrul AL, dupá scáderea a doi operanzi ín format BCD neímpachetat.
acelaßi octet, fiecare grup de 4 biti ce codificá o cifrá numindu-se tetradá. Rezultatul corect, ín format BCD neímpachetat este depus ín registrele
Cum toate operatiile realizate de ALU-procesor se fac ín binar, obtinerea AH ßi AL.
unui rezultat BCD corect se face efectuänd anumite ajustári asupra c) AAM ; ASCII Adjust after Multiplication
rezultatului. Ajustárile se fac dupá efectuarea operatiilor respective. Instructiunea realizeazá corectia zecimalá a rezultatului obtinut, ín
Instructiunile de ajustare sunt urmátoarele: registrul AL, dupá ínmultirea a doi operanzi ín format BCD
a) DAA ; Decimal Adjust after Addition neímpachetat. Rezultatul corect, ín format BCD neímpachetat este depus
Instructiunea realizeazá corectia zecimalá a rezultatului obtinut, ín ín registrele AH ßi AL.
registrul AL, dupá adunarea a doi operanzi ín format BCD ímpachetat. d) AAD ; ASCII Adjust before Division
Rezultatul corect (ín format BCD ímpachetat) rámäne ín AL. Instructiunea realizeazá corectia zecimalá a deímpártitului ínaintea
b) DAS ; Decimal Adjust after Subtraction ímpártirii a doi operanzi ín format BCD neímpachetat. Ímpártirea se face
Instructiunea realizeazá corectia zecimalá a rezultatului obtinut, ín cu DIV, rezultatul din AL corectat, ín format BCD neímpachetat fiind
registrul AL, dupá scáderea a doi operanzi ín format BCD ímpachetat. depus ín registrele AH ßi AL.
Rezultatul corect (ín format BCD ímpachetat) rámäne ín AL.
2. Grupul instructiunilor logice
Observaþii:
a. Corectia rezultatului se face ín functie de valoarea bistabililor de 2.1. Instructiuni logice
conditie AF ßi CF. Microprocesorul I8086/I8088 poate realiza cinci instructiuni
b. Ín aritmetica BCD ímpachetatá nu se pot executa direct operatii de logice: NOT, AND, OR, XOR ßi TEST.
ínmultire ßi ímpartire. a) Instructiunea:
NOT DST ; Logical NOT
realizeazá negarea logicá (complementul fatá da 1) al operandului DST.
3
Forme de utilizare: _ Existá urmátoarele instructiuni de deplasare si de rotatie:
not R ; R <--- R_ unde R poate fi R8 sau R16 a) SHL DST, 1 ; Deplasare logicá stänga a operandului DST cu
not M ; M <--- M unde M poate fi M8 sau M16 ; 1 pozitii
b) Instructiunile SHL DST, CL ; Deplasare logicá stänga a operandului DST cu
; (CL) pozitii
AND DST, SRC ; (DST) <--- (DST) ∩ (SRC)
b) SHR DST, 1 ; Deplasare logicá dreapta a operandului DST cu
OR DST, SRC ; (DST) <--- (DST) ∪ (SRC)
; 1 pozitii
XOR DST, SRC ; (DST) <--- (DST) ∀ (SRC) SHR DST, CL ; Deplasare logicá dreapta a operandului
realizeazá operatiile logice SI, SAU ßi SAU EXCLUSIV, bit cu bit, íntre ; DST cu (CL) pozitii
continutul operandului sursá ßi continutul operandului destinatie, c) SAL DST, 1 ; Deplasare aritmeticá stänga a operandului DST
rezultatul depunändu-se ín destinatie, sursa nefiind afectatá. Pentru aceste ; cu 1 pozitii
instructiuni sunt permise urmátoarele tipuri de operanzi: SAL DST, CL ; Deplasare aritmeticá stänga a operandului DST
and | or | xor R8, R8 ; R8 <--- R8 ∩ ∪ ∀ R8 ; cu (CL) pozitii
and | or | xor R8, M8 ; R8 <--- R8 ∩ ∪ ∀ M8 d) SAR DST, 1 ; Deplasare aritmeticá dreapta a operandului
and | or | xor M8, R8 ; M8 <--- M8 ∩ ∪ ∀ R8 ; DST cu 1 pozitii
and | or | xor R16, R16 ; R16 <--- R16 ∩ ∪ ∀ R16 SAR DST, CL ; Deplasare aritmeticá dreapta a operandului
and | or | xor R16, M16 ; R16 <--- R16 ∩ ∪ ∀ M16 ; DST cu (CL) pozitii
and | or | xor M16, R16 ; M16 <--- M16 ∩ ∪ ∀ R16 e) ROL DST, 1 ; Rotire la stänga (cu carry) a operandului DST
and | or | xor R8, DATA8 ; R8 <--- R8 ∩ ∪ ∀ DATA8 ; cu 1 pozitii
ROL DST, CL ; Rotire la stänga (cu carry) a operandului DST
and | or | xor M8, DATA8 ; M8 <--- M8 ∩ ∪ ∀ DATA8
; cu (CL) pozitii
and | or | xor R16, DATA16 ; R16 <--- R16 ∩ ∪ ∀ DATA16
f) ROR DST, 1 ; Rotire la dreapta (cu carry) a operandului DST
and | or | xor M16, DATA16 ; M16 <--- M16 ∩ ∪ ∀ DATA16 ; cu 1 pozitii
Observatie: Dupá executia instructiunile AND, OR, XOR, íntotdeauna: ROR DST, CL ; Rotire la dreapta (cu carry) a operandului DST
CF = 0 , OF = 0. ; cu (CL) pozitii
c) Instructiunea: g) RCL DST, 1 ; Rotire la stänga prin carry a operandului DST
TEST DST, SRC ; TEST ; cu 1 pozitii
combiná proprietátile instructiunilor AND ßi CMP: ca ßi o instructiune RCL DST, CL ; Rotire la stänga prin carry a operandului DST
AND, TEST realizeazá operatia logicá SI íntre bitii corespunzátori ai ; cu (CL) pozitii
sursei ßi destinatiei, fárá ínscrierea rezultatului; ca ßi o instructiune CMP, h) RCR DST, 1 ; Rotire la dreapta prin carry a operandului DST
TEST pozitioneazá ín mod corespunzátor rezultatului obtinut bistabilii de ; cu 1 pozitii
conditie, cu exceptia flagurilor CF ßi OF care se pozitioneazá pe 0. RCR DST, CL ; Rotire la dreapta prin carry a operandului DST
; cu (CL) pozitii
2.1. Instructiuni logice pentru deplasare ßi rotatie Precizám cá operandul DST poate fi: R8, R16, M8, M16 . Cei opt operatori
Instructiunile de deplasare ßi rotatie lucreazá pe octeti sau cuvinte. de mai sus sunt Sugestiv prezentati ín Fig. 5.1.
Deplasarea (logicá sau aritmeticá) sau rotatia spre stänga sau spre dreapta Observaþii:
se poate efectua cu o singurá pozitie (un bit) sau cu un numár de pozitii a. Instructiunile de deplasare logicá ßi aritmeticá afecteazá toti indicatorii
(biti) specificat ín registrul CL. de conditie;
4
b. Instructiunile de rotire afecteazá numai fanioanele CF ßi OF. STIVA ENDS
ARITM SEGMENT
Operand DATA8 DB 8 DUP (78h)
a) SHL CF MSB LSB 0 Shift logical left
DATA16 DW 4 DUP (3456h)
START:
mov ax, cs ; Segmentele de date si cod sunt comune
b) SHR 0 MSB LSB CF Shift logical right mov ds, ax ; Incarca DS cu adresa de baza a
; sgmentului de date
mov ax, STIVA ;
c) SAL CF MSB LSB 0 Shift arithmetic left
mov ss, ax ;
sub ax, ax ; AX = 0
mov bx, ax ; BX = 0
d) SHR MSB LSB CF Shift arithmetic right mov cx, ax ; CX = 0
mov bp, ax ; BP = 0
add ax, 456 ; AX = 1c8h
sub ah, 3 ; AX = fec8h (CF=1, SF=1)
e) ROL CF MSB LSB Rotate left
sub DATA8, 78h ; (DATA8) = 0
sub DATA16[2], 78h ; (DATA16+3,DATA16+2) =
; 3456h - 78h = 33deh
f) ROR MSB LSB CF Rotate right inc bx ; BX = 1
inc cl ; CX = 1
dec ch ; CX = 0ff01h
inc DATA8[2] ; (DATA8+2) = 79h
g) RCL CF MSB LSB Rotate through carry left dec WORD PTR DATA8[bx-1]
; (DATA8+1, DATA8) = 7800h - 1 = 77ffh
dec ds : DATA16[bp+1]
h) RCR
; (DATA16+2, DATA16+1) = 0de34h - 1 = 0de33h
MSB LSB CF Rotate through carry right
mov [di], 258
mov al, DATA8[7] ; AL = 78h
mov ah, 0 ; AX = 0078h
Figura 5.1.
add al, 16h ; AX = 008eh
Exemplul 5.1.
daa ; Ax = 0094h (78 + 16 = 94)
title ARITM.ASM
sub al,77h ; AX = 001dh
; ARITM realizeaza operatiile aritmetice de adunare, scadere, inmultire
das ; AX = 0017h (94 - 77 = 17)
; si impartire, ajustarile zecimale si ASCII corespunzatoare
mov ax, 8 ; AX = 0008h
ASSUME cs:ARITM, ds:ARITM, ss:STIVA
STIVA SEGMENT STACK
add al, 9 ; AX = 0011h =17
DB 50 DUP (0)
aaa ; AX = 0107h
5
sub al, 8 ; AX = 01ffh n10 DW 10
aas ; AX = 0009h .CODE
; Inmultirea si impartirea START:
mov bl, 8 ; BL = 08h mov ax, @DATA
mul bl ; AX = 9*8 = 72 = 48h mov ds, ax
aam ; AX = 702h mov ax, w ; (AX) = w ; AX = 00c8h
aad ; AX = 48h = 72 sub ax, x ; (AX) <--- w - x ; AX = 0064h
mov bl, al ; BL = 48h cwd ; Se extinde semnul; AX = 0064h, DX = 0000h
add al, 7 ; AX = 4fh = 79 idiv n10 ; (AX) = (AX)/10; Citul = 000Ah --> AX;
div bl ; AX = 0701h (rest = 7 in AH, cit = 1 in AL) ; Restul = 0 --> DX
mov al, 20h ; AX = 0720h imul y ; (AX) = (AX)*y ; AX = fff6h, DX = ffffh
cbw ; DX = 0, AX = 0020h imul x ; (AX) <--- (AX)^2 ; AX = 0064h, DX = 0000h
mul DATA16[4] ; DX = 6h, AX = 8ac0h mov z, ax ; Rezultatul se depune in z
; (20h*3456h = 68ac0h) mov ax, 4c00h ; Iesire in sistem
add ax, 5 ; AX = 8ac5h int 21h
div DATA16[4] ; DX = 5h, AX = 20h (rest = 5 END START
; in DX, cit = 20h in AX)
mov ax, DATA16[6] ; AX = 3456h Exemplul 5.3
cwd ; DX = 0, AX = 3456h title SUMAT.ASM
div ax ; DX = 0, AX = 1 (rest = 0 in ; SUMAT realizeaza suma elementelor dintr-un tabel, folosind
; DX, cit = 1 in AX) ; operatorii generatori de valori: LENGTH, SIZE, TYPE
mov ax, 4c00h ; Iesire in sistem STIVA SEGMENT STACK
int 21h stivap DB 100 DUP (0)
ARITM ENDS STIVA ENDS
END START SUMAT SEGMENT
ASSUME cs:SUMAT, ds:SUMAT, ss:STIVA
Exemplul 5.2. TABEL DW 50 DUP (10h) ;
title ARIMT1.ASM START:
; ARITM1 realizeaza implementarea operatiilor z = ((w - x) / 10 * y)^2, mov ax, cs ; Segmentele de date si de cod sunt comune
; unde x, y, w, z sunt intregi, cu semn, reprezentate pe cite un octet mov ds, ax ; Se incarca registrul DS cu adresa de baza a
DOSSEG ; segmentului de date
.MODEL SMALL mov ax, STIVA
.STACK 10h mov ss, ax
.DATA sub ax, ax ; AX = 0
w DW 200 mov cx, LENGTH TABEL ; Incarca CX cu numarul de
x DW 100 ; elememte ale variabilei
y DW -1 ; TABEL (50)
z DW ?
6
mov si, SIZE TABEL ; Incarca SI cu numarul de octeti shr bx, 1 ; BX = 4000h
; ai variabilei TABEL (100) sar ax, cl ; AX = 0400h
NEXT: shr bx, cl ; BX = 0400h
sub si, TYPE TABEL ; Incarca SI cu 2 (datele din mov cl, 8 ; CL = 08h
; TABEL sunt de tip cuvint) mov dx, 7ah ; DX = 007ah
add ax, TABEL[si] ; rol dx, cl ; DX = 7a00h
loop NEXT ror dx, cl ; DX = 007ah
mov ax, 4c00h ror dx, cl ; DX = 7a00h
int 21h rcl dx, 1 ; DX = f400h (CF = 1)
SUMAT ENDS rcl dx, 1 ; DX = e800h
END START rcr dx, cl ; DX = 01e8h
xor dx, 0ffffh ; DX = fe17h
Exemplul 5.4. and dl, cl ;
title LOGIC.ASM or cl, dh ;
; LOGIC realizeaza operatiile logice AND, OR, XOR, TEST, deplasari test bx, dx
; logice si aritmetice, rotatii cu si fara bitul de transport. Deplasarile si mov ax, 4c00h ; Iesire in sistem
; rotatiile se pot executa la stinga sau la dreapta cu o pozitie sau cu un int 21h
; numar variabil de pozitii indicat de continutul registrului CL. LOGIC ENDS
ASSUME cs:LOGIC, ds:LOGIC, ss:STIVA END START
STIVA SEGMENT STACK
DB 100 DUP (0) Exemplul 5.5.
STIVA ENDS title MEDIEA.ASM
LOGIC SEGMENT ; MEDIEA calculeaza, prin intermediul unei proceduri, media aritmetica
START: ; a 8 numere intregi
mov ax, cs ; STIVA SEGMENT STACK
mov ds, ax ; Se incarca registrul DS cu adresa de DB 100 DUP (0)
; baza a segmentului de date STIVA ENDS
mov ax, STIVA ;
mov ss, ax ; DATA SEGMENT
mov bx, 101h ; BX = 0101h addate DW 8 DUP (?)
mov cl, 4 ; CL = 04h n1 DW 25
sal bl, cl ; BX = 0110h n2 DW 10
sal bx, cl ; BX = 1100h n3 DW 35
shl bh, cl ; BX = 1000h n4 DW 43
shl bx, 1 ; BX = 2000h n5 DW 57
mov ax, 8000h ; AX = 8000h n6 DW 21
mov bx, ax ; BX = 8000h n7 DW 111
shr ax, 1 ; AX = 4000h n8 DW 18
7
medie DW ? pop si ; Se reface din stiva continutul regisrelor
DATA ENDS pop cx ; utilizate de procedura c_medie
CODE SEGMENT pop ax
ASSUME cs:CODE, ds:DATA, ss:STIVA, es:PROCED SF: mov ax, 4c00h
START: int 21h
mov ax, DATA CODE ENDS
mov ds, ax PROCED SEGMENT
mov ax, PROCED ASSUME cs:PROCED, ds:DATA
mov es, ax c_medie PROC FAR
mov ax, STIVA xor si, si ; (SI) = 0
mov ss, ax xor ax, ax ; (AX) = 0
mov ax, n1 ; Se incarca zona de memorie addate cu bucla: add ax, ds:addate[si] ; In AX se calculeaza suma
mov addate, ax ; numerele a caror medie aritmetica se ; elementelor tabloului
;doreste a se calcula add si, 2
mov ax, n2 ; loop bucla
mov addate+2, ax ; mov cx, LENGTH addate
mov ax, n3 ; cwd
mov addate+4, ax ; idiv cx ; In AX se calculeaza media aritmetica
mov ax, n4 ; ret
mov addate+6, ax ; c_medie ENDP
mov ax, n5 ; PROCED ENDS
mov addate+8, ax ; END START
mov ax, n6 ;
mov addate+10, ax ; Modul de lucru
mov ax, n7 ;
1. Se vor studia instructiunile din grupul instructiunilor aritmetice si
mov addate+12, ax ;
logice.
mov ax, n8 ;
2. Se vor edita, asambla ßi rula cele cinci programe prezentate.
mov addate+14, ax ;
3. Se vor obtine ßi analiza fißierele listing ßi de referinte íncrucißate.
push ax ; Se salveaza in stiva continutul regisrelor
4. Se vor rula sub TD programele realizate ín modul pas cu pas.
push cx ; utilizate de procedura c_medie
5. Sa se scrie un program care sa realizeze suma si diferenta a doua
push si
numere reprezentate pe 32 biti.
mov cx, LENGTH addate ; Incarca in CX lungimea
6. Se va scrie un program pentru calculul lui n!, pentru n = 6.
; blocului de date
call FAR PTR c_medie ; Se apeleaza procedura de
Conþinutul referatului
; calcul a valorii medii
mov medie, ax ; Media aritmetica calculata este 1. Listingurile programelor realizate .
; depusa la adresa medie 2. Observaþiile ßi comentariile studentului.

8
; operatorul etichetá (eticheta a fost definitá ca
; FAR (instructiunea ocupá 5 octeti))
LUCRAREA NR. 6 2. JMP FAR PTR eticheta ; Salt direct inter-segment la operatorul
Grupul instrucþiunilor de salt. Instrucþiuni de buclare ; eticheta (eticheta a fost definitá ca NEAR
;in segmentul ín care se face saltul)
3. JMP DWORD PTR [pointer] ; Salt indirect inter-segment, adresa
Scopul lucrárii
;de salt (segment:offset), fiind specificatá
Lucrarea prezintá succint douá dintre grupurile de instrucþiuni ale ; prin conþinutul lui (pointer)
limbajului de asamblare al microprocesoarelor I8086/I8088 ßi anume
grupul instrucþiunilor de salt ßi grupul instrucþiunilor de buclare. Dupá o 1.2. Instrucþiuni de salt condiþionat
scurtá prezentare a sintaxei acestor instrucþiuni, urmeazá o serie de
exemple care sá evidenþieze modul de utilizare al acestora. Sunt Instructiunile de salt conditionat se folodesc, de obicei, ímpreuná
prezentate de asemenea ßi instrucþiunile pentru poziþionarea indicatorilor cu instructiunile de comparare (CMP DST, SRC), care determiná relatia
de condiþie. dintre douá numere. Ín prima etapá, instructiunea CMP executá o scádere
a celor douá numere (DST-SRC), fárá depunerea rezultatului, dar cu
Chestiuni teoretice modificarea corespunzátoare a fanioanelor de conditie conform operatiei
1. Grupul instrucþiunilor de salt efectuate. Ín a doua etapá, instructiunea de salt conditionat, testeszá
conditia specificatá (bistabilul de conditie), Fig. 6.1, efectuänd saltul
Instrucþiunile de salt se ímpart ín douá categorii: instrucþiuni de numai ín situatia ín care conditia este adeváratá, ín caz contrar trecänd la
salt necondiþionat ßi instrucþiuni de salt condiþionat. instructiunea urmátoare.

1.1. Instrucþiuni de salt necondiþionat


Existá urmatoarele instructiuni de salt neconditionat: NU DA
Conditie indeplinita ? Se executa
a) Intra-segment saltul
1. JMP SHORT eticheta ; Salt direct scurt intra-segment Executa instructiunea urmatoare IP <--- IP + DEPL8
2. JMP eticheta ; Salt direct intra-segment apropiat IP <--- IP +2
; (eticheta este definitá ín interiorul segmentului curent ca NEAR)
DEPL8 ∈ [-128, +127]
JMP NEAR etichetá; Salt direct apropiat intra-segment
Fig. 6.1
3. JMP R16 ; Salt indirect intra-segment la adresa de offset
; conþinutá ín registrul R16
Dacá se executá saltul, adresa efectivá de salt se determiná
4. JMP WORD PTR [pointer] ; Salt indirect intra-segment la
efectuänd suma dintre continutul actual al registrului IP si un
adresa de offset specificatá prin contextul lui (pointer)
deplasament cu semn pe 8 biti, care prin extindere de semn devine un
5. JMP eticheta [pointer] ; Salt indirect intra-segment la adresa de
deplasament pe 16 biti. Deoarece instructiunile de salt au o distantá de
; offset specificatá prin continutul unui TABLOU[pointer] salt limitatá de intervalul [-128, +127], saltul la o instructiune din afara
b) Inter-segment acestui domeniu se poate realiza prin efectuarea unui salt conditionat
1. JMP eticheta ; Salt direct índepártat (ín alt segment) la urmat de un salt neconditionat la instructiunea doritá.
1
Observaþie: Trebuie fácutá distinctia íntre "mai mare" ßi "mai mic" ín 12. JNBE / JA etichetá ; Jupm if not below nor equal / above
cazul numerelor cu semn ßi fárá semn. Astfel, dacá se compará douá ; Salt dacá DST SRC
numere cu semn, se folosesc termenii "less than" (mai mic decät) ßi c) Alte categorii
"greater than" (mai mare decät), iar dacá se compará douá numere fárá 13. JC etichetá ; Jump if carry set (CF = 1)
semn, se folosesc termenii "below" (inferior, sub) ßi "above" (deasupra, ; Salt dacá flagul CF nu a fost setat
peste, superior). 14. JNC etichetá ; Jump if no carry (CF = 0)
; Salt dacá flagul CF a fost setat
Existá urmátoarele instructiuni de salt conditionat: 15. JZ / JE etichetá ; Jupm if zero / equal (ZF = 1)
; Salt dacá DST = SRC
a) Pentru numere cu semn: 16. JNZ / JNE etichetá ; Jupm if not zero / not equal (ZF = 0)
1. JL / JNGE etichetá ; Jupm if less / not greater nor equal ; Salt dacá DST ÷ SRC
; Salt dacá DST < SRC
17. JP / JPE etichetá ; Jupm if parity / parity even (PF = 1)
2. JLE / JNG etichetá ; Jupm if less or equal / not greater
; Salt dacá paritate pará
; Salt dacá DST ≤ SRC 18. JNP / JPO etichetá ; Jupm if no parity / parity odd (PF = 0)
3. JNL / JGE etichetá ; Jupm if not less / greater or equal ; Salt dacá paritate impará
; Salt dacá DST ≥ SRC 19. JCXZ etichetá ; Jupm if CX = 0
4. JNLE / JG etichetá ; Jupm if not less nor equal / greater ; Salt dacá CX = 0
; Salt dacá DST > SRC
5. JO etichetá ; Jupm if overflow (OF = 0) 2. Instrucþiuni pentru controlul ciclurilor (Bucle)
; Salt dacá existá depáßire
6. JNO etichetá ; Jupm if no overflow (OF = 1) Existá urmátoarele instructiuni de buclare:
; Salt dacá nu existá depáßire 1. LOOP etichetá ; Loop until count complete
7. JS etichetá ; Jupm if sign (SF = 1) Se executá salt repetat la operandul etichetá atät timp cät
; Salt dacá numárul este negativ continutul registrului CX este nenul. Instructiunea functioneazá dupá
8. JNS etichetá ; Jupm if not sign (SF = 0) structura din Fig. 6.2.
; Salt dacá numárul este pozitiv
CX <--- CX - 1
b) Pentru numere fárá semn
Executa instructiunea DA NU Salt la eticheta
9. JB / JNAE / JC etichetá ; Jupm if below / not above nor equal / CX = 0
urmatoare IP <--- IP + DEPL8
; carry (CF = 1)
; Salt dacá DST < SRC Fig. 6.2.
10. JBE / JNA etichetá ; Jupm if below or equal / not above 2. LOOZ/LOOPE etichetá
; Salt dacá DST < SRC
11. JNB / JAE / JNC etichetá ; Jupm if not below / above or equal / Se executá salt repetat la operandul etichetá atät timp cät
; not carry (CF = 0) continutul registrului CX este nenul ßi indicatorul de conditie ZF = 1.
; Salt dacá DST ≥ SRC Instructiunea functioneazá dupá structura din Fig. 6.3.

2
; memorie si afisarea numarului continut in locatia de memorie
CX <--- CX - 1 respectiva
; (Daca numarul de afisat este mai mic decit 10 acesta se converteste in
DA NU ; ASCII si se afisaza. Daca numarul de afisat este mai mare sau egal ca
CX = 0 ; 10 se parcurge algoritmul procedurii ).
Executa instructiunea NU DA DOSSEG
ZF = 1
urmatoare .MODEL SMALL
Salt la eticheta .STACK 10h
IP <--- IP + DEPL8 .DATA
Fig. 6.3.
nr DW 65535 ; Numarul de afisat
3. LOONZ/LOOPE etichetá nr1 DW 0
Se executá salt repetat la operandul etichetá atät timp continutul n10 DW 10
registrului CX este nenul ßi indicatorul de conditie ZF = 0. Instructiunea .CODE
functioneazá dupá structura identicá cu cea din figura din Fig. 6.3, START:
singura diferentá fiind cá se testeazá ZF = 0 ín loc de ZF = 1. mov ax, @DATA
mov ds, ax ; Incarca DS cu adresa de baza a
3. Instructiuni pentru pozitionarea indicatorilor de conditie ; segmentului de date
mov si, OFFSET nr ; Incarca SI cu adresa de offset a
Ín aceastá categorie se íncadreazá instructiunile: ; numarului de afisat
CLC ; Clear Carry Flag (CF = 0) mov ax, [si] ; Continutul locatiei de afisat se
STC ; Set Carry Flag (CF = 1)
__ ; incarca in AX
CMC ; Complement Carry Flag (CF = CF ) call CONVERSIE
STD ; Set Direction Flag (DF = 1) jmp SF
CLD ; Clear Direction Flag (DF = 0) CONVERSIE PROC NEAR
STI ; Set Interrupt Flag (IF = 1); mov dx, 0 ; Extensie la 32 de biti
; Activeazá sistemul de íntreruperi div n10 ; Citul in AX, restul in DX
CLI ; Clear Interrupt Flag (IF = 0); cmp ax, 0 ; Citul = 0 ?
; Dezactiveazá sistemul de íntreruperi jz GATA
push dx ; Se salveaza in stiva restul
Ín continuare sunt prezentate cäteva exemple de utilizare a call CONVERSIE
pop dx ; Se reface restul din stiva
instructiunilor prezentate.
GATA:
Exemplul 6.1. mov al, dl ; AL se incarca cu cifra de afisat
add al, '0' ; Corectie ASCII
title CONVASC.ASM mov ah, 14 ; Functie BIOS pentru afisarea unui caracter
; CONVASC - rutina de conversie in ASCII a continutului unei locatii int 10h ; pe display cu pozitionarea cursorului
de ret
CONVERSIE ENDP
3
; bucla1: rcl ax, 1 ; Bucla pentru calculul numarului de biti
SF: mov ax, 4c00h ; Iesire in sistem
adc bx, 0 ; Reg. BX contorizeaza bitii 1 din
int 21h
; cuvintul incarcat in AX
END START loop bucla1
add si, TYPE zona ; Se formeaza adresa cuvintului urmator
Exemplul 6.2. cmp si, lzona ; S-au terminat toate cuvintele ?
title NRBITI1.ASM jnz bucla ; Se trece la cuvintul urmator
; NRBITI1 - determina numarul bitilor care au valoarea 1 dintr-o zona mov dx, OFFSET mes1; Se afisaza numarul de biti 1 din zona
de mov ah, 9
; memorie. Este prezentata utilizarea unor bucle incuibate, precum si a int 21h
; expresiilor this <tip> mov ax, bx
; call CONVERSIE
DOSSEG
.MODEL SMALL ; Se utilizeaza aceeasi zona de memorie, dar cu numele zonaq
.STACK 100h xor bx, bx ; BX = 0
.DATA xor si, si ; SI = 0
zonaq EQU this qword ; Zona poate fi referita si cu numele clc ; CF = 0
; zonaq si zonat buclaq: mov cx, 16
zonat EQU this tbyte mov ax, WORD PTR zonaq[si] ; Incarca AX cu primul
zona DW 1234h ; cuvint din zonaq
DW 5678h buclaq1: rcl ax, 1 ; Bucla pentru calculul numarului de biti
DW 2222h adc bx, 0 ; Reg. BX contorizeaza bitii 1 din
DW 1111h ; cuvintul incarcat in AX
DW 0 loop buclaq1
lzona EQU $-zona ; Lungimea zonei de memorie add si, TYPE zona
mes1 DB 13, 10, 'Numarul de biti 1 din zona = ', '$' cmp si, lzona
mes2 DB 13, 10, 'Numarul de biti 1 din zonaq = ', '$' jnz buclaq
mes3 DB 13, 10, 'Numarul de biti 1 din zonat = ', '$' mov dx, OFFSET mes2 ; Se afisaza numarul de
n10 DW 10 ; biti 1 din zonaq
.CODE mov ah, 9
START: int 21h
mov ax, @DATA mov ax, bx
mov ds, ax call CONVERSIE
xor bx, bx ; BX = 0 ; Se utilizeaza aceeasi zona de memorie, dar cu numele zonat
xor si, si ; SI = 0 xor bx, bx ; BX = 0
clc ; CF = 0
xor si, si ; SI = 0
bucla: mov cx, 8*TYPE zona ; Incarca CX cu numarul de biti clc ; CF = 0
; dintr-un cuvint (16) buclat: mov cx, 16
mov ax, zona[si] ; Incarca AX cu primul cuvint din zona
4
mov ax, WORD PTR zonat[si] ; Incarca AX cu primul title NFACT.ASM
; cuvint din zonat ; NFACT - calculeaza n! = 1.2.3...n ( n < 9 )
buclat1: rcl ax, 1 ; Bucla pentru calculul numarului de biti ;
adc bx, 0 ; Reg. BX contorizeaza bitii 1 din DOSSEG
.MODEL SMALL
; cuvintul incarcat in AX
.STACK 100h
loop buclat1
add si, TYPE zona .DATA
nr DW 8 ; Numarul al carui factorial se doreste a fi calculat
cmp si, lzona
jnz buclat n10 DW 10
mes1 DB 13, 10, 'n = ', '$'
mov dx, OFFSET mes3 ; Se afisaza numarul de
mes2 DB 13, 10, 'n! = ', '$'
; biti 1 din zonat
mov ah, 9 .CODE
START:
int 21h
mov ax, @DATA
mov ax, bx
call CONVERSIE mov ds, ax
mov dx, OFFSET mes1 ; Se afisaza n
jmp SF
mov ah, 9
;
CONVERSIE PROC NEAR int 21h
mov cx, WORD PTR [nr]
mov dx, 0 ; Extensie la 32 de biti
mov ax, cx
div n10 ; Citul in AX, restul in DX
cmp ax, 0 ; Citul = 0 ? call CONVERSIE
mov ax, 1
jz GATA
xor bx, bx ; BX = 0
push dx ; Se salveaza in stiva restul
call CONVERSIE bucla: inc bx ; Bucla pentru calculul lui n!
cmp bx, cx
pop dx ; Se reface restul din stiva
je ultima_inm
GATA: mov al, dl ; AL se incarca cu cifra de afisat
add al, '0' ; Corectie ASCII imul bx ; In AX se calculeaza n!
jmp bucla
mov ah, 14 ; Functie BIOS pentru afisarea unui
ultima_inm:
; caracter pe display
int 10h; ; imul bx
push ax
ret
mov dx, OFFSET mes2 ; Se afisaza n!
CONVERSIE ENDP
; mov ah, 9
SF: mov ax, 4c00h ; Iesire in sistem (DOS) int 21h
pop ax
int 21h
END START AFIS: call CONVERSIE
jmp SF
;
Exemplul 6.3. CONVERSIE PROC NEAR

5
mov dx, 0 ; Extensie la 32 de biti .CODE
div n10 ; Citul in AX, restul in DX START:
cmp ax, 0 ; Citul = 0 ? mov ax, @DATA
jz GATA mov ds, ax
push dx ; Se salveaza in stiva restul mov dx, OFFSET buffer ; Incarca DX cu offsetul bufferului
call CONVERSIE ; care va memora sirul
pop dx ; Se reface restul din stiva mov buffer, 17 ; Primul coctet din buffer
GATA: contine ; lungime_max = 17
mov al, dl ; AL se incarca cu cifra de afisat mov ah, 10 ; Functie DOS pentru citirea unui sir de caractere
add al, '0' ; Corectie ASCII ; de la tastatura pina la apasarea tastei ENTER.
mov ah, 14 ; Functie BIOS pentru afisarea ; Caracterele, incluzind si returul de car (CR),
; unui caracter pe display ; sunt memorate incepind cu octetul al treilea in
int 10h; ; ; bufferul specificat in DS:DX
ret int 21h
CONVERSIE ENDP xor bx, bx ; BX = 0
; mov bl, nr_caract_intr ; BL contine lungimea sirului
SF: mov ax, 4c00h ; Iesire in sistem (DOS)
mov buffer[bx+2], '$'
int 21h mov al, 80 ; Calcul numar siruri pe o linie-ecran
END START
cbw
div nr_caract_intr ; (AL) = de cite ori incape sirul pe linie
Exemplul 6.4. xor ah, ah ; (AH) = 0
title UMPLEECR.ASM mov siruri_pe_linie, ax
; UMPLEECR - realizeaza umplerea ecranului cu un sir de caractere mov cx, 24 ; Incarca CX cu numarul de linii-ecran
; introduse de la tastatura cu ecou afisare_ecran:
; push cx ; Salveaza in stiva numarul liniei curente
DOSSEG mov cx, siruri_pe_linie
.MODEL SMALL afisare_linie:
.STACK 100h mov dx, OFFSET sir
.DATA
buffer LABEL BYTE ; buffer este un alt nume pentru lung_max AFIS: mov ah, 9 ; Functie DOS de afisare a unui sir
lung_max DB ? ; Lungimea maxima a sirului introdus int 21h
nr_caract_intr DB ? ; Numarul caracterelor introduse de la loop afisare_linie
; tastatura ; mov dx, OFFSET crlf ; Se trece la afisarea liniei
sir DB 17 DUP (?) ; Tampon pentru 17 caractere (se ; urmatoare
; considera si un CR) ; mov ah, 9 ; OBS: Aceste instructiuni se utilizeaza
siruri_pe_linie DW 0 ; Numarul sirurilor care incap pe o linie ; int 21h ; numai daca numarul caracterelor afisate pe
ecran ; o linie este mai mic decit 80
pop cx ; Reface din stiva numarul liniei curente
crlf DB 0dh, 0ah, '$' loop afisare_ecran
6
SF: mov ax, 4c00h ; Iesire in sistem
int 21h
END START

Modul de lucru
1. Se vor studia instructiunile din grupul instructiunilor de salt ßi de
ciclare.
2. Se vor edita, asambla ßi rula cele patru programe prezentate in
exemplele anterioare.
3. Se vor obtine ßi analiza fißierele listing ßi de referinte íncrucißate.
4. Se vor rula sub TD programele realizate ín modul pas cu pas.
5. Sá se alcatuiascá un program pentru realizarea unei íntirzieri.
6. Sá se alcátuiascá un program pentru ordonarea sirului
"ahre25ruy9v07c23z9", sir care se aflá in segmentul de date la adresa
sir.
7. Sá se alcátuiascá un program care sá determine adresa primului octet
cu valoare diferitá de zero dintr-o zoná de memorie a cárei adresá de
ínceput se transmite ín registrul DI, iar adresa de sfirßit se transmite ín
registrul CX. Rezultatul rámäne ín registrul DI.
8. Sá se alcátuiascá un program care sá permitá afißarea pe ecran a unui
numár format din 16 cifre zecimale.

Continutul referatului
1. Listingurile programelor realizate la punctele 5, 6, 7 ßi 8 de la "Modul
de lucru".
2. Observaþiile ßi comentariile studentului.

7
2. STOSB (STOSW) DST ; Store String
Instrucþiunea memoreazá conþinutul registrului AL (AX) ín octetul
LUCRAREA NR. 7 (cuväntul) din ßirul destinaþie DST adresat prin ES:DI, cu actualizarea
corespunzátoare a registrului DI. Conþinutului registrului AL (AX) nu se
Grupul instrucþiunilor de lucru pe ßiruri de caractere
modificá.
Scopul lucrárii Exemplu:
STOSB ; Memoreazá continutul registrului AL la adresa
Lucrarea prezintá succint grupul de instrucþiuni pe ßiruri de ; ES:DI si incrementeaza continutul lui DI cu 1
caractere ale limbajului de asamblare al microprocesoarelor I8086/I8088. STOSW ; Memoreazá continutul registrului AX la adresa
Dupá o scurtá prezentare a sintaxei acestor instrucþiuni, urmeazá o serie ; ES:DI si incrementeaza continutul lui DI cu 2
de exemple care sá evidenþieze modul de utilizare al acestora.
3. MOVSB (MOVSW) DST, SRC ; Move String
Grupul instructiunilor pe ßiruri de caractere Transferá un octet (o pereche de octeþi) íntre ßirul sursá SRC
Pentru toate instrucþiunile pe ßiruri de caractere, se considerá cá adresat prin DS:SI ín octetul (perechea de octeþi) din ßirul destinaþie DST
ßirul sursá este conþinut ín segmentul curent de date (a cárui adresá de adresat prin ES:DI, cu actualizarea corespunzátoare a registrelor index SI
ínceput este conþinutá ín registrul DS), iar adresa relativá a ßirului ín ßi DI. Conþinutului ßirului sursá nu se modificá.
segment este conþinutá ín registrul SI. §irul destinaþie este conþinut ín
segmentul de date suplimentare (a cárui adresá de ínceput este conþinutá Observatie: Este clar cá ínaintea operatiei de transfer trebuie íncarcate ín
ín registrul ES), iar adresa relativá a ßirului ín segment este conþinutá ín registrele SI ßi DI adresele de ínceput ale celor douá ßiruri (sursá,
registrul DI. Pentru ßirul sursá se poate considera ßi alt registru de respectiv destinatie), iar ín CX numárul elementelor ce trebuie
segment utilizänd un prefix de registru adecvat. Flagul DF indicá sensul transferate. Pentru claritate prezentám urmátorul exemplu:
de parcurgere ín memorie al ßirurilor sau, altfel spus, modul ín care se ..................................
actualizeazá registrele SI ßi DI dupá execuþia operaþiei. Astfel, dacá mov ax, extra_sgm ; Se íncarcá registrul ES cu adresa de
flagul DF are valoarea zero, atunci se considerá cá ßirurile se vor mov es, ax ; bazá a segmentului de date suplimentare
parcurge de la adrese mici cátre adrese mari. Actualizarea registrelor SI mov si, OFFSET SRC
ßi DI se face prin incrementarea acestora cu 1 sau cu 2 dupá cum ceea ce mov di, OFFSET DST
se executá este o operatie care implicá un octet sau un cuvänt. Dacá mov cx, numar_elem
flagul DF are valoarea unu, atunci se considerá cá ßirurile se vor parcurge cld ; DF = 0 - ßirurile se vor parcurge ín sens crescátor
de la adrese mari cátre adrese mici. Actualizarea registrelor SI ßi DI se MUTA:movsb ; Transferul octetilor de la sursa SRC la
face prin decrementarea acestora cu 1 sau cu 2 dupá cum se executá o loop MUTA ; destinatiaDST se executá päná cänd CX = 0
operatie care implicá un octet sau un cuvänt. ....................................

Operaþiile elementare pe ßiruri de caractere sunt: 4. CMPSB (CMPSW) DST, SRC ; Compare Strings
Compará un octet (o pereche de octeti) din ßirul destinatie DST
1. LODSB (LODSW) SRC ; Load String adresat prin ES:DI cu octetul (perechea de octeþi) din ßirul sursá SRC
Instrucþiunea íncarcá fiecare octet (cuvänt) din ßirul sursá SRC adresat prin DS:SI, cu actualizarea corespunzátoare a registrelor SI ßi DI.
adresat prin DS:SI ín registrul AL (AX), cu actualizarea corespunzátoare Comparaþia se realizeazá prin scáderea octetului (cuväntului) sursá din
a registrului SI. Conþinutului ßirului sursá nu se modificá. octetul (cuväntul) destinaþie, fárá ínscrierea rezultatului, dar cu
poziþionarea indicatorilor de condiþie conform rezultatului obþinut. SCASB (SCASW) ßi CMPSB (CMPSW) la egalitatea a douá elemente.
Conþinutul celor douá ßiruri nu se modificá. Menþionám cá dupá fiecare execuþie a operaþiei elementare conþinutul
registrului CX este decrementat cu 1.
4. SCASB (SCASW) DST ; Scan String
Scaneazá ßirul destinaþie DST adresat prin ES:DI. Instrucþiunea Observatie: Tipul prefixului este semnificativ numai pentru operaþiile
poziþioneazá indicatorii de condiþie conform diferenþei dintre conþinutul SCASB (SCASW) ßi CMPSB (CMPSW). Pentru toate celelalte
registrului AL (AX) ßi octetul (perechea de octeþi) din ßirul destinaþie instrucþiuni pe ßiruri de elemente, toate prefixele au aceeaßi semnificaþie
DST fárá ínscrierea rezultatului ßi fárá modificarea conþinutului ca ßi prefixul REP.
registrului AL (AX) ßi a continutului ßirului. Se actualizeazá Prezentám ín continuare cäteva exemple de utilizare a
corespunzátoar registrelor DI. instrucþiunilor pe ßiruri de caractere:
Pentru repetarea operaþiile elementare pe ßiruri de caractere se por Exemplul 7.1.
utiliza urmátoarele prefixe (obþinänd astfel o instrucþiune cu opcod-ul pe title TRANSFB.ASM
2 octeþi): ; TRANSFB - transfera un bloc de date dintr-o zona de memorie in alta
1. REP - Se repetá operaþia care urmeazá päná cänd conþinutul ; zona de memorie
registrului CX devine zero (nu mai este nevoie de instrucþiunea LOOP ca DOSSEG
ín exemplul anterior). Precizám cá, dupá fiecare execuþie a operaþiei .MODEL SMALL
elementare, conþinutul registrului CX este decrementat cu 1. .STACK 100h
lung_bloc EQU 2000h
Exemplu: Dorim sá transferám 100 octeþi de la adresa DS:0200h la
.DATA
adresa DS:0300h. Secvenþa de instrucþiuni va fi urmátoarea:
bloc_sursa db 2000 dup(0)
mov ax, ds
bloc_dest db 2000 dup(?)
mov es, ax
.CODE
mov si, 200h
START:
mov di, 300h
mov ax, @DATA ; Incarca in AX adresa de baza a
mov cx, 100
mov ds, ax ; segmentului de date
cld
cld ; Sterge DF (DF = 0)
rep movsb
mov cx, lung_bloc ; Se incarca CX cu lungimea blocului de
2. REPZ, REPE - Se repetá operaþia care urmeazá päná cänd date
conþinutul registrului CX devine zero sau päná cänd indicatorul ZF mov si, OFFSET bloc_sursa ; Se incarca SI cu adresa de
devine zero. Indicatorul ZF este setat numai de cátre instrucþiunile ; inceput a blocului sursa
SCASB (SCASW) ßi CMPSB (CMPSW) la egalitatea a douá elemente. mov ax, SEG bloc_sursa ; Se incarca AX cu adresa de
Menþionám cá dupá fiecare execuþie a operaþiei elementare conþinutul ; segment e blocului
registrului CX este decrementat cu 1. mov ds, ax ; sursa, care se inscrie apoi inDS
mov di, OFFSET bloc_dest ; Se incarca DI cu adresa de
3. REPNZ, REPNE - Se repetá operaþia care urmeazá päná cänd
; inceput a blocului dest
conþinutul registrului CX devine zero sau päná cänd indicatorul ZF
mov ax, SEG bloc_dest ; Se incarca AX cu adresa de
devine unu. Indicatorul ZF este setat numai de cátre instrucþiunile
mov es, ax ; segment e blocului destinatie,
; care se inscrie apoi in ES inc dx ; In DX se contorizeaza numarul locatiilor diferite
trans: movsb ; Se realizeaza transferul octet cu octet ; dintre cele doua siruri
loop trans inc cx ;
mov ax, 4c00h ; Iesire in sistem loop compb
int 21h SF1: jz SF
END START inc dx
SF: mov ax, 4c00h ; Iesire in sistem
Exemplul 7.2. int 21h
title COMPAS.ASM END START
; COMPAS - compara doua siruri de octeti, numarul locatiilor diferite
; fiind contorizat in registrul DX Exemplul 7.3.
DOSSEG title COMPAS.ASM
.MODEL SMALL ; COMPAS - compara doua siruri de octeti, numarul locatiilor diferite
.STACK 100h ; fiind contorizat in registrul DX si apoi afisarea acestui numar
lungs EQU 100h ; lungs - lungimea sirurilor de comparat DOSSEG
.DATA .MODEL SMALL
bloc_sursa db lungs DUP (0) .STACK 100h
bloc_dest db lungs/4 DUP (1) .DATA
db lungs/4 DUP (0) lungs EQU 2000 ; lungs - lungimea sirurilor de comparat
db lungs/4 DUP (5) bloc_sursa db lungs DUP (0)
db lungs/4 DUP (0) bloc_dest db lungs/4 DUP (?)
.CODE db lungs/4 DUP (0)
START: db lungs/4 DUP (5)
mov ax, @DATA db lungs/4 DUP (0)
mov ds, ax n10 dw 10
mov ax, SEG bloc_sursa .CODE
mov ds, ax START:
mov si, OFFSET bloc_sursa mov ax, @DATA
mov ax, SEG bloc_dest mov ds, ax
mov es, ax mov ax, SEG bloc_sursa
mov di, OFFSET bloc_dest mov ds, ax
cld ; Sterge DF mov si, OFFSET bloc_sursa
mov cx, lungs ; Incarca CX cu lungimea sirurilor de mov ax, SEG bloc_dest
; comparat mov es, ax
compb: cmpsb ; Bucla pentru compararea sirurilor, octet cu octet mov di, OFFSET bloc_dest
loope compb cld ; Sterge DF
jcxz SF1 ; Daca CX = 0, operatia de comparare s-a terminat mov cx, lungs
xor dx, dx ;
ASSUME cs:STRING, ds:STRING, es:STRING, ss:STIVA
compb: cmpsb ; Bucla pentru compararea sirurilor, octet cu octet
STIVA SEGMENT STACK
loope compb
DB 50 DUP (0)
jcxz SF1 ; Daca CX = 0, operatia de comparare s-a terminat
STIVA ENDS
inc dx ; In DX se contorizeaza numarul locatiilor
STRING SEGMENT
; diferite dintre cele doua siruri
DESTINATIE DB 8 DUP (0)
inc cx
SURSA DB 8 DUP ('A')
loop compb
START:
SF1: jz AFIS
mov ax, cs ; Segmentele de date si cod sunt comune
inc dx
mov ds, ax ; Incarca DS cu adresa de baza a
; Se afißazá numárul de caractere diferite conþinut ín registrul DX
; segmentului de date
AFIS: mov ax, dx
mov es, ax ; Incarca ES cu adresa de baza a
call CONVERSIE
; segmentului de date
jmp SF
mov ax, STIVA ;
CONVERSIE PROC NEAR
mov ss, ax ;
mov dx, 0 ; Extensie la 32 de biti ;
div n10 ; Citul in AX, restul in DX mov di, OFFSET DESTINATIE
cmp ax, 0 ; Citul = 0 ? mov si, OFFSET SURSA
jz GATA mov cx, LENGTH SURSA ; AX = 8
push dx ; Se salveaza in stiva restul cld ; DF = 0
call CONVERSIE REP MOVSB ; (SURSA) <-- (DESTINATIE) in
pop dx ; Se reface restul din stiva ; sensul creßterii adreselor
GATA: std ; DF = 1
mov al, dl ; AL se incarca cu cifra de afisat mov al, 0 ; AL = 0
add al, '0' ; Corectie ASCII mov cx, 3 ; CX = 3
mov ah, 14 ; Functie DOS pentru afisarea dec di ; (DI) = DESTINATIE+8 - 1
int 10h ; unui caracter pe display REP STOSB ; DESTINATIE: 'A', 'A', 'A', 'A', 'A', 0, 0, 0
ret cld ; DF = 0
CONVERSIE ENDP mov cx, LENGTH SURSA ; CX = 8
SF: mov ax, 4c00h ; Iesire in sistem mov di, OFFSET DESTINATIE
int 21h REPNE SCASB ; Cauta 0 in sisul DESTINATIE
END START ; (ultimele 3 elemente sunt nule)
mov di, OFFSET DESTINATIE
Exemplul 7.4. mov si, OFFSET SURSA
title STRING.ASM mov cx, LENGTH SURSA ; CX = 8
; STRING ilustreazaa operatii cu siruri, folosind instructiuni repetitive REPE CMPS DESTINATIE, SURSA ; Compara sirul sursa
; realizate cu prefixele REP, REPE, REPNE ; cu sirul destinatie
mov ax, 5599h ; AX = 5599h mov ax, STIVA
REP STOSW ; (DI) = (DESTINATIE+10) mov ss, ax
std ; DF = 1 mov dx, OFFSET mes12 ; Se afisaza sirul initial
sub di, 2 mov ah, 9 ; Functie DOS de afisare a unui
mov cx, 3 ; sir terminat cu caracterul $
REP STOS WORD PTR DESTINATIE+8 int 21h
; (DESTINATIE+9,DESTINATIE+8) <-- 5599h... mov dx, OFFSET sir
mov ax, 4c00h ; Iesire in sistem mov ah, 9
int 21h int 21h
STRING ENDS mov dx, OFFSET crlf
END START mov ah, 9
int 21h
Exemplul 7.5. mov bx, 0ffffh ; BX = ffffh
title STRING1.ASM count: inc bx ; La prima incrementare BX = 0
; STRING1 opereaza asupra unui sir de caractere astfel: prima jumatate cmp BYTE PTR sir[bx], '$' ; Se testeaza sfirsitul de sir (ffh)
; a sirului este lasata nemodificata, iar a doua jumatate a sirului repeta jne count
; elementele din prima jumatate in ordine inversa, folosind o procedura mov ax, bx ; AX contine numarul de caractere din sir
; recursiva numita INV mov bl, 02 ;
; div bl ; Citul in AL, restul in AH
DATA SEGMENT
and al, al
term EQU 0ffh
jz STOP ; Sirul s-a terminat
sir DB 'ABCDEFGHIJKLMNOPRSTUVXZ', '$'
push ax ; Salveaza in stiva caracterele sirului
mes11 EQU 'Sirul initial: $'
xor si, si ; SI = 0
mes12 DB mes11
call INV ; Se apeleaza procedura de inversare
mes21 EQU 'Sirul final: $' ;
mes22 DB mes21 mov sir[si+1], '$'
crlf DB 0dh, 0ah, '$' mov dx, OFFSET mes22 ; Se afisaza sirul final
DATA ENDS mov ah, 9 ; Functie DOS de afisare a unui
; sir terminat cu caracterul $
STIVA SEGMENT STACK int 21h
DB 100 DUP(0)
mov dx, OFFSET sir
STIVA ENDS mov ah, 9
CODE SEGMENT int 21h
ASSUME cs:CODE, ds:DATA, ss:STIVA mov dx, OFFSET crlf
START: mov ah, 9
mov ax, DATA int 21h
mov ds, ax pop ax
STOP: lmes2 EQU $-mesaj2
mov ax, 4c00h ; Iesire in sistem r elem < > ; Memoreaza inregistrarea curent inserata
int 21h vect elem < '30', 'C' > ; Vectorul de inregistrari care trebuie sortat
elem < '20', 'B' >
INV PROC NEAR
elem < '40', 'D' >
mov bl, sir[si]
elem < '10' >
push bx ; Salveaza caracterele din prima jumatate a sirului
n EQU ($ - vect)/(TYPE elem) ; Se calculeaza numarul de
inc si
; elemente ale vectorului
dec al
lvect EQU $-vect
jz GATA
i DW ? ; Zona variabilelor din schema logica
call INV
j DW ?
GATA:
ind DB ?
and ah, ah ; ZF=1 daca numarul caracterelor din sir este par
k DW ?
jz impar ; Sirul are un numar impar de caractere
DATA ENDS
xor ah, ah ; Se sare caracterul din mijloc
inc si STIVA SEGMENT STACK
impar: pop bx ; Reface din stiva caracterele in ordine inversa DW 100h;
mov sir[si], bl STIVA ENDS
inc si
ret CODE SEGMENT 'CODE'
INV ENDP ASSUME cs:CODE, ds:DATA, ss:STIVA
begin: mov ax, DATA
CODE ENDS
mov ds, ax
END START
mov ax, STIVA
Exemplul 7.6. mov ss, ax
mov bx, 1 ; Se afisaza vectorul vect inainte de sortare
title SORTVECT.ASM mov cx, lmes1
; SORTVECT - sorteaza elementele unui vector de structuri de un mov dx, OFFSET mesaj1
; anumit tip mov ah, 40h ; Functie DOS de afisare a unui sir al carui
int 21h ; numar de caractere este specificat in registrul CX
DATA SEGMENT 'DATA'
mov bx, 1
elem STRUC
mov cx, lvect
cheie DW ?
mov dx, OFFSET vect
info DB 'A'
mov ah, 40h
elem ENDS
int 21h
mesaj1 DB "Structura vectorului vect inainte de sortare", 0dh, 0ah ;
lmes1 EQU $-mesaj1 lea bx, vect ; Registrul BX memoreaza adresa de
mesaj2 DB 0dh, 0ah, "Structura vectorului vect dupa sortare", 0dh, 0ah ; baza a vectorului vect
mov j, 2 mov [bx+di].cheie, ax
mov cx, TYPE elem ; Reg. CX memoreaza numarul de octeti mov al, [bx+si].info
; ai unui element al vectorului. Acest mov [bx+di].info, al
; numar este necesar pentru a se adresa dec i
;usor elementele vectorului cmp i, 0 ; Se testeaza daca mai sunt elemente de comparat
bucla: mov ax, j jne skip ; Daca da, in final se va relua corpul buclei
cmp ax, n ; Compara pe j cu n (n = nr. ele mov ind, 1 ; Altfel, se seteaza ind pentru iesirea din bucla
jng cont ; Daca j <= n, se continua secventa jmp skip
jmp STOP ; Altfel, programul se termina
etich1: mov ind, 1
cont: mov ax, j
skip: cmp ind, 1 ; Test de terminare bucla
dec ax
jne repeta
mov i, ax ; Atribuie lui i valoarea j-1
mov ax, i ; Se insereaza elementul curent pe pozitia i+1
mov ax, j
mul cx
dec ax
mov di, ax
mul cx
mov ax, r.cheie
mov si, ax
mov [bx+di].cheie, ax
mov ax, [bx][si].cheie
mov al, r.info
mov k, ax ; Incarca in k cheia a-j-a
mov [bx+di].info, al
mov r.cheie, ax ; Incarca in r al-j-lea element al vectorului
inc j ; Se incrementeaza j pentru adresarea
mov al, [bx][si].info
; elementului urmator
mov r.info, al
jmp bucla ; Reluarea buclei principale
mov ind, 0
STOP: nop
repeta: mov ax, i
mov bx, 1 ; Se afisaza vectorul vect dupa sortare
dec ax
mov cx, lmes2
mul cx
mov dx, OFFSET mesaj2
mov si, ax
mov ah, 40h
mov ax, [bx][si].cheie
int 21h
cmp k, ax ; Compara pe k cu continutul cheii a-j-a
mov bx, 1
jge etich1 ; Daca k >= kj, se iese din bucla si se seteaza
mov cx, lvect
; ind, altfel, se continua secventa
mov dx, OFFSET vect
mov ax, i ; Se deplaseaza elementul i pe pozitia i+1 in vector
mov ah, 40h
dec ax
int 21h
mul cx
mov ax, 4c00h ; Iesire in sistem
mov si, ax
int 21h
mov ax, [bx][si].cheie
CODE ENDS
mov di, si
END begin
add di, cx
7
Modul de lucru
1. Se vor studia instrucþiunile din grupul instrucþiunilor de lucru pe ßiruri
de caractere.
2. Se vor edita, asambla ßi rula cele ßase programe prezentate.
3. Se vor obþine ßi analiza fißierele listing ßi de referinþe íncrucißate.
4. Se vor rula sub CV sau TD programele realizate ín modul pas cu pas.
5. Sá se deducá schema logicá a programului din exemplul 7.6.
6. Sá se alcátuiascá un program pentru ordonarea sirului
"ahre25ruy9v07c23z9" care se aflá ín segmentul de date la adresa sir.
Sirul va fi afißat atät ín ordine directá cät ßi inversá.
7. Sá se alcátuiascá un program care sá ordoneze alfabetic (atät dupá
prima literá a numelui, cät ßi dupá prima literá a prenumelui) numele
studenþilor din subgrupa din care faceþi parte ßi apoi sá afißeze aceste
nume atät ín ordine directá cät ßi inversá.

Conþinutul referatului
1. Schema logicá a programului din exemplul 7.6.
2. Listingurile programelor realizate la punctele 6 ßi 7 de la "Modul de
lucru".
3. Observaþiile ßi comentariile studentului.

8
Exemplu:
mov dx, 14 ;
LUCRAREA NR. 8 in al, dx ; Citeßte octetul din portul cu numárul 14
Grupul instrucþiunilor de intrare/ießire. Instrucþiuni pentru mov dx, 5 ;
controlul íntreruperilor. Instrucþiuni pentru sincronizare externá in ax, dx ; Citeßte cuväntul din portul cu numárul 5
Observatii:
Scopul lucrárii 1. Numai primele 256 porturi pot fi specificate direct ín instructiune, ín
Lucrarea prezintá succint grupul instrucþiunilor de intrare/ießire, timp ce oricare din cele 2**16 porturi pot fi specificate indirect prin
instrucþiunile pentru controlul íntreruperilor ßi instrucþiunile pentru registrul DX.
sincronizare externá specifice microprocesoarelor I8086/I8088. Dupá o 2. Avantajul specificárii directe a portului constá ín aceea cá nu mai este
scurtá prezentare a sintaxei acestor instrucþiuni, urmeazá o serie de necesará executarea unei instructiuni suplimentare de íncárcare prealabilá
exemple care sá evidenþieze modul de utilizare al acestora. a numárului portului ín registrul DX.
3. Avantajul specificárii indirecte a portului constá ín aceea cá se pot
Chestiuni teoretice adresa (prin bucle) porturi cu adrese consecutive.
1. Instrucþiuni de intrare/ießire (I/O) Transmiterea unor date sau a unor comenzi se face prin
Accesul la interfetele corespunzátoare echipamentelor periferice se intermediul unor instructiuni de forma:
realizeazá prin intermediul unor instructiuni speciale. Fiecare interfatá a) OUT PORT, AL (AX) ; Output byte or word
are asociate un numár de coduri specifice numite porturi. Atribuirea b) OUT DX, AL (AX)
codurilor pentru fiecare interfatá se face la proiectarea sistemului de Efectul acestor instructiuni constá ín:
calcul. Comunicatia íntre microprocesor ßi mediul exterior reprezentat de a) Scrierea continutului registrului AL (AX) ín portul de adresá
interfetele de I/O se face prin executia unor instructiuni care adreseazá (cod) PORT specificat ín instructiune (PORT ∈ {0, 1, ..., 255} ).
aceste porturi. Un port este o valoare íntreagá reprezentatá pe 8 sau 16 b) Scrierea continutului registrului AL (AX) ín portul adresat indirect
biti. Citirea unor date sau informatii de stare se face prin intermediul prin continutul registrului DX.
unor instructiuni de forma: Exemple: out 49, al ; Se ínscrie octetul din AL ín portul 49
a) IN AL (AX), PORT ; Input byte or word out 15, ax ; Se ínscrie cuväntul din AX ín portul 15
b) IN AL (AX), DX Echivalentul acestor instructiuni, utilizänd ínsá registrul DX este
Forma a) poate fi utilizatá numai dacá portul PORT de intrare are urmátorul:
un cod mai mic decät 256 (PORT ∈ {0, 1, ..., 255} ) ßi este specificat mov dx, 49 ;
direct printr-un octet ín cadrul instructiunii. Efectul acestei instructiuni out dx, al ; Se ínscrie octetul din AL ín portul 49
constá ín íncárcarea valorii citite din PORT-ul specificat ín registrul AL mov dx, 15 ;
(AX). out dx, ax ; Se ínscrie cuväntul din AX ín portul 15
Exemplu: in al, 14 ; Citeßte octetul din portul cu numárul 14 Observatie: Comentariile de la instructiunea IN sunt valabile ßi pentru
in ax, 5 ; Citeßte cuväntul din portul cu numárul 5 instructiunea OUT.
Efectul executiei unei instructiuni de forma b) constá ín íncárcarea 2. Instrucþiuni pentru controlul íntreruperilor
valorii citite de la portul adresat indirect prin continutul registrului DX, Instructiunea
ín registrul AL (AX). INT n
1
unde n este un numár íntreg permite generarea unor íntreruperi software. Ín general legátura cu sistemul de operare (BIOS, DOS) de
Numárul n din instructiune reprezintá numárul nivelului de realizeazá utilizänd instructiuni de tip INT.
íntrerupereasociat semnalului de íntrerupere generat. Sunt posibile 256 Reíntoarcerea din procedurile de tratare a íntreruperilor se face cu
nivele de íntrerupere cuprinse íntre 0 ßi 255. ajutorul instructiunii IRET, plasatá la sfärßitul unei astfel de proceduri ßi
Pentru fiecare íntrerupere existá o procedurá specialá de tratare a care are ca efect refacerea valorilor registrelor IP ßi CS salvate anterior ín
acesteia. Efectul instructiunii INT n constá ín salvarea ín stivá a stivá, precum ßi starea indicatorilor de conditie salvati de asemenea ín
registrului indicatorilor de conditie F, a continutului registrelor CS ßi IP, stivá.
resetarea indicatorilor TF ßi IF ßi efectuarea saltului la adresa procedurii Pentru microprocesoarele I8086/I8088 o serie de nivele de
de tratare a íntreruperii, adresá memoratá pe 4 octeti la adresa specificá íntrerupere sunt asociate unor cauze specifice, astfel:
nivelului de íntrerupere. Adresa asociatá unui nivel de íntrerupere se - nivel 0: depaßire la ímpártire (ímpártire cu zero sau cu valori
obtine ínmultind cu 4 numárul n al nivelului de íntrerupere. Adresa de apropiate de zero);
segment pentru adresa asociatá unui nivel de íntrerupere este zero. - nivel 1: íntrerupere pentru executia programelor pas cu pas
Simbolic, cele spuse mai sus se scriu sub urmátoarea formá: (TF = 1);
SP <----- SP - 2 - nivel 2: íntrerupere nemascabilá (NMI);
(SP +1, SP) <----- F ; IF, TF <--- 0 - nivel 3: íntrerupere scurtá (breack point);
SP <----- SP - 2 - nivel 4: deepáßire superioará sau inferioará.
(SP +1, SP) <----- CS
Instructiunea INTO (Interrupt on Overflow) este o instructiune pe
SP <----- SP - 2
un octet care genereazá o íntrerupere de tipul 4, dacá bistabilul de
(SP +1, SP) <----- IP
conditie OF = 1. O astfel de instructiune ar trebui sá urmeze dupá fiecare
IP <----- (4 * n)
instructiune aritmeticá aplicatá unor operanzi cu semn ori de cäte ori
CS <----- (4 * n +2)
existá posibilitatea aparitiei unei depáßiri.
Adresele procedurilor de tratare a íntreruerilor sunt continute
Ín afara íntreruperilor software INT n prezentate, activitatea
íntr-un tabel cu 256 de intrári, fiecare intrare fiind pe 4 octeti. Tabelul
íncepe la adresa de memorie 0000:0000h, conform Fig. 8.1. procesorului poate fi íntreruptá ßi de un semnal extern ce se aplicá pe
pinul INTR al procesorului. Dacá indicatorul IT = 1, dupá terminarea
Adresa memorie Memorie executiei instructiunii curente, procesorul se opreßte din taskul sáu
0000: 0000 h obißnuit ßi se pregáteßte sá treacá la subrutina de tratare a íntreruperii
0000: 0001 h IP receptionate. Pentru ínceput, procesorul salveazá ín stivá toate
0000: 0002 h Intrerupere tip 0 informatiile importante despre taskul sáu (valorile curente ale
CS
0000: 0003 h indicatorilor de conditie ßi ale indicatorilor de stare, valorile curente ale
0000: 0004 h registrelor CS ßi IP), apoi va prelua de la dispozitivul (elementul) extern
0000: 0005 h
IP
Intrerupere tip 1 tipul íntreruperii ßi va trece la subrutina de tratare a acesteia. Orice
0000: 0006 h subrutiná de tratare a unei íntreruperi se termina cu instructiunea IRET.
CS
0000: 0007 h Dacá procesorul primeßte o íntrerupere pe pinul NMI atunci,
0000: 0008 h indiferent de valoarea lui IF, procesorul va executa aceleaßi operatii ca ßi
0000: 0009 h la o íntrerupere pe pinul INTR, cu singura deosebire cá nu mai este
nevoie sá se precizeze tipul íntreruperii deoarece, ín aceastá situatie, se
Fig. 8.1. genereazá o íntrerupere de tipul 2.
2
3. Instructiuni pentru sincronizare externá Procedura pentru controlul ceasului de timp real permite citirea,
Pentru sincronizarea cu evenimentele externe, microprocesoarele respectiv initializarea contorului de treceri prin procedura de tratare a
I8086/I8088 admit instructiunea íntreruperilor provenite de la ceasul de timp real.
HLT ; Halt
Prin executia acestei instructiuni, UCP-procesor intrá ín starea Pentru controlul ceasului de timp real se pot selecta urmatoarele
HALT. Efectul acestei instructiuni constá ín aceea cá oferá posibilitatea functii:
procesorului sá aßtepte sosirea unei íntreruperi care ar reprezenta Functia 0 - Citire contor.
realizarea unui eveniment ín proces. Ca rezultat al apelului acestei functii, registrul CX va contine
Ießirea din starea HALT se poate face prin íntreruperi de tip NMI, partea cea mai semnificativá, iar registrul DX va contine partea mai putin
íntreruperi pe pinul INTR cänd IF = 1, precum ßi prin semnalul hardware semnificativá a contorului. Registrul AL va contine valoarea
RESET = 1. indicatorului de depaßire a 24 de ore.
a). La aparitia unei íntreruperi, valorile curente ale indicatorilor de Functia 1 - Initializare contor:
conditie ßi ale indicatorilor de stare, precum ßi valorile curente ale Contorul se poate initializa ín modul urmator: cei mai
registrelor CS ßi IP sunt salvate ín stivá ßi procesorul trece la ßi executá semnificativi 2 octeti vor primi valoarea continutá ín registrul CX, iar cei
subrutina de tratare a íntreruperii respective. Cänd, ín aceastá subrutiná, mai putin semnificativi 2 octeti vor primi valoarea continuta ín registrul
procesorul íntälneßte instructiunea IRET, valorile lui IP, CS ßi registrului DX.
F sunt refácute din stivá, dupá care se va executa instructiunea care Observatie: Functiile 2 ÷ 7 sunt functii specifice sistemelor de tip
urmeazá imediat dupá HLT. AT, astfel:
b). Dacá din HALT se iese cu RESET = 1, atunci íntregul sistem
se initializeazá. Functia 2 - Citeßte timpul din contorul nevolatil (CMOS) al
Ínainte de a exemplifica modul de utilizare a instructiunilor ceasului de timp real.
anterioare, prezentám cäteva functii BIOS specifice controlului ceasului La ießire: Registrul CH - ora ín BCD;
de timp real. Registrul CL - ora ín BCD;
Registrul DH - ora ín BCD;
Controlul ceasului de timp real (INT 1AH) Flagul CF = 1 dacá ceasul nu este operational.
Pentru ceasul de timp real, BIOS-ul contine douá proceduri: una Functia 3 - Seteaza timpul ín contorul nevolatil (CMOS) al
pentru tratarea íntreruperilor provenite de la ceasul de timp real ßi alta ceasului de timp real.
accesibilá utilizatorilor pentru controlul ceasului de timp real. Procedura La intrare: Registrul CH, CL - ora ín BCD;
de tratare a íntreruperilor provenite de la ceasul de timp real este apelatá Registrul DH - secunde ín BCD;
de aproximativ 18,21 ori pe secundá. La fiecare apel al procedurii se Registrul DL = 1 pentru salvarea optiunii.
incrementeazá un contor format din 4 octeti a cárui adresa este 40H:6CH. Functia 4 - Citeste data din contorul nevolatil (CMOS) al ceasului
Contorul memoreazá numárul de treceri prin procedurá de lá ora de timp real.
00:00:00. De asemenea, aceastá procedurá verificá dacá contorul a ajuns La ießire: Registrul CH - secolul ín BCD;
la echivalentul a 24 ore. In acest ultim caz, contorul este reinitializat la 0 Registrul CL - anul ín BCD;
ßi la adresa 40H:70H se memoreazá valoarea 1 (ín mod normal, valoarea Registrul DH - luna ín BCD;
acestui octet este 0). Pentru fiecare apel al acestei proceduri se va apela Registrul DL - ziua ín BCD;
íntreruperea software INT 1CH. Flagul CF = 1 dacá ceasul nu este operational.
3
Functia 5 - Seteazá data ín contorul nevolatil (CMOS) al ceasului or al,1
de timp real. out 21h, al
La intrare: Registrul CH, CL - secolul ßi anul ín BCD; ; Stabileste legatura
Registrul DH, DL - luna ßi ziua ín BCD; push ds
push cs ; (DS:DX) = adresa inceput procedura
Exemplul 8.1. pop ds ; DS <-- CS
title INT1CH.ASM mov ax, 25h * 256 + nivel_1c
; INT1CH ilustreaza modul de tratare a intreruperii INT 1CH. Procedura mov dx, OFFSET tratare
; de tratare a intreruperii 1CH afiseaza de 5 ori caracerul 'A'. Programul int 21h ; Apel functie DOS (25H) pentru
; care ilusreaza utilizarea acestei proceduri afiseaza intr-o bucla 800 de ; stabilirea intreruperii pe nivel 1CH
; caractere '*'. La inceputul executiei sale, programul realizeaza legatura pop ds
; cu procedura definita de utilizator pentru INT 1CH, iar la sfirsitul ; Demascheaza intrerupere ceas
; executiei se va reface vechea adresa de tratare a intreruperii in al, 21h
.MODEL SMALL and al, 0feh
.STACK 10h out 21h, al
.DATA ret
int1c_ptr EQU THIS DWORD legatura ENDP
int9_ofs DW ?
; Procedura pentru tratare intrerupere 1CH
int9_seg DW ?
tratare PROC
nivel_1c EQU 1ch
push ax
.CODE
push bx
; Procedura pentru definirea unei proceduri de tratare a intreruperii
mov cx, 5
1CH
mov bh, 0 ; Pagina zero
legatura PROC iar: mov ax, 0e41h ; Afiseaza de 5 ori 'A' cu repozitionarea
; Salveaza vechea legatura ; cursorului
push ds int 10h
mov ax, 0 loop iar
mov ds, ax pop bx
mov bx, nivel_1c * 4 pop ax
mov ax, WORD PTR [bx] ; Adresa de offset iret
mov dx, WORD PTR [bx + 2] ; Adresa de segment tratare ENDP
pop ds
; Proceduda pentru refacerea vechii adrese pentru INT 1CH
mov int9_ofs, ax ; In int9_ofs se pastreaza adresa de offset
mov int9_seg, dx ; In int9_seg se pastreaza adresa de reface_legatura PROC
segment ; Mascheaza intrerupere ceas
; Mascheaza intrerupere ceas in al, 21h
in al, 21h or al,1
4
out 21h, al Exemplul 8.2.
push ds title BEEP.ASM
mov cx, WORD PTR int9_ofs ; BEEP prezinta un mod de programare a circuitului 8253 pentru a
mov dx, WORD PTR int9_seg ; permite emiterea unui semnal cu frecventa de 1000 Hz
mov ax, 0
STIVA SEGMENT STACK
mov ds, ax
DB 50 DUP (0)
mov bx, nivel_1c * 4
STIVA ENDS
mov WORD PTR [bx], cx ; Adresa in segment
CODE SEGMENT
mov WORD PTR [bx + 2], dx ; Adresa de segment
ASSUME cs:CODE, ds:CODE, ss:STIVA
pop ds
; Datele programului
; Demascheaza intrerupere ceas
timer EQU 40h
in al, 21h
portb EQU 61h
and al, 0feh
; Codul programului
out 21h, al
ret beep PROC
reface_legatura ENDP ; Programare contor
cli
BEGIN: mov ah, 35h ; Functia 35H determina adresa mov al, 0B6h ; Contor 2, LSB, MSB, binar
; dispozitivului curent de intrerupere out timer + 3, al
mov al, 1ch ; AL = numarul intreruperii mov ax, 533h ; Divizor pentru 1000 Hz
int 21h ; Acest apel DOS intoarce in ES:BX out timer + 2, al ; LSB
; pointerul catre rutina de tratare a mov al, ah
; intreruperii de la ceas out timer + 2, al ; MSB
call legatura ; Programare 8255 pentru a permite sunete
mov cx, 800 in al, portb ; Citeste starea circuitului 8255
mov bh, 0 ; Afisare in pagina 0 push ax ; Salvare stare 8255
bucla: mov ax, 0e2ah ; Se afiseaza 800 de asteriscuri or al, 3 ; Deschide generator de tonuri
int 10h out portb, al
loop bucla ; Bucla pentru intirziere
call reface_legatura xor cx, cx
cli b1: loop b1
mov ax,4c00h ; Iesire in sistem dec bl
int 21h jnz b1 ; Mai dureaza ?
END BEGIN ; Reface stare 8255
Observatie: Exemplele 8.2 si 8.3 prezinta un mod de programare a pop ax
circuitului 8253 in vederea emiterii unor semnale sonore out portb, al
sti
ret
5
beep ENDP out timer + 2, al ; MSB
START: ; Programare 8255 pentru a permite sunete
mov ax, CODE ; in al, portb ; Citeste starea circuitului 8255
mov ds, ax ; Incarca DS cu adresa de baza a push ax ; Salvare stare 8255
; segmentului de date or al, 3 ; Deschide generator de tonuri
mov ax, STIVA ; out portb, al
mov ss, ax ; ; Bucla pentru intirziere
mov bl, 3 xor cx, cx ; CX = 0
call beep b1: add cx, 0
nop loop b1
; Sfirsit executie program dec bl
mov ax, 4c00h ; Iesire in sistem jnz b1 ; Mai dureaza ?
int 21h ; Reface stare 8255
CODE ENDS pop ax
END START out portb, al
ret
Exemplul 8.3. beep ENDP
title SUNETE.ASM ; Procedura pentru generarea de tonuri
; SUNETE produce prin intermediul circuitului 8253 semnale sonore ce ; (DH) = numar de tonuri lungi
; pot fi utilizate in anumite teste ; (DL) = numar de tonuri scurte
sunet PROC
STIVA SEGMENT STACK cli ; Dezactiveaza sistem de intreruperi
DB 50 DUP (0) or dh, dh ; Exista tonuri lungi ?
STIVA ENDS jz s3 ; Nu exista tonuri lungi
CODE SEGMENT ; Generare tonuri lungi
ASSUME cs:CODE, ds:CODE, ss:STIVA s1: mov bl, 50 ; Contor beep-uri
; Datele programului call beep
timer EQU 40h s2: loop s2 ; Intirziere
portb EQU 61h dec dh ; Mai sunt tonuri lungi ?
; Codul programului jnz s1
; ; Generare tonuri scurte
beep PROC s3: or dl, dl ; Exista tonuri scurte ?
; Programare contor jz s6 ; Nu exista tonuri scurte
mov al, 0B6h ; Contor 2, LSB, MSB, binar s4: mov bl, 10 ; Contor beep-uri
out timer + 3, al call beep
mov ax, 533h ; Divizor pentru 1000 Hz s5: loop s5 ; Intirziere
out timer + 2, al ; LSB dec dl ; Mai sunt tonuri scurte ?
mov al, ah jnz s4
6
s6: sti out timer + 3, al
ret ; Programare 8255 pentru a permite sunete
sunet ENDP in al, portb ; Citeste starea circuitului 8255
START: push ax ; Salvare stare 8255
mov ax, CODE ; or al, 3 ; Deschide generator de tonuri
mov ds, ax ; Incarca DS cu adresa de baza a out portb, al
; segmentului de date ; Citeste valoare curenta ceas
mov ax, STIVA ; mov ah, 0
mov ss, ax ; int 1ah ; Apel BIOS pentru citire ceas
mov dx, 3 * 256 + 5 ; 3 tonuri lungi si 5 scurte mov bx, dx ; Salvare valoare low ceas
call sunet iar1: lodsw ; Incarca in AX frecventa curenta
nop out timer + 2, al ; LSB
; Sfirsit executie program xchg al, ah
mov ax, 4c00h ; Iesire in sistem out timer + 2, al ; MSB
int 21h add bx, 1
CODE ENDS ; Bucla pentru intirziere
END START iar2:
; Citeste valoare curenta ceas
Exemplul 8.4. mov ah, 0
title CINTEC.ASM int 1ah ; Apel BIOS pentru citire ceas
; CINTEC produce semnale sonore ce pot fi organizate ca o melodie. cmp bx, dx ; S-a schimbat ?
; Precizam ca declansarea generatorului de tonuri se realizeaza sub jnz iar2 ; Daca nu, se mentine intirzierea
; controlul ceasului de timp real dec di ; Mai sunt note ?
; jnz iar1
STIVA SEGMENT STACK ; Reface stare 8255
DB 50 DUP (0) pop ax
STIVA ENDS out portb, al
CODE SEGMENT ret
ASSUME cs:CODE, ds:CODE, ss:STIVA melodie ENDP
; Procedura pentru interpretarea unei melodii ;
; La apel: (SI) = adresa unde incepe descrierea melodiei START: mov ax, CODE ;
; (DI) = numar de note muzicale mov ds, ax ; Incarca DS cu adresa de baza a
timer EQU 40h ; segmentului de date
portb EQU 61h mov ax, STIVA ;
; mov ss, ax ;
melodie PROC mov si, OFFSET cintecel ; Adresa de inceput a melodiei
; Initializare mod de lucru contor mov di, sfirsit_cintecel / 2 ; Numar frecvente
mov al, 0B6h ; Contor 2, LSB, MSB, binar call melodie
7
nop
; Sfirsit executie program
mov ax, 4c00h ; Iesire in sistem
int 21h
cintecel LABEL WORD
dw 0852, 0852, 0002, 0002, 0903, 0903, 0002, 0002, 0957, 0957, 0903, 0903
dw 0957, 0957, 1013, 1013, 1074, 1074, 0002, 0002, 1138, 1138, 0002, 0002
dw 1205, 1205, 1205, 1205, 1138, 1138, 1138, 1138, 1013, 1013, 0002, 0002
dw 1074, 1074, 0002, 0002, 1138, 1138, 1074, 1074, 1138, 1138, 1205, 1205
dw 1277, 1277, 0002, 0002, 1353, 1353, 0002, 0002, 1433, 1433, 1433, 1433
dw 1353, 1353, 1353, 1353, 1138, 1138, 0002, 0002, 1518, 0002, 1518, 0002
dw 1609, 1609, 1609, 1609, 1518, 1518, 1518, 1518, 1138, 1138, 0002, 0002
dw 1518, 0002, 1518, 0002, 1609, 1609, 1609, 1609, 1518, 1518, 1518, 1518
dw 1806, 1806, 1704, 1704, 1609, 1609, 1518, 1518, 1433, 1433, 1353, 1353
dw 1277, 1277, 1205, 1205, 1138, 1138, 0002, 0002, 1074, 1074, 0002, 0002
dw 1013, 1013, 0002, 0002, 0903, 0903, 0002, 0002, 0852, 0852, 0852, 0852
dw 0852, 0852, 0852, 0852, 0002, 0002
sfirsit_cintecel EQU $ - cintecel
CODE ENDS
END START

Modul de lucru
1. Se vor studia instrucþiunile din grupul instrucþiunilor de intrare/ießire,
instrucþiunle pentru controlul íntreruperilor, instrucþiunile pentru
sincronizare externá, precum ßi funcþiile BIOS specifice controlului
ceasului de timp real.
2. Se vor edita, asambla ßi rula cele patru programe prezentate.
3. Se vor obþine ßi analiza fißierele listing ßi de referinþe íncrucißate.
4. Se vor rula sub CV sau TD programele realizate ín modul pas cu pas.
5. Sá se alcátuiascá un program care sá permitá afißarea datei ßi a orei
curente.

Conþinutul referatului
1. Listingurile programelor realizate la punctul 5 de la "Modul de
lucru".
2. Observaþiile ßi comentariile studentului.

8
Ín tabelul 9.1 sunt prezentate codurile modurilor de lucru ßi
caracteristicile acestora.
LUCRAREA NR. 9 Tabelul 9.1.
Utilizarea funcþiilor BIOS Cod Mod Coloane Linii Culori Tip interfata
0 alfanumeric 40 25 16 / 8 * CGA, EGA, VGA
Scopul lucrárii
1 alfanumeric 40 25 16 / 8 CGA, EGA, VGA
Se va prezenta modul ín care se pot utiliza, din programe utilizator,
2 alfanumeric 80 25 16 / 8 * CGA, EGA, VGA
principalele puncte de intrare în BIOS. Selecþia funcþiei solicitate pentru
fiecare punct de intrare (fiecare tip de íntrerupere), se face pe baza 3 alfanumeric 80 25 16 / 8 CGA, EGA, VGA
conþinutului registrului AH. 4 grafic 320 200 4 CGA, EGA, VGA

1. Utilizarea terminalului grafic (INT 10H) 5 grafic 320 200 4 * CGA, EGA, VGA
6 grafic 640 200 2 CGA, EGA, VGA
Terminalul grafic poate sá lucreze ín douá categorii de moduri de
lucru: moduri de lucru alfanumerice ßi moduri de lucru grafice. 7 alfanumeric 80 25 3 MA, EGA, VGA
Modurile de lucru alfanumerice sunt caracterizate de numárul de 13 grafic 320 200 16 EGA, VGA
linii-caracter, numárul de coloane-caracter, atributele de culoare 14 grafic 640 200 16 EGA, VGA
disponibile ßi numárul de pagini. Numerotarea linilor íncepe cu 0, pentru 15 grafic 640 350 3 EGA, VGA
linia din partea superioará a ecranului, iar numerotarea coloanelor începe
16 grafic 640 350 16 sau 4 EGA, VGA
tot cu 0, pentru coloana din stänga ecranului.
Pentru modurile de lucru alfanumerice, un caracter este specificat 17 grafic 640 480 2 VGA
prin codul ASCII ßi atributul de culoare utilizat. Atributul de culoare 18 grafic 640 480 16 VGA
conþine trei elemente: cei mai puþin semnificativi 4 biþi reprezintá codul 19 grafic 640 480 256 EGA, VGA
pentru culoarea cu care se scrie caracterul, urmátorii 3 biþi reprezintá * - pentru CGA 2 culori
culoarea fondului pe care se scrie caracterul, iar bitul cel mai Dacá interfaþa utilizatá este de tip EGA sau VGA, atunci adáugänd
semnificativ comandá afißarea continuá sau intermitentá (blinking) a valoarea 80H la codul modului selectat, comutarea de mod se face fárá
caracterului. ßtergerea ecranului.
Deoarece pentru modurile de lucru alfanumerice capacitatea Funcþia 1 - Selecþie formá ßi dimensiune cursor.
memoriei ecran este mai mare decät cea necesará, aceasta este organizatá
Cursorul are forma unui dreptunghi de láþimea unui caracter avänd
pe pagini, fiecare paginá putänd sá memoreze imaginea unui ecran.
lungimea maximá egalá cu aceea a unui caracter. Numárul liniei
Modurile de lucru grafice sunt caracterizate de numárul de linii,
inferioare (valoarea minimá 0) se transmite ín registrul CH, numárul
numárul de coloane ßi culorile disponibile. Ín acest caz numárul de linii
liniei superioare (depinde de modul de lucru) se transmite ín registrul CL.
ßi coloane se referá la puncte. Coordonatele punctului aflat în colþul din
Dacá numárul liniei inferioare este mai mare decät numárul liniei
stänga sus al ecranului sunt (0, 0).
superioare, atunci cursorul va fi format din douá jumátáþi neadiacente.
Pentru utilizarea terminalului grafic se pot selecta urmátoarele
Funcþia 2 - Poziþionare cursor pe ecran.
funcþii:
Conþinutul registrului DH reprezintá numárul liniei-caracter, iar
Funcþia 0 - selecþie mod de lucru pentru terminalul grafic.
conþinutul registrului DL reprezintá numárul coloanei-caracter pe care va
Conþinutul registrului AL precizeazá modul de lucru care se selecteazá.
1
fi poziþionat cursorul pentru pagina al cárui numár este conþinut ín Funcþia 8 - Citire caracter de pe ecran.
registrul BH (pentru modurile de lucru grafice acest numár de paginá este Aceastá funcþie realizeazá citirea caracterului aflat pe ecran în dreptul
zero). cursorului. Pentru modurile de lucru alfanumerice registrul BH va
Funcþia 3 - Citire coordonate cursor. conþine numárul paginii referite. Codul ASCII al caracterului se obþine în
Numárul paginii din care se citeßte poziþia cursorului este conþinut ín registrul AL. Pentru modurile alfanumerice ín registrul AH se va obþine
registrul BH. Rezultatul se preia ín registrele (DH,DL) - linie, coloaná ßi atributul de culoare utilizat pentru afißarea caracterului.
(CH,CL) - fomá cursor. Funcþia 9 - Afißare caractere pe ecran.
Funcþia 4 - Citire poziþie indicator optic (light pen) . Poziþia de început pentru afißare este poziþia curentá a cursorului. Pentru
Dacá la reíntoarcerea din execuþia acestei funcþii conþinutul registrului modurile de lucru alfanumerice registrul BH va conþine numárul paginii
AH este 0 ínseamná cá nu s-a solicitat o poziþionare a indicatorului optic. unde se face afißarea. Caracterul care se utilizeazá pentru afißare este
Dacá conþinutul registrului AH este 1, atunci poziþia indicatorului optic transmis în registrul AL, numárul de repetári pentru acest caracter este
este specificatá atät ca poziþie-caracter (conþinutul registrelor (DH,DL) transmis în registrul CX. Pentru modurile de lucru alfanumerice registrul
specificá numárul liniei-caracter, respectiv numárul coloanei-caracter), BL va conþine atributul de culoare utilizat. Pentru modurile de lucru
cät ßi ca poziþie-punct (conþinutul registrelor (CH,BX) specificá numárul grafice registrul BL va conþine culoarea utilizatá pentru afißare. Poziþia
liniei, respectiv numárul coloanei punctului specificat). Precizia indicárii cursorului nu se modificá ca urmare a execuþiei acestei funcþii.
este ínsá la nivelul dimensiunii unui caracter, indiferent de modul de Funcþia 10 - Înlocuire caractere pe ecran cu pástrarea
lucru al terminalului grafic. caracteristicilor de culoare.
Funcþia 5 - Selecþie paginá-ecran activá. Poziþia de început pentru înlocuire este poziþia curentá a cursorului.
Pagina-ecran activá este pagina afißatá pe ecran. Aceastá funcþie are Aceastá funcþie este similará cu funcþia 9, cu singura deosebire cá
semnificaþie numai pentru modurile de lucu alfanumerice deoarece, ín atributele de culoare utilizate pentru caracterele care se afißeazá se preiau
modul de lucru grafic existá o singurá paginá-ecran. Numárul paginii de la caracterele afißate pe ecran ßi pe care noul ßir le înlocuießte.
selectate este transmis ín registrul AL. Funcþia 11 - Fixare caracteristici de culoare.
Funcþia 6 - Execuþie operaþie "scroll up". Aceastá funcþie are semnificaþie numai pentru modul de lucru 4 (grafic
Pentru aceastá funcþie se realizeazá defilarea ín sus a imaginii conþinute 320x200 color) . Funcþia poate sá fie utilizatá pentru fixarea culorii care
íntr-o fereastrá ín cadrul paginii-ecran active, cu un numár de linii se va utiliza pentru fundal (dacá conþinutul registrului BH este 0) sau
conþinut ín registrul AL. Limitele ferestrei ín care se face deplasarea sunt pentru specificarea paletei de culori disponibile (dacá registrul BH este
specificate prin poziþia colþului stänga sus al ferestrei (registrele (CH,CL) 1). În cazul în care se realizeazá specificarea culorii pentru fundal,
specificá numárul liniei, respectiv numárul coloanei) ßi poziþia colþului registrul BL va conþine codul culorii. În cazul în care funcþia este
dreapta jos al ferestrei (registrele (DH,DL) specificá numárul liniei, utilizatá pentru fixarea paletei de culori atunci, dacá conþinutul registrului
respectiv al coloanei). Ín registrul BH se specificá atributul de culoare cu BL este par se va selecta paleta: verde, roßu, cafeniu (reprezentänd
care se formeazá liniile care se introduc ín partea inferioará a ferestrei. culorile 1,2,3), altfel se va selecta paleta: turcoaz, purpuriu, alb
Dacá numárul de linii specificat pentru deplasare (conþinutul registrului (reprezentänd culorile 1,2,3).
AL) este 0 atunci se va face o ßtergere a ferestrei utilizänd atributul Funcþia 12 - Afißarea unui punct pe ecran.
specificat în registrul BH. Aceastá funcþie are semnificaþie numai pentru modurile de lucru grafice.
Funcþia 7 - Execuþie operaþie "scroll down". Poziþia punctului pe ecran este specificatá prin numárul liniei (registrul
Pentru aceastá funcþie se realizeazá defilarea ín jos a imaginii conþinute DX) ßi numárul coloanei (registrul CX). Codul culorii utilizate pentru
íntr-o fereastrá ín cadrul paginii active. Semnificaþia conþinutului afißare este specificat în registrul AL. Dacá bitul cel mai semnificativ al
registrelor este aceeaßi ca ßi ín cazul funcþiei anterioare. registrului AL este 1 atunci se va executa un "sau exclusiv" între culoarea
2
punctului curent afißat pe ecran ßi noua culoare. Registrul BH conþine Structura octetului care codifica culorile de afisare este:
numárul paginii video.
Funcþia 13 - Citire culoare punct de pe ecran. B F F F C C C C
Aceastá funcþie are semnificaþie decät pentru modurile de lucru grafice.
Poziþia punctului pe ecran este specificatá prin numárul liniei (registrul unde: B - indicá afißare continuá (B = 0), sau intermitentá (B =
DX) ßi numárul coloanei (registrul CX). Codul culorii punctului se obþine 1);
în registrul AL. Registrul BH conþine numárul paginii video. FFF - indicá codul culorii utilizate pentru fundal;
Funcþia 14 - Afißare caracter pe ecran cu actualizare poziþie CCCC - indicá codul culorii utilizate pentru pentru afißarea
cursor. caracterului..
Afißarea caracterului se face pe poziþia curentá a cursorului dupá care Talelul 8.2 descrie culorile standard pentru o interfaþá CGA.
cursorul este deplasat la dreapta cu o poziþie pe linia curentá,
executändu-se, eventual, trecerea pe linia urmátoare dacá se depáßeßte Tabelul 8.2.
lungimea liniei, respectiv executänd o deplasare în sus dacá se depáßeßte Nume culoare Cod culoare Nume culoare Cod culoare
dimensiunea unei pagini. Caracrerul care se afißeazá se transmite în Black 0 Dark Gray 8
registrul AL. Dacá modul curent de lucru este grafic, culoarea utilizatá
pentru caracter este specificatá în registrul BL. O serie de caractere Blue 1 Light Blue 9
speciale sunt interpretate direct ín cadrul executárii acestei funcþii. Aceste Green 2 Light Green 10
caractere sunt: "bell" - (7), "backspace" - (8), "line feed" - (10) ßi Cyan 3 Light Cyan 11
"carriage return" - (13).
Red 4 Light Red 12
Funcþia 15 - Citire caracteristici mod de lucru curent.
Ca rezultat al execuþiei acestei funcþii, se obþine un numár care reprezintá Magenta 5 Light 13
codul modului de lucru curent în registrul AL, numárul de Magenta
coloane-caracter va fi obþinut ín registul AH, iar numárul paginii curente Brown 6 Yellow 14
va fi obþinut în registrul BH (pentru modurile de lucru grafice numárul Light gray 7 White 15
paginii este 0).
Observaþie: Funcþiile 16÷ 19 sunt caracteristice interfeþelor de tip Pentru desenarea caracterelor sunt disponibile toate cele 16
EGA ßi VGA. Funcþiile 26÷ 28 sunt caracteristice numai interfeþelor de colori, iar pentru fundalul pe care se deseneazá caracterele sunt
tip VGA. disponibile numai primele 8 culori.
Pentru a memora conþinutul ecranului se utilizeazá o zona de
Exemple de utilizare a terminalului grafic ín regim memorie specialá, avänd adrese ín afara spaþiului de memorie utilizat
alfanumeric, prin intrermediul funcþiilor BIOS pentru programe. Pentru o interfaþá CGA "clasicá", memoria utilizatá
pentru eran are adresa de segment 0B800H. Deoarece pe ecran existá mai
Pentru afißarea unui text utilizänd o interfaþá CGA (Color Graphics multe puncte decät caractere, ín zona de memorie utilizatá pentru
Adapter), care permite existenþa pe ecran a 16 culori, pentru fiecare
memorarea informaþiei corespunzátoare imaginii unui ecran ín mod
caracter se pástreazá ín memorie douá informaþii: codul caracterului care
grafic se pot memora informaþiile corespunzátoare pentru mai multe
se afißeazá ßi culorile utilizate pentru desenarea caracterului, respectiv a
imagini de ecran-text. De exemplu, pentru un ecran text cu rezoluþia 80
fundalului pe care se face afißarea.
3
coloane ßi 25 linii sunt necesari 80 x 25 x 2 = 4000 octeþi. Pentru o mov cx, 1 ; Se afisaza cite un caracter
interfaþá CGA standard, memoria-ecran este de 16 Kocteþi. Deci, ín bucla: mov ah, 2 ; Afisare in bucla
aceastá memorie se pot pastra informaþiile pentru mai multe ecrane tip int 10h ; Apel functie BIOS pentru pozitionare cursor
text. Dintre aceste ecrane, la un moment dat este activ (selectat) unul lodsb ; Se incarca in AL caracterul curent
singur. cmp al, '$' ; Este ultimul caracter ?
Adresa ocupatá ín memoria ecran de cátre informaþia jz GATA
corespunzátoare unui caracer este: cmp al, 0dh ; Este CR ?
adresa_caracter = (linie_caracter * 80 + coloana_caracter) * 2 + jz CR
numar_ecran * 4096. mov ah, 9
Selectarea paginii active (vizibile) se face prin apelul BIOS 10H, int 10h ; Apel BIOS pentru afisare caracter
incárcänd ín registrul AH valoarea 5, iar ín registrul AL numárul ; Determinare pozitie utmatoare cursor
ecranului selectat: inc dl
mov ah, 5 cmp dl, 80 ; Sfirsit de linie ?
mov al, numar_ecran jnz bucla
int 10h CR: inc dh ; Se trece la linia urmatoare
Vom considera cäteva exemple de programare a terminalului mov dl, 0 ; Se porneste din coloana 0
grafic ín regim alfamumeric. jmp bucla
GATA:
Exemplul 9.1. ret
title AFISTEXT.ASM afisare ENDP ; Sfirsitul procedurii
; AFISTEXT permite afisarea unui text pe ecran intr-o pozitie dorita START:
utilizind si atribute de culoare mov ax, cs ;
; mov ds, ax ; Incarca DS cu adresa de baza a
STIVA SEGMENT STACK segmentului de date
DB 50 DUP (0) mov ax, STIVA ;
STIVA ENDS mov ss, ax ;
CODE SEGMENT ; Sterge ecran
ASSUME cs:CODE, ds:CODE, ss:STIVA mov cx, 0 ; (CH = 0, CL = 0) - coltul din stings sus
; Procedura de afisare text utilizind si atribute de culoare mov dx, 256*24 + 79 ; Coltul din dreapta jos
; Continut registre la apel: mov ax, 600h ; " scroll up "
; (DH,DL) = numar linie-coloana pentru primul caracter din text mov bh, 36h ; Atribut culoare (fond albastru
; (BH) = numar pagina ecran in care se va face afisarea ; deschis - gri argintiu)
; (BL) = atribut culoare utilizat pentru toate caracterele int 10h ; Apel BIOS
; (DS) = adresa segmentului care contine textul ; Apel procedura afisare
; (SI) = adresa relativa in segment a textului mov dx, 10 * 256 + 25 ; Pozitie inceput text: linia 10,
; Textul se termina cu $ ; coloana 25
afisare PROC mov bh, 0 ; Afisare in pagina 0
4
mov bl, 00011100b ; Atributul utilizat: caracter rosu END START
; aprins, fundal albastru
mov si, OFFSET mesaj ; Adresa relativa inceput text Exemplul 9.2.
call afisare title DIAG1.ASM
mov dx, OFFSET mesaj1 ; Afisare mesaj1 ; DIAG1 permite afisarea unei linii diagonale formata din caracterul A
mov ah, 9 STIVA SEGMENT STACK
int 21h DB 50 DUP (0)
mov ah, 1 STIVA ENDS
int 21h ; Asteapta un caracter de la tastatuta CODE SEGMENT
cmp al, 'y' ASSUME cs:CODE, ds:CODE, ss:STIVA
jz culori_init ; Se revine la culoarea initiala a fundalului
cmp al, 'Y' linie_diagonala PROC NEAR
jnz SF ; Nu se mai revine la culoarea initiala a fundalului mov ah, 15
culori_init: int 10h ; Apel functie BIOS pentru determinare
; Sterge ecran ; pagina curenta
mov cx, 0 ; (CH = 0, CL = 0) - coltul din mov cx, 1 ; Se afisaza cite un caracter
stings sus mov dx, 0 ; Pozitie initiala cursor
mov dx, 256*24 + 79 ; Coltul din dreapta jos linie_iar:
mov ax, 600h ; " scroll up " mov ah, 2 ; Afisare in bucla
mov bh, 0fh ; Atribut culoare (fond negru, caractere albe) int 10h ; Apel functie BIOS pentru pozitionare cursor
int 10h ; Apel BIOS mov al, ' '
; Apel procedura afisare int 10h
mov dx, 10 * 256 + 25 ; Pozitie inceput text: linia 10, inc dl ; Se trece la coloana urmatoare
coloana 25 mov al, ' '
mov bh, 0 ; Afisare in pagina 0 int 10h
mov bl, 00011100b ; Atributul utilizat: caracter rosu inc dl ; Se trece la coloana urmatoare
aprins, fundal albastru mov al, 'A'
mov si, OFFSET mesaj ; Adresa relativa inceput text mov ah, 10 ; Se va afisa caracterul 'A' utilizind atributul
call afisare int 10h ; de culoare existent in memorie
inc dh ; Se trece la linia urmatoare
; Sfirsit executie program inc dl ; Se trece la coloana urmatoare
SF: mov ax, 4c00h ; Iesire in sistem cmp dh, 25 ; S-au parcurs toate liniile ?
int 21h jnz linie_iar
mesaj DB ' A M R E U S I T ! ! ! ', '$' ret
mesaj1 DB 13, 10, 'Doriti sa reveniti la culoarea initiala a fundalului linie_diagonala ENDP
(Y/N) ? $' START:
CODE ENDS mov ax, cs ;
5
mov ds, ax ; Incarca DS cu adresa de baza a CODE ENDS
segmentului de date END START
mov ax, STIVA ;
mov ss, ax ; Exemplul 9.3.
mov ax, 3 ; Se alege modul aflanumeric 80 x 40 color title DIAG2.ASM
int 10h ; Apel functie BIOS pentru initializare mod ; DIAG2 permite afisarea unor linii diagonale formate din caracterul A
; Construire fundal prin afisarea a 2000 de blancuri ; cu sau fara stergerea caracterelor anterioare
mov cx, 2000 ; Numar caractere intr-o pagina
mov bh, 0 ; Afisare in pagina 0 STIVA SEGMENT STACK
mov al, ' ' ; Caracter pentru fundal DB 50 DUP (0)
mov bl, 1fh ; Atribut utilizat pentru scriere: alb STIVA ENDS
; stralucitor pe fundal albastru CODE SEGMENT
mov ah, 9 ; Scriere cu modificare atribut ASSUME cs:CODE, ds:CODE, ss:STIVA
int 10h directie DB ?
call linie_diagonala limita DB ?
mov ah, 0
int 16h ; Asteapta un caracter de la tastatuta animatie PROC NEAR
mov dx, OFFSET mesaj1 ; Afisare mesaj1 mov ah, 15
mov ah, 9 int 10h ; Apel functie BIOS pentru determinare
int 21h pagina curenta
mov ah, 1 mov cx, 1 ; Se afiseaza cite un caracter
int 21h ; Asteapta un caracter de la tastatuta linie_iar:
cmp al, 'y' mov ah, 2 ; Afisare in bucla
jz culori_init int 10h ; Apel functie BIOS pentru pozitionare cursor
cmp al, 'Y' mov al, 'A'
jnz SF mov ah, 10 ; Se va afisa caracterul 'A' utilizind
culori_init: int 10h ; atributul de culoare existent in memorie
; Sterge ecran call intirziere
mov cx, 0 ; (CH = 0, CL = 0) - coltul din stings sus ; mov al, ' ' ; Sterge caracterul prin afisarea unui blanc
mov dx, 256*24 + 79 ; Coltul din dreapta jos ; mov ah, 10
mov ax, 600h ; " scroll up " ; int 10h
mov bh, 0fh ; Atribut culoare (fond negru, caractere albe) add dh, directie ; Alta linie
int 10h ; Apel BIOS inc dl ; Se trece la coloana urmatoare
; Sfirsit executie program cmp dh, limita ; S-au parcurs toate liniile ?
SF: mov ax, 4c00h ; Iesire in sistem jnz linie_iar
int 21h ret
mesaj1 DB 13, 10, 'Doriti sa reveniti la culorile initiale (Y/N) ? $' animatie ENDP
6
; Procedura de intirziere int 21h
intirziere PROC mov ah, 1
push cx int 21h ; Asteapta un caracter de la tastatuta
mov cx, 0ffffh cmp al, 'y'
int1: add cx, 0 jz culori_init
loop int1 cmp al, 'Y'
pop cx jnz SF
ret culori_init:
intirziere ENDP ; Sterge ecran
; mov cx, 0 ; (CH = 0, CL = 0) - coltul din stings sus
START: mov ax, cs ; mov dx, 256*24 + 79 ; Coltul din dreapta jos
mov ds, ax ; Incarca DS cu adresa de baza a mov ax, 600h ; " scroll up "
segmentului de date mov bh, 0fh ; Atribut culoare (fond negru, caractere albe)
mov ax, STIVA ; int 10h ; Apel BIOS
mov ss, ax ; ; Sfirsit executie program
SF: mov ax, 4c00h ; Iesire in sistem
mov ax, 3 ; Se alege modul aflanumeric 80 x 40 color int 21h
int 10h ; Apel functie BIOS pentru initializare mod mesaj1 DB 13, 10, 'Doriti sa reveniti la culorile initiale (Y/N) ? $'
; Construire fundal prin afisarea a 2000 de blancuri CODE ENDS
mov cx, 2000 ; Numar caractere intr-o pagina END START
mov bh, 0 ; Afisare in pagina 0
mov al, ' ' ; Caracter pentru fundal Exemplul 9.4.
mov bl, 1fh ; Atribut utilizat pentru scriere: alb title CHENAR.ASM
; stralucitor pe fundal albastru ; CHENAR permite construirea unui chenar pe marginea ecranului fara
mov ah, 9 ; Scriere cu modificare atribut ; modificarea desenului deja afisat (cu exceptia punctelor de pe
int 10h ; marginea ecranului). Terminalul se foloseste in mod grafic
mov dx, 0 ; Pozitie initiala cursor .MODEL SMALL
mov directie, 1 ; Deplasare in jos .STACK 10h
mov limita, 25 ; Limita inferioara de deplasare .CODE
call animatie af_chenar PROC ; Procedura pentru construirea unui chenar
mov directie, -1 ; Deplasare in sus ; Test daca mod grafic
mov limita, -1 ; Limita superioara de deplasare mov ah, 15
call animatie int 10h
mov ah, 0 cmp al, 4
int 16h ; Asteapta un caracter de la tastatuta jz da1
mov dx, OFFSET mesaj1 ; Afisare mesaj1 mov ax, 4
mov ah, 9 int 10h
7
da1: push es ; Salvare registru ES mov ax,4c00h
mov ax, 0b800h ; Adresa segment memorie ecran int 21h
mov es, ax END begin
; Desen linia de sus
mov al, 0ffh 2. Determinarea configuraþiei sistemului (INT 11H)
mov cx, 80 ; Numar octeti pentru o linie Ca rezultat al apelului aceastei intrari BIOS, în registrul AX se
mov di, 0 ; Adresa relativa de inceput memorie ecran obþine o descriere a configuraþiei sistemului, codificatã în modul urmãtor:
cld Biþii:
rep stosb ; Desen linie 15, 14 - numárul de imprimante ataßate sistemului;
; Desen corp 12 - este conectat adaptorul pentru joy-stik;
mov di, -80 11, 10, 9 - numárul de interfeþe seriale ataßate sistemului;
mov si, 100 ; Numar de perechi de linii 8 - existá DMA;
mov bp, 2000h ; Pentru linii pare 7, 6 - numárul de unitáþi de disc flexibil ataßate:
mov dx, 0 ; Pentru linii impare 00 - 1, 01 - 2, 10 - 3, 11 - 4;
a1: add di, 80 ; Linia curenta 5, 4 - modul de lucru iniþial pentru terminalul grafic:
mov cx, 2 01 - modul de lucru alfanumeric 25 de linii x 40 de coloane color;
a2: or BYTE PTR es:[bp+di],0c0h ; Deseneaza punct stinga 10 - modul de lucru alfanumeric 25 de linii x 80 de coloane color;
or BYTE PTR es:[bp+di+79],3 ; Deseneaza punct dreapta 11 - modul de lucru alfanumeric 25 de linii x 80 de coloane alb/negru;
xchg bp, dx ; Urmatoarea linie para/impara Observatie: Pe baza acestei informaþii se poate determina tipul
loop a2 adaptorului pentru terminalul grafic utilizat. Astfel, dacá modul de lucru
dec si iniþial este diferit de 11, atunci adaptorul este color. Se observá cá se
jnz a1 ; Daca mai sunt perechi de desenat utilizezá o altá codificare a modurilor de lucru decät cea de la INT 10H.
; Desen linie de jos 3, 2 - capacitatea memoriei RAM de pe placa de bazá:
mov al, 0ffh 00 - 64 Kocteþi;
mov cx, 80 ; Numar de octeti pentru o linie 01 - 128 Kocteþi;
10 - 172 Kocteþi;
add di, bp ; Adresa relativa a ultimei linii 11 - 256 Kocteþi;
cld 1 - existá coprocesor matematic:
rep stosb ; Desen linie 0 - nu;
pop es 1 - da;
ret 0 - existá unitate de disc flexibil în sistem:
af_chenar ENDP ; Sfirsit procedura af_chenar 0 - nu;
begin: call af_chenar ; Inceput program principal 1 - da.
mov ah, 0
int 16h ; Se asteapta un caracter de la tastatura Exemplul 9.5.
mov ax, 3 title CONFIGS.ASM
int 10h ; Se trece in modul alfanumeric ; CONFIGS determiná ßi afißeazá numárul de unitáþi de disc flexibil din
8
; configuratia sistemului, precum si modul de lucru al terminalului grafic mov ah, 9
STIVA SEGMENT STACK int 21h
DB 50 DUP (0) ; Determinare mod de lucru pentru terminalul grafic
STIVA ENDS int 11h ; Apel BIOS pentru determinare configuratie
CODE SEGMENT and al, 60h ; Se selecteaza bitii care indica modul de
ASSUME cs:CODE, ds:CODE, ss:STIVA ; lucru al terminalului grafic
; Datele programului mov cl, 4 ; Se construieste codul ASCII pentru
mes1 DB 'In configuratie sunt $' shr al, cl ; determinarea modului de lucru al
mes2 DB ' unitati de disc flexibil $' ; terminalului grafic
mes3 DB 13, 10, 'Mod de lucru terminal grafic: alfanumeric 25 linii add al, '0'
x 80 coloane - color $' cmp al, '2'
mes4 DB 13, 10, 'Mod de lucru terminal grafic: alfanumeric 25 linii jz afmes3
x 80 coloane - alb/negru $' mov dx, OFFSET mes4
; Codul programului mov ah, 9
START: int 21h
mov ax, CODE ; jmp SF
mov ds, ax ; Incarca DS cu adresa de baza a afmes3: mov dx, OFFSET mes3
segmentului de date mov ah, 9
mov ax, STIVA ; int 21h
mov ss, ax ; ; Sfirsit executie program
mov dx, OFFSET mes1 ; Se afisaza primul mesaj SF: mov ax, 4c00h ; Iesire in sistem
mov ah, 9 int 21h
int 21h CODE ENDS
int 11h ; Apel BIOS pentru determinare configuratie END START
and al, 0c0h ; Se selecteaza bitii care indica numarul
; de unitati de disc
3. Determinarea capacitãþii memoriei sistemului (INT 12H)
; Construieste codul ASCII al numarului de unitati de disc
mov cl, 6 Rezultatul execuþiei acestei funcþii BIOS constá ín depunerea în
shr al, cl ; Bitii se aduc in pozitia cea mai putin registrul AX a valorii capacitáþii memoriei sistemului. Capacitatea se
; semnificativa exprimá în Kocteþi.
add al, 1 + '0' ; Corectie ASCII 4. Utilizare interfaþa serialã (INT 14H)
mov dl, al
; Afisare numar unitati de disc Pentru utilizarea interfeþei seriale se pot utiliza urmátoarele
mov ah, 2 funcþii:
int 21h ; Apel DOS pentru afisarea Funcþia 0 - Iniþializare interfaþá serialá.
caracterului din reg. DL Prin aceastá funcþie se stabilesc caracteristicile transferurilor ce se vor
mov dx, OFFSET mes2 ; Se afisaza al doilea mesaj executa prin intermediul interfeþei seriale. Registrul DX conþine numáru

9
l interfeþei seriale (de regulá configuraþia conþine o singurá interfaþá, deci Registrul DX conþine numárul interfeþei seriale referite la apelul funcþiei.
registrul DX va conþine valoarea 0). Registrul AL conþine codificarea Codificarea stárii se transmite ín registrul AX în modul urmãtor:
caracteristicilor pentru iniþializare, astfel: Registrul AH:
Biþii: 7, 6, 5 - viteza de transmisie: bit 7 = "time out"
000 - 110 biþi / secundá; 6 = registrul de serializare este liber
001 - 150 biþi / secundá; 5 = registrul care memoreazã octetul este liber
010 - 300 biþi / secundá; 4 = detecþie "break"
011 - 600 biþi / secundá; 3 = eroare "framming"
100 - 1200 biþi / secundá; 2 = eroare de paritate
101 - 2400 biþi / secundá; 1 = eroare "overrun"
111 - 9600 biþi / secundá; 0 = existã octet recepþionat
4, 3 - utilizare bit de paritate: Registrul AL:
x0 - nu se utilizeazá bit de paritate; bit 7 = DCD
01 - paritate impará; 6=0
11 - paritate pará; 5 = DSR
2 - numár biþi de stop: 4 = CTS
0 - 1 bit de stop; 3=1
1 - 2 biþi de stop; 2=1
1, 0 - lungime cuvänt: 1 = delta DCD
10 - 7 biþi; 0=1
11 - 8 biþi.
Stabilirea acestor caracteristici se face în funcþie de echipamentul 5. Utilizare tastaturá (int 16h)
cu care se face interconectarea prin intermediul interfeþei seriale. Pentru tastaturá BIOS-ul conþine de fapt douá proceduri. Prima
Funcþia 1 - Transmisie. corespunde nivelului 9 de întreruperi (nivelul 1 pentru întreruperile
Registrul AL conþine octetul care se transmite. Registrul DX conþine externe) care trateazá semnalele de întrerupere externe provenite de le
numárul interfeþei seriale utilizate în tranfer. În cazul în care nu s-a putut tastaturá, în timp ce a doua corespunde nivelului 22 (16H) care trateazá
face transmiterea octetului, la revenirea din execuþia funcþiei bitul cel mai cererile de întrerupere solicitate de cátre programe pentru obþinerea unui
semnificativ din AH va fi 1. Ceilalþi biþi din AH codificá întotdeauna caracter de la tastaturá. Legátura între cele douá proceduri este realizatã
starea interfeþei seriale înainte de transmiterea octetului. prin intermediul unui buffer în cere prima procedurá acumuleazá
Funcþia 2 - Recepþie. caractere pe másurá ce acestea sunt transmise de la tastaturá ßi din care a
Ca rezultat al execuþiei acestei funcþii ín registrul AL se va obþine octetul doua procedurá preia caractere. Bufferul poate sá memoreze maximum
recepþionat. În registrul DX se va transmite numárul interfeþei seriale 16 caractere. La depáßirea capacitáþii bufferului, sistemul emite un
utilizate în tranfer. La revenirea din execuþia funcþiei, în registrul AH semnal sonor. Bufferul este organizat circular ßi conþine pentru fiecare
biþii corespunzátori erorilor sunt poziþionaþi conform erorilor detectate caracter transmis o pereche de octeþi cu semnificaþia generalá: cod ASCII
înainte de preluarea caracterului. ßi respectiv cod scanare (numárul tastei care a produs caracterul
Funcþia 3 - Citire stare interfaþá serialá. respectiv).

10
Procedura pentru tratarea întreruperilor provenite de la tastaturá Tastele ALT, CTRL, SHIFT funcþioneazá în modul "clasic" (sunt active
realizeazá traducerea codurilor specifice, transmise de la tastaturá , în atät timp cät sunt apásate). Celelalte taste sunt active ca efect între o
perechi de coduri conform standardului IBM. Codurile transmise de cátre primá ßi o a doua apásare (între care trebuie sá se execute o eliberare).
tastaturá se numesc coduri de scanare. Pentru fiecare tastá este asociat un Starea acestor taste este memoratá la adresele 40H:17H, 40H:18H în
cod de scanare unic pe care tastatura îl transmite la apásarea tastei forma urmátoare:
respective. Valorile codurilor de scanare sunt cuprinse între 1 ßi 101 adresa 40H:17H :
(tastatura are101 taste). La eliberarea tastei, tastatura transmite un cod bit 7 = 1 - stare "INSERT" activá
obþinut din codul de scanare prin adunarea valorii 80H (poziþionare în 1 a bit 6 = 1 - stare "CAPS LOCK" activá
bitului cel mai semnificativ). Cele douá coduri obþinute pentru apásarea, bit 5 = 1 - stare "NUM LOCK" activá
respectiv pentru eliberarea unei taste, se numesc cod "make", respectiv bit 4 = 1 - stare "SCROLL LOCK" activá
cod "break". Dacá o tastá este apásatá pentru un interval mai mare de bit 3 = 1 - tasta "ALT" apásatá
timp, tastatura va începe sá transmitá la intervale scurte de timp codul bit 2 = 1 - tasta "CTRL" apásatá
"make" asociat tastei respective ("autorepeat"). bit 1 = 1 - tasta "SHIFT stänga" apásatá
Procedura pentru tratarea întreruperilor provenite de la tastaturá bit 0 = 1 - tasta "SHIFT dreapta" apásatá
realizeazá ßi interpretatrea, respectiv execuþia, unor comenzi imediate adresa 40H:18H :
corespunzátoare unor combinaþii de taste speciale care trebuie sá fie bit 7 = 1 - tasta "INSERT" apásatá
apásate simultan: bit 6 = 1 - tasta "CAPS LOCK" apásatá
CTRL, NUM LOCK - comandá opirea execuþiei unui program bit 5 = 1 - tasta "NUM LOCK" apásatá
päná la apásarea altei taste; bit 4 = 1 - tasta "SCROLL LOCK" apásatá
SHIFT, PRINT SCRIN - comandá copierea la imprimantá a bit 3 = 1 - execuþia programului opritá prin comanda
caracterelor afißate pe ecran. În acest scop se utilizeazá apelul unei CTRL, NUM LOCK
proceduri speciale (INT 5) ;
Informaþia conþinutá în cei mai semnificativi 4 biþi de la adresa
CTRL, SCROLL LOCK - comandá, în general, încheierea
40H:18H este utilizatá pentru a evita tratarea unui cod, retransmis
execuþiei unui program. Dacá programatorul îßi defineßte propria sa
datoritá funcþiei de "autorepeat" a tastaturii, drept o nouá apasare a tastei
procedurá pentru tratarea întreruperii, INT 1BH (utilizänd funcþia DOS
respective.
corespunzátoare, sau direct memoränd la adresa 0:6CH adresa
procedurii), atunci pentru aceastá combinaþie de taste se va apela Pornind de la codul de scanare transmis de tastaturá, în funcþie de
procedura utilizator respectivá; starea tastelor de tip "shift", se obþine o pereche de octeþi. Primul octet
CTRL, ALT, DEL - comandá reiniþializarea sistemului. Spre conþine, pentru caracterele "obißnuite" (din setul ASCII), codul ASCII
deosebire de secvenþa de acþiuni ce se executá la pornirea sistemului, în corespunzátor. Pentru aceste caractere, al doilea octet conþine codul de
acest caz nu se mai efectueazá testul memoriei. Din acest motiv scanare transmis de la tastaturá. Utilizänd tastele "ALT" ßi tastele
reiniþializarea se executá mult mai rapid. numerice din dreapta tastaturii, se poate construi orice caracter din setul
Modul în care sunt interpretate codurile de scanare provenite de la ASCII extins (coduri între 128 ßi 255). În acest caz primul octet conþine
tastaturá depinde de "starea" tastelor considerate de tip "shift". În aceastá codul ASCII extins, iar al doilea octet conþine valoarea 0. Pentru tastele
categorie se încadreazá urmátoarele taste: INSERT,CAPS LOCK, NUM speciale (tastele funcþionale, tastele pentru deplasarea cursorului etc.)
LOCK, ALT, CTRL, SHIFT dreapta, SHIFT stänga. Dintre aceste taste primul octet are valoarea 0, iar al doilea va conþine un cod de scanare
numai tasta INSERT se va memora în buffer, celelalte taste fixeazá starea
tastaturii determinänd modul în care se vor interpreta celelalte taste.
11
calculat pe baza codului transmis de la tastaturá. În tabelul 8.2 este 117 CTRL, END
prezentat modul în care se obþine aceste coduri.
118 CTRK, PGDN
Tabelul 8.2.
Valoare cod Modul în care se obþine 119 CTRL, HOME
[120-131] ALT, 1;...;ALT, =
3 CTRL, 2
132 CTRL, PGUP
15 SHIFT, TAB
[16-25] ALT,Q; ... ;ALT,P Pentru utilizarea tastaturii se pot selecta urmátoarele funcþii:
[30-38] ALT, A; ... ;ALT, L Functia 0 - Citire caracter.
[44-50] ALT, Z; ... ;ALT,M Pentru aceastá funcþie se extrage din buffer o pereche de octeþi care
reprezintá codul ASCII al caracterului (registrul AL) ßi codul de scanare
[59-68] F1;...;F10
(registrul AH). Dacá bufferul este gol se aßteaptá päná la introducerea în
71 HOME buffer a unei perechi de octeþi de cátre procedura de tratare a întreruperii
72 ^ externe provenite de la tastaturá.
Funcþia 1 - Test caracter disponibil.
73 PGUP Dacá bufferul tastaturii conþine caractere, aceastá funcþie are ca efect
75 <-- copierea ín registrul AX a celor doi octeþi corespunzátori caracterului
curent din buffer, iar indicatorul ZF este poziþionat pe 0. Dacá bufferul
77 -->
nu conþine caractere, indicatorul ZF este poziþionat pe 1 ßi se executá
79 END reîntoarcerea din execuþia funcþiei. Se observá cá aceastá funcþie are mai
80 mult rolul de a verifica dacá existá un caracter disponibil decät de a
prelua caracterul din buffer, deoarece la urmátorul apel acelaßi caracter
81 PGDN este oferit ca disponibil.
82 INS Funcþia 2 - Citire stare taste de tip "shift".
Ca rezultat al acestui apel, ín registrul AL se íncarcá octetul ce codificá
83 DEL
starea tastelor de tip "shift". Acest octet este memorat la adresa 40H:17H.
[84-93] SHIFT, F1; ... ;SHIFT,F10
[94-103] CTRL,F1;... ;CTRL,F10 Modul de lucru
Sa se realizeze un program care sa afiseze pe ecran macheta din
[104-113] ALT,F1;...;ALT,F10 Fig. 9.1. Programul trebuie sa permita actualizarea corespunzátoare a
114 CTRL, PRTSC parametrilor precizati, cu selectia corespunzátoare a buclei. Se cere, de
asemenea, realizarea unei proceduri care sa permita afißarea datei ßi a
115 CTRL, <--
orei curente.
116 CTRL, -->

12
APLICATIE DE REGLARE

BUCLA 1 BUCLA 2 BUCLA 3

Referinta [%] 30. 50 45.00 35.55


DATA
Masura [%] 28.45 48.00 53.83
23. 11. 2001
Comanda [%] 1 -1 85.78

Regim A A A
ORA CURENTA
Kr 2.75 2.50
08: 40: 55
Ti [sec] 10.00 10.00

Td [sec] 2.00

Zona ins. 0.50 0.02

C. O. P. Bucla selectata

R: 55.50 1

Fig. 9.1.

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