Osnovni cilj je: ovladati programiranjem na asemblerskom jeziku procesora 80x86. U okviru kursa, upoznaćemo se sa sledećim temama:
- Istorijatom, arhitekturom i osobinama ovog procesora (o tome će biti mnogo više reči na predavanjima)
- Instrukcijama i pseudoinstrukcijama asemblerskog jezika
- Makroima
- Sistemom prekida i mehanizmom obrade prekida
- Načinom asembliranja i povezivanja (linkovanja)
- Strukturom izvršnih datoteka (izvršnog koda)
- Načinima za formiranje izvršne datoteke od više izvornih datoteka
- Koprocesorom (matematičkim pocesorom), njegovom arhitekturom, osobinama i instrukcijama, te mehanizmom zajedničkog rada koprocesora i procesora
- Povezivanjem asemblerskog koda sa programima napisanim na nekom drugom programskom jeziku
- Načinom komunikacije procesora sa drugim uređajima u okviru računarskog sistema: disk jedinicom, grafičkom karticom (video adapterom), karakter uređajima itd.
- Asemblerski (simbolički) jezici su najstariji programski jezici.
- Pre nastanka asemberskih jezika, komunikacija sa računarima (tj. programiranje) se odvijala tako što su sekvence nula i jedinica bivale ručno unošene u memoriju računara na zahtevanu poziciju (adresu), a potom je program startovan.
- Veliko unapređenje mukotrpnog postupka programiranja nastupa kada se dopusti da se koriste mnemotehničke oznake koje zamenjuju odgovarajuće instrukcije računara, tj. uvođenjem operacionog koda (opkod).
- Pored uvođenja operacionog koda, uvode se i simbolička imena adresa, tj. uvodi se mogućnost da se sekvence nula i jedinica zamene simboličkim imenom. Zbog te karakteristike, za asemblerske jezike se u literaturi često koristi naziv simbolički jezici.
- Program na asemblerskom jeziku, ne može direktno da se izvršava na mašini. On sada predstavlja ulaz za neke druge programe koji ga transformišu u kod razumljiv mašini i smeštaju u memoriju.
-
Vremenom je programiranje na asemblerskom jeziku obogaćeno drugim mogućnostima:
raznovrsnim načinima adresiranja; mogućnošću pravljenja
procedura, tj. logičkog organizovanja programa i
izdvajanja celina u podprograme;
- Asemblerski jezik koji podržava rad sa makroima naziva se makroasembler.
Sledeća klasifikacija ukazuje na mesto asemblerskih i makroasemblerskih jezika među programskim jezicima:
U poređenju sa mašinski nezavisnim jezicima, asemblerski i makroasemblerski jezici imaju sledeće osobine:
- zavise od konkretnog tipa računara, čime je bitno umanjena prenosivost programa (mada jedan proizvođač obično pravi svoje programe tako da budu vertikalno kompatibilni);
- manja udobnost u programerovom radu, nego što je to slučaj sa mašinskim jezicima (mada izražajna sredstva postaju sve raznovrsnija, a i samo okruženje postaje sve udobnije);
- programi (preciznije, dobro napisani programi) na asemblerskom jeziku osetno bolje iskorištavaju resurse računara, nego programi napisani na nekom od mašinski nezavisnih jezika; tako se smatra da se dobar asemblerski program u proseku izvršava 20-30% brže od odgovarajućeg C programa (mada prevodioci postaju sve “pametniji”);
- kako programi na asemblerskom jeziku nemaju osobinu samodokumentovanosti (čitljivost im nije jača strana), neophodno je istaći ogroman značaj koji ima dokumentacija, komentarisanje koda, itd.
- u programima na asemblerskom jeziku najbitnije je maksimalno iskorišavanje računarskih resursa, pa se (ne vodeći računa o čitljivosti) mogu koristiti sve dosetke koje ubrzavaju rad algoritma, ili smanjuju veličinu zahtevanih resursa.
Zbog svih ovih karakteristika, jasno je da se programira na asemblerskom jeziku kada se pravi softver koji je u uskoj vezi sa hardverom, kao što su drajveri (veznici, pogonaši) za neke uređaje; kada se želi povećati iskorišćenost resursa; kada se želi ubrzati izvršavanje konkretnog algoritma.
Kada se govori o asemblerskom jeziku, često se može čuti maksima: “Pri programiranju na asemblerskom jeziku, ništa ne stoji između programera i računara. Međutim, ništa ne stoji ni između programera i greške”. Preciznije bi bilo da se reč “ništa” iz prve i iz druge rečenice maksime, zameni sa “skoro ništa”.
Sledeća shema prikazuje proces dobijanja izvršnog koda (izvršnog programa) na osnovu izvornih programa (asemblerskih programa):
Izvorni Objekt Izvršni
program kod kod
- Prvo se preko nekog ulaznog uređaja unese izvorni program (na asemblerskom jeziku) u memoriju računara, i zapamti se u datoteku na nekom od uređaja spoljne memorije.
- Potom se pozove program koji prevodi (asemblira) izvorni program i, ukoliko tokom prevođenja nije bilo grešaka, kreira objekt program. Program koji vrši prevođenje naziva se asembler, a otud potiče i naziv za celu klasu jezika - asemblerski jezici. Asembler će oformljeni objekt program upisati u posebnu datoteku.
- Objekt program (objekt kod) još nije spreman za izvršavanje. Potrebno ga je povezati. To obavlja uslužni program nazvan povezivač (linker). Linker će, po potrebi, povezati i više modula sa objekt kodom. Tako će se, ukoliko prilikom povezivanja ne dođe do grešaka, oformiti izvršni program (izvršni kod) koji se upisuje u potrebnu datoteku, kako bi se kasnije mogao izvršavati.
Centralni predmet proučavanja u ovom kursu je asemblerski jezik procesora 80386. Tokom obrade gradiva, ukazivaće se na sličnosti i razlike između ovog procesora i njegovih prethodnika (8086, 80286). Isto tako, pri obradi procesora 80387 govoriće se i o sličnostima i razlikama između njega i njegovih prethodnika.
U ovom poglavlju se opisuju samo pozicioni brojni sistemi i predstavljanje celih brojeva. U tom slučaju, osnova brojevnog sistema jednoznačno identifikuje taj sistem. Cifre nekog prirodnog broja u tom brojevnom sistemu su ostaci pri deljenju tog broja sa stepenima osnove sistema. Dakle, isti broj će imati različite zapise u različitim brojevnim sistemima.
Biće ponovljene osnovne osobine i načini izvršenja operacija za sledeće brojevne sisteme: dekadni, binarni, oktalni i heksadekadni (heksadecimalni).
Osnovne aritmetičke operacije nad brojevima u nekom od prethodno pobrojanih pozicionih brojnih sistema izvode se potpuno analogno aritmetičkim operacijama nad dekadnim brojevima (dakle, onako kako smo i navikli da radimo).
Osnova brojnog sistema je 10. Cifre su: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
Osnova brojnog sistema je 2. Cifre su: 0 i 1.
Pri radu sa binarnim brojevima kod procesora 80386 razlikuju se:
bit (eng. binary digit) |
1 |
bajt (oktet, eng. byte) |
8 |
polubajt (kvartet. eng. nibble) |
4 |
reč (eng. word) |
16 |
dvostruka reč (eng. double word) |
32 |
Svaka klasa ovakvih binarnih brojeva ima svoju dužinu, i može predstavir određen opseg brojeva
Ako se posmatraju brojevi u odgovarajućem opsegu, može se govoriti o neoznačenim i označenim brojevima. Stoga, ista bitovna niska može predstavljati jedan broj ako se tumači kao neoznačen, a sasvim drugi broj ukoliko se tumači kao označen.
Postoji i više načina za predstavljanje označenih brojeva (znak i apsolutna vrednost, nepotpuni komplement, potpuni komlement). Kod procesora 80386 označeni brojevi se čuvaju u formatu potpunog komplementa (komplemet dvojke, eng. two’s complement).
Osnova brojnog sistema je 8. Cifre su: 0, 1, 2, 3, 4, 5, 6, 7.
Osnova brojnog sistema je 16. Cifre su: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E , F. Cifre A, B, C, D, E, F imaju numeričku vrednost 10, 11, 12, 13, 14, 15 respektivno.
Procesor 80386 je 32-bitni procesor. To znači da maksimalna dužina niza bitova sa kojom ovaj procesor operiše u jednoj instrukciji iznosi 32. Stoga, i registri ovog procesora imaju dužinu 32. Težina bitovnih mesta je određena tako da krajnje desni bit registra predstavlja bit najmanje težine.
Procesor 80386 sadrži devet 32-bitnih registara i deset jednobitnih flegova (zastavica, eng. flag). Flegovi se nalaze u tzv. registru flegova.
31 |
16 |
15 8 |
7 0 |
|
|
|
AH A |
X |
EAX |
|
|
BH B |
X BL |
EBX |
|
|
CH C |
X CL |
ECX |
|
|
DH D |
X DL |
EDX |
|
|
S |
I |
ESI |
|
|
D |
I |
EDI |
|
|
B |
P |
EBP |
|
|
S |
P |
ESP |
|
|
|
|
|
31 |
16 |
15 |
0 |
|
|
|
|
|
EIP |
|
|
|
|
EFLAGS |
Osam od ovih devet opštih registara su tzv. registri opšte namene. Za najveći broj instrukcija procesora, ovi registri mogu biti korišćeni bez obzira na vrstu instrukcije. Ali, kao što će se kasnije detaljnije videti, postoje i neke, veoma važne, instrukcije, koje su orjentisane na specifične registre. Te instrukcije koriste konkretne registre na specificiran način, i pri izvršenju tih instrukcija konkretan registar ne može biti zamenjen nijednim drugim registrom. Deveti registar, nazvan brojač naredbi (pokazivač instrukcije, eng. instruction pointer), nije direktno pristupačan programeru.
Kad procesori ne bi posedovali opšte registre, svaka instrukcija bi dohvatala svoje operande iz meorije, i vraćala bi rezultat u memoriju. Ali, pristup meoriji oduzima vreme. To vreme potrebno za dohvatanje i smeštaj operanada može biti redukovano privremenim čuvanjem često korišćenih podataka i međurezultata na mestu kome se može brže pristupiti. Takvo mesto je, kod procesora 80386, skup njegovih opštih registara.
Opšti registri procesora 80386 su 32-bitni registri EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP. Slovo E na početku oznake je skraćenica od reči raširen (eng. extended), jer je svaki od ovih registara raširenje nekog 16-bitnog registra koji su postojali kod starijih procesora u ovoj familiji. Ti 16-bitni registri (nazvani AX, BX, CX, DX, SI, DI, BP i SP) su donje polovine ovih raširenih registara. Prva četiri 16-bitna registra se dalje dele na 8-bitne registre. Polovine registara manje težine označavaju se sa Al, BL, CL, DL (L od nizak - eng. low), dok se podregistri veće težine označavaju sa AH, BH, CH, DH (H od visok - eng. high).
Sposobnost procesora 80386 da adresira 8-bitovne i 16-bitovne podskupove 32-bitnih opštih registara omogućuje da ovaj procesor rukuje bajtovima, rešima i dvostrukim rečima na uniforman način.
Za najveći broj instrukcija ma koji opšti registar može učestvovati kao operand.
Primer.
Instrukcija ADD može sabrati sadržaj ma kog 8, 16, 32-bitnog opšteg registra sa sadržajem ma kog registra iste dužine i smestiti rezultat u odgovarajući registar (te dužine).
Ipak, kako je i istaknuto u prethodnom poglavlju, postoji nekoliko instrukcija koje određene, fiksirane registre, koriste za određenje svrhe.
Primer.
Instrukcije za rad sa niskama (stringovima,
eng. string) zahtevaju da registar ECX sadrži broj elemenata niske. Nijedan od drugih registara se ne može koristiti u tu svrhu pri
izvršavanju instrukcija za rad sa niskama.
Specijalizovana upotreba registra ECX dovodi do toga da ga u literaturi često nazivaju brojač (eng. counter). Specijalizovano korišćenje registara EAX, EBX, EDX, koje će biti kasnije objašnjeno, nameće da se za njih koriste opisna imena akumulator (eng. accomulator), baza (eng. base), podatak (eng. data) redom.
Procesor 80386 sadrži deset flegova koji se koriste za čuvanje informacija o statusu procesora (takvi flegovi su statusni flegovi, tj. statusne zastavice) ili za kontrolu operacija procesora (kontrolni flegovi, tj. kontrolne zastavice).
Statusni flegovi, u opštem slučaju, po izvršenju aritmetičke ili logičke instrukcije dobijaju vrednost koja odslikava određene osobine rezultata takvih operacija.
Statusni flegovi su:
CF - fleg prenosa (eng. carry flag), koji indicira da je izvršena instrukcija generisala prenos sa mesta najveće težine;
AF - pomoćni fleg prenosa (eng. auxilary carry flag), koji ukazuje da je izvršenje instrukcije generisalo prenos sa mesta najveće težine polubajta najmanje težine, tj. prenos sa bita na poziciji ;
OF - fleg prekoračenja (eng. overflow flag), koji ukazuje da lli je instrukcija oformila rezultata u obliku označenog celog broja, koji je izašao iz okvira (opsega);
ZF - nula fleg (eng. zero flag), ukazuje na to da li je instrukcija generisala rezultat koji je nula, tj. da li se rezultat sastoji od svih nula;
SF - fleg znaka (eng. sign flag), ukazuje da je instrukcija svojim izvršavanjem generisala negativan rezultat; vrednost flega znaka poklapa se sa vrednošću bita najveće težine rezultata;
PF - fleg
parnosti (eng. parity flag), indicira da je instrukcija svojim
Kontrolni flegovi, kao što im ime kaže, kontrolišu način izvršavanja pojedinih instrukcija. Stoga se njihova vrednost postavlja na jedan (još se kaže “fleg se postavlja”, eng. set) ili na nulu (koristi se izraz “fleg se briše”, eng. clear) pre izvršenja instrukcije. U kontrolne flegove spadaju:
DF - fleg pravca (eng. direction flag), kontroliše pravac izvršenja instrukcija za manipulaciju niskama;
IF - fleg omogućavanja prekida (eng. interrupt enable flag) omogućava ili onemogućava spoljašnje prekide;
TF - zamka fleg (eng. trap flag), prebacuje procesor u jednokoračni mod, radi dibagiranja programa;
RF - fleg nastavljanja (eng. resume flag), prekida rad ugrađenog procesorovog dibagera.
Svi ovi flegovi, kao i neki drugi koje zasad nećemo pominjati, zauzimaju bitovna mesta u raširenom registru flegova - EFLAGS.
Da bi se moglo govoriti o načinu izvršenja instrukcija procesora, mora se znati na koji se način u unutrašnjoj memoriji računara čuvaju podaci, tj. nizovi bitova.
Fizička memorija računarskog sistema baziranog na procesoru 80386 je organizovana kao sekvenca bajtova. Svakom bajtu je dodeljena jedinstvena adresa u intervalu od 0 do 232-1 (dužina opsega je 4 GB).
Svaki bajt u memoriji ima svoju adresu. Delovi memorije koji imaju manju adresu, tj. čija je adresa bliža nuli, nazivaće se viša memorija i smatraće se da se oni nalaze “iznad” delova memorije koji imaju veću adresu. U tom smislu, kod dva susedna bajta u memoriji, viši bajt će biti onaj koji ima manju adresu. Analogna konvencija se uspostavlja za reči i dvostruke reči.
Isto kao kod registara, u okviru svakog bajta krajnje desno nalazi bit najmanje težine, levlje su sve značajniji bitovi, da bi krajnje levo bio bit najveće težine.
Reč se čuva u memoriji (u dva susedna bajta) tako što se niži bajt reči upiše u viši bajt memorije, a viši bajt reči u niži bajt memorije.
Dvostruka reč se čuva u memoriji u četiri uzastopna bajta. Bajt najmanje težine dvostruke reči čuva se najvišem mestu u memoriji, sledeći bajt se čuva na sledećem mestu itd. Bajt najveće težine dvostruke reči čuva se na najnižem mestu u memoriji.
Dakle, pri smeštaju reči i dvostruke reči u memoriju, prvo se smesti niži bajt, a potom viši bajt itd, sve do bajta najveće težine .
Primer.
On jasno ilustruje način čuvanja bajta u memoriji. Prikazuje sadržaj memorije pre i posle izvršenja instrukcija za prenos bajta iz opšteg registra u memoriju i instrukcija za prenos i memorije u registre. Sadržaj jednog bajta zapisuje se pomoću dve heksadecimalne (heksadekadne, heksa) cifre.
Početno stanje
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
|
eax: |
c |
c |
b |
b |
a |
a |
4 |
0 |
a: |
7 |
8 |
||
|
|
|
|
|
|
|
|
|
|
|
1 |
2 |
||
|
|
|
|
|
|
|
|
|
|
|
3 |
4 |
||
|
|
|
|
|
|
|
|
|
|
|
5 |
6 |
||
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
MOV a,
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
|
eax: |
c |
c |
b |
b |
a |
a |
4 |
0 |
a: |
4 |
0 |
||
|
|
|
|
|
|
|
|
|
|
|
1 |
2 |
||
|
|
|
|
|
|
|
|
|
|
|
3 |
4 |
||
|
|
|
|
|
|
|
|
|
|
|
5 |
6 |
||
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
MOV AX, a
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
|
eax: |
c |
c |
b |
b |
1 |
2 |
4 |
0 |
a: |
4 |
0 |
||
|
|
|
|
|
|
|
|
|
|
|
1 |
2 |
||
|
|
|
|
|
|
|
|
|
|
|
3 |
4 |
||
|
|
|
|
|
|
|
|
|
|
|
5 |
6 |
||
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
MOV EAX, a
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
|
eax: |
5 |
6 |
3 |
4 |
1 |
2 |
4 |
0 |
a: |
4 |
0 |
||
|
|
|
|
|
|
|
|
|
|
|
1 |
2 |
||
|
|
|
|
|
|
|
|
|
|
|
3 |
4 |
||
|
|
|
|
|
|
|
|
|
|
|
5 |
6 |
||
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
MOV AX, 0F1E2H
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
|
eax: |
5 |
6 |
3 |
4 |
F |
1 |
E |
2 |
a: |
4 |
0 |
||
|
|
|
|
|
|
|
|
|
|
|
1 |
2 |
||
|
|
|
|
|
|
|
|
|
|
|
3 |
4 |
||
|
|
|
|
|
|
|
|
|
|
|
5 |
6 |
||
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
MOV a, EAX
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
|
eax: |
5 |
6 |
3 |
4 |
F |
1 |
E |
2 |
a: |
E |
2 |
||
|
|
|
|
|
|
|
|
|
|
|
F |
1 |
||
|
|
|
|
|
|
|
|
|
|
|
3 |
4 |
||
|
|
|
|
|
|
|
|
|
|
|
5 |
6 |
||
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
Asemblerski programi za prosesor 80386 se mogu kreirati tako da budu nezavisni od fizičkog adresnog prostora. Ovo znači da se programi mogu pisati bez poznavanja tačnih podataka o tome gde su u fizičkoj memoriji smeštene instrukcije i podaci.
Model organizacije memorije, onako kako ga vidi aplikativni programer, određen je od strane dizajnera sistemskog softvera. Arhitektura procesora 80386 daje dizajneru slobodu izbora modela za svaki od zadataka. Model organizacije memorije se kreće između sledeća dva ekstrema:
1. Ravan adresni prostor, koji se sastoji od jednog niza veličine do 4 GB
2. Segmentirani adresni prostor, koji se sastoji od skupa koji sadrži ne više od 16383 linearnih adresa veličine do 4GB.
Oba modela obezbeđuju memorijsku zaštitu. Različiti poslovi mogu koristiti različite modele memorijske organizacije.
U ravnom modelu organizacije memorije, aplikacioni programer vidi memoriju kao jedinstven niz maksimalne veličine 4 GB (=232 bajtova). Obično je veličina memorije mnogo manja od 4GB, pa procesor mapira (eng. map - preslikavanje) ravan prostor od 4 GB u fizički adresni prostor. Mehanizam adresnog preslikavanja, tj. adresne translacije, će biti opisan u nekom od sledećih poglavlja. Aplikativni programeri ne moraju da znaju detalje mapiranja.
Pokazivač na objekat u ovom ravnom adresnom prostoru je 32-bitni neoznačen ceo broj. On se kreće između 0 i 232-1. U ovom slučaju relokacija razdvojeno asembliranih modula mora biti izvršena od strane sistemskog softvera.
U segmentiranom modelu organizacije memorije adresni prostor, onako kako ga vidi aplikacija, je mnogo veći nego u prethodnom slučaju. Taj prostor se naziva logički adresni prostor i kod ovog modela organizacije njegova veličina može da ide i do 64TB (=246 bajtova). I u ovom modelu se pomoću mehanizma adresne translacije vrši preslikavanje logičkog u fizički adresni prostor.
Slično kao u prethodnom slučaju, aplikativni programeri ne moraju da znaju detalje mapiranja. Oni će logički adresni prostor procesora 80386 videti kao skup od maksimalno 16383 jednodimenzionalnih podprostora, nazvanih segmenti. Segment je, dakle, jedinica neprekidnog adresnog prostora. Njegova veličina može varirati od jednog bajta do četiri gigabajta.
Kompletan pokazivač na objekte u ovom adresnom prostoru se sastoji od dva dela:
1. Segmentni selektor, 16-bitno polje koje identifikuje segment.
2. Ofset (eng. offset - pomeraj, pomak) u segmentu, 32-bitni neoznačen ceo broj koji adresira bajtove u okviru segmenta.
Tokom izvršavanja programa, procesor asocira segmentni selektor sa fizičkom adresom početka segmenta. Odvojeno asemblirani moduli mogu, izmenom bazne adrese segmenta, biti relocirani u vremenu izvršavanja.
Instrukcije procesora 80386 se obično izvršavaju nad dva, jednim ili nijednim operandom. Sintaksa ovih instrukcija se, korišćenjem modifikovane Bekusove notacije, zapisuje na sledeći način:
[<prefiks ponavljanja>]<mnemonik><odredišni operand>[[,<pomoćni operand>],<izvorni operand>]] đ
[<prefiks ponavljanja>]<mnemonik><izvorni operand>
Procesor 80386 dopušta veliku širinu u izboru operanda koji se mogu koristiti sa instrukcijama.
Ukoliko mnemonik instrukcije prate tri operanda, tada prvi operand predstavlja odredišni operand i označava se sa D (eng. destination - odredište), drugi operand, u oznaci H (eng. help - pomoć) je pomoćni, dok je treći operand specificira izvor i označava se sa S (eng. source - izvor).
Ako mnemonik instrukcije prate dva operanda, onda ti operandi predstavljaju odredište i izvor.
Ako instrukcija ima jedan operand, taj operand kod nekih instrukcija specificira izvor, a kod drugih odredište.
Postoje i instrukcije koje nemaju operande.
Treba napomenuti da, iako programer o mnemonicima (tj. mnemotehničkim skraćenicama) razmišlja kao o jednoj instrukciji, pa smatra da jednom mnemoniku odgovara jedan operacioni kod (jedan opkod, tj. jedan niz nula i jedinica), kod procesora 80386 to nije slučaj. Naime, tu preslikavanje skupa mnemonika u skup opkodova nije funkcija. Drugim rečima, preslikavanje skupa opkodova u skup mnemonika nije injekcija.
Primer.
Mnemonik asemblerske instrukcije MOV ima 17 različitih opkodova.
Dakle, generisanje koda prilikom asembliranja ne zavisi samo od mnemonika, već i od načina adresiranja, veličine operanda, itd.
Razlikuju se sledeći načini adresiranja (tj. načini modifikacije operanada):
1) Neposredno adresiranje
2) Registarsko adresiranje
3) Direktno memorijsko adresiranje
4) Indirektno memorijsko adresiranje
1. baza
2. (skalirani) indeks
3. baza+(skalirani) indeks
4. baza+pomeraj
5. (skalirani) indeks+pomeraj
6. baza+(skalirani) indeks+pomeraj
Ova vrsta adresiranja označava da je operand konstanta inkorporirana u instrukciju, tj. konstanta koja predstavja deo instrukcije. Neposredni operandi su najčešće celi brojevi ili pokazivači na memoriju koji su specificirani kao konstante korišćenjem pseudoinstrukcije OFFSET (sve pseudoinstrukcije, pa i pseuudoinstrukcija OFFSET biće opisane u jednom od sledećih poglavlja).
Primer.
Neka je NIZ ime memorijske lokacije. Neposredno adresiranje je zastupljeno kod sledećih instrukcija:
MOV CL, 100
MOV ESI, OFFSET NIZ
Ovo adresiranje označava da je operand registar, pa se operacija koja je specificirana instrukcijom vrši nad sadržajem registra-operanda. U slučaju registarskog adresiranja, instrukcija će sadržati naziv registra-operanda.
Primer.
U sledećim instrukcijama koristi se registarsko adresiranje
ADD AX,BX
MOV ECX, EDX
Ovo adresiranje označava da se direktno pristupa memorijskoj lokaciji. Za pristup memorijskoj lokaciji koristi se uređeni par sledećeg oblika:
segment:offset.
- Segment može biti naziv bilo kog 16-bitnog segmentnog registra (CS, DS, SS, ES, FS, GS), ili ime segmenta (koje je u okviru asemblerskog programa definisano korišćenjem pseudoinstrukcije SEGMENT), ili ime grupe (definisano u okviru asemblerskog programa pomoću pseudoinstrukcije GROUP). Kako je kod prethodnika procesora 80386 memorija bila segmentizovana, to se način specificiranja adrese pomoću para segment:pomeraj zadržao i nadalje.
- Offset (pomeraj) mora biti ceo broj ili izraz čija je vrednost u intervalu 0000H do 0FFFFH za 16-bitni segment, odnosno 00000000H do 0FFFFFFFFH za 32-bitni memorijski segment.
Primer.
Neka je DATA ime prethodno definisanog memorijskog segmenta. Sledeće instrukcije predstavljaju primer korišćenja direktno memorijskog adresiranja:
MOV EBX, DS:0
MOV AL, DATA:11
Kod indirektnog memorijskog adresiranja, efektivna odresa se gradi pomoću nekih od sledećih komponeneti: baza, (skalirani) indeks i pomeraj.
Za razliku od njenih prethodnika, kod procesora 80386 se svaki od 32-bitnih opštih registara može koristiti kao baza. Baza (eng. base) je, ukoliko je prisutna, sadržaj 32-bitnog opšteg registra (nazivama se bazni registar) u trenutku kada se instrukcija izvršava. Ona se, ukoliko postoji, sabira sa ostalim komponentama kako bi se izračunala efektivna adresa. Programer specificira bazu tako što ime registra čiji sadrežaj treba da predstavlja bazu uokviri uglastim zagradama.
Primer.
Sledeća instrukcija prebacuje u registar EBX dvostruku reč iz memorije na koju ukazuje registar EDX:
MOV EBX,[EDX]
Zagrade u ovom primeru saopštavaju asembleru da registar-izvorni operand ne sadrži podatke koji će se premestati, već pokazivač na lokaciju u memoriji iz koje se podaci pomeraju.
Indeks (eng. index) je, slično kao baza, vrednost koja se određuje u trenutku izvršavanja instrukcije i dodaje se pri izračunavanju efektivne adrese. Kao i kod baze, vrednost indeksa je vrednost nekog 32-bitnog opšteg registra. Taj registar se naziva indeks registar. Za indeksiranje se može koristiti ma koji opšti registar, sem registra ESP.
Pre dodavanja na druge komponente adrese, indeks se pomnoži sa faktorom skaliranja (koji može biti 1, 2, 4 ili 8). Programer specificira indeks koristeći za skaliranje uobičajenu multiplikativnu notaciju, a potom stavljajući izraz u uglaste zagrade. Ukoliko se skaliranje eksplicitno ne navede, podrazumeva se da je faktort skalliranja 1.
Primer.
Instrukcija za prenos bajta iz memorije u registar AL, koristeći EBP za bazu, a EDX za indeks sa faktorom skaliranja 2 je:
MOV AL, [EBP][EDX*2]
Ova instrukcija se može zapisati i na drugi način
MOV AL, [EBP+EDX*2]
Treća i završna komponenta koja se dodaje na memorijsku adresu je pomeraj (eng. displacement). Pomeraj je konstanta, dužine do 32 bita, koja je enkodirana u instruciju.
Pomeraj se u programima javlja bilo kao eksplicitna konstanta, bilo kao naziv promenljive čija pozicija (adresa, tj. preciznije offset) u memoriji predstavlja pomeraj.
Primer.
Pokazuje kako sve pomeraj može da figuriše u okviru instrukcija procesora 80386:
MOV AX, [EBP+8] ; konstantni pomeraj cija je vrednost 8
MOV AX, NIZ[ECX*2] ; vrednost pomeraja je adresa lokacije NIZ
MOV AX, NIZ[ECX+8] ; vrednost pomeraja je i konstanta 8 i adresa lokacije NIZ
MOV AX, NIZ[EBX+ECX*4+8] ; prisutne su sve komponente pri racunanju efektivne adrese
Primer.
Pokazuje različite načine kombinovanja baze, indeksa i pomeraja u zapisu asemblerskih instrukcija:
MOV AX, [BX] ; baza
MOV EAX, [ECX]+16 ;baza+pomeraj
MOV BX, 32[ECX] ; baza+pomeranje
MOV AX, [BP][SI] ; baza+indeks
MOV AX, NIZ[EBX+ECX*2] ; baza+skalirani indeks + pomeraj
Primer.
Pokazuje različite načine zapisa jedne iste instrukcije:
MOV AX, NIZ[BX][DI]
MOV AX, NIZ[BX+DI]
MOV AX, [NIZ+BX+DI]
MOV AX, [BX][DI].NIZ
MOV AX, [BX][DI]+ NIZ
MOV AX, NIZ[DI][BX]
Primer.
a) ako se radi o nizu bajtova MOV BL, X MOV A[ESI], BL |
b) ako se radi o nizu reči MOV BX, X MOV A[ESI*2], BX |
c) ako se radi o nizu dvostrukih reči MOV EBX, X MOV A[ESI*4], EBX |
Ilustruje kako bi izgledao asemblerski kod ekvivalentan naredbi dodele A(I)=X u nekom višem programskom jeziku, tj. kako se realizuje dodela vrednosti nekom elementu datog niza. Jasno je da se promenljiva iz višeg programskog jezika realizuje pomoću fiksirane lokacije u memoriji (sadržaj te lokacije je vrednost promenljive), a da se niz realizuje preko uzastopnih memorijskih lokacija, Dakle, ako se pretpostavi da su X i A lokacije u memoriji, a da se za pristup elementima niza koristi registar ESI, onda se gornja naredba dodele realizuje na sledeći način:
Operandi instrukcija procesora 80386 mogu da se nađu u trima veličinama: bajt, reč i dvostruka reč.
Kako se često javlja slučaj da instrukcije nad podacima veličinama podataka imaju isti mnemonik a ražličiti opkod, asembler tokom asmbliranja pojdeine instrukcije mora znati veličinu operanada. Inače, asembler neće biti u stanju da korektno generiše objekt kod.
Pravila na osnovu kojih asembler zaključuje o dužini operanda su:
1) Ako postoji još neki od operanada u instrukciji (obično registar), kome se zna dužina,tada nepoznata veličina operanda mora biti jednaka poznatoj veličini operanda (sem u nekoliko retkih izuzetaka);
2) Ako je operand ime koje je prethodno definisano korišćenjem neke od pseudoinstrukcija tj. direktiva DB, DW, DD, onda se veličina operanda izvodi iz vrste direktive koja je korišćena onda kadaje definisano ime;
3) Programer je eksplicitno dao dužinu operanda.
Primer.
U sledećim instrukcijama je eksplicitno data dužina operanda.
INC BYTE PTR[EBX]
INC WORD PTR[EBX]
INC DWORD PTR[EBX]
Asembler ne bi mogao samostalno (tj. primenom prvog i drugog pravila) dokučiti da li da generiše kod za inkrementiranje bajta, reči ili dvostruke reči na koje ukazuje EBX.
Sa tačke gledišta mašine, tj. pri izvršavanju kreiranog izvršnog koda, nema dileme o veličinama operanada. Tu je specifikacija veličine operanda eksplicitna. Već po bitovima u opkodu je jasno da li se radi o bajt-operandu, illi o reč/dvostruka reč operandu.
Još se postavlja pitanje kako mašina razlikuje reči od dvostrukih reči. Za razlikovanje služi prefiks veličine operanda, koji se nalazi pre opkoda.
Značenje tog prefiksa zavisi od stanja procesora 80386.
1) Ako procesor 80386 emulira neki od svojih prethoodnika, tada je podrazumevajuuća veličina za ne bajt operande jednaka 16, tj. podrazumeva se da se radi sa rečima. Prisustvo prefiksa označava da se radi sa dvostrukim rečima
2) Ako procesor 80386 ne emulira prethodnike, tada je podrazumevajuća veličina ne bajt operanada dvostruka reč (tj. 32). Dakle, odsustvo prefiksa za veličinu operanda označava da se radi o dvostrukim rečima, a prisustvo da se radi o rečima.
Uputstvo za Turbo
Asembler
Pisanje, prevođ enje i linkovanje
programa
Programi
u asembleru se pišu i prevode slicno kao i u drugim programskim jezicima.
Taj postupak se sastoji iz nekoliko
koraka:
1.
U editoru teksta uneti kod izvornog programa (source) i dobijeni fajl sacuvati
sa ekstenzijom .asm (npr. ime_fajla.asm). Moze se koristiti bilo koji editor,
na primer Notepad ili Ultraedit koji rade pod operativnim sistemom Windows. Ako
se koristi Notepad, prilikom snimanja
preporucljivo je kompletan naziv fajla staviti u navodnike (npr. ”
vezba1.asm„).
2.
Pomoću prevodioca prevesti izvorni fajl u objektni. To se radi iz DOS
prompta (do kog se dolazi sa Start -> Programs ->Command Prompt),
izvrsavanjem naredbe:
tasm /zi/w/t ime_fajla
Primetiti
da nije potrebno navoditi ekstenziju fajla. Ukoliko prevođenje prođe bez grešaka, dobija se objektni
fajl sa ekstenzijom .obj (npr. ime_fajla.obj).
3. Pomoću linkera povezati objektni
program i prevesti ga u izvrs ni. To
se takođe radi
iz DOS prompta, komandom:
tlink /n/x/v
ime_fajla
I ovde
primetiti da nije potrebno navoditi ekstenziju fajla. Dobijeni izvrs ni fajl ime_fajla.exe se izvrs ava unos enjem imena fajla u DOS promptu
i pritiskom na taster
<Enter>.
Debagovanje
programa
Pod
debagovanjem se podrazumeva kontrolisano izvrs avanje programa radi njegovog testiranja i otklanjanja
eventualnih gres aka.
Jedan od alata koji to omogu´ava kod
asemblerskih
programa je Turbo Debugger, koji se iz DOS prompta poziva sa:
td ime_fajla
Pored
navedenog, ovaj debager omogu´ava pra´ enje i izmenu sadrzaja registara, flegova,
memorijskih lokacija i varijabli, postavljanje prekidnih tacaka itd. U nastavku ´ će ovo biti detaljnije objas njeno.
Nakon
pokretanja, dobija se osnovni prozor debagera, prikazan na slici .
Osnovni
prozor se sastoji od pet manjih prozora. Njihov broj i polozaj nije fiksan ć neki se mogu izbaciti, a neki
se mogu dodati, u zavisnosti od potrebe. Korisnik se moze kretati kroz te prozore
pritiskom na taster <Tab>.
Sa 1 je
oznacen
prozor instrukcija. U njemu su prikazane instrukcije programa u simbolickom, ali i u mas inskom obliku. Pored njih se
nalaze ofset adrese instrukcija u
kodnom
segmentu. Na adresu instrukcije koja se nalazi u programskom brojacu, pokazuje simbol u obliku
strelice. To je instrukcija koja se izvrs ava u narednom koraku. Simbol ¨ oznacava instrukciju koja se nalazi
u izvornom fajlu.
Prozor
2 je registarski prozor. U njemu je prikazano trinaest registara x86
procesora.Sadrzaj
svakog od njih, moze se
izmeniti selektovanjem odgovaraju´eg registra i upisom vrednosti u heksadecimalnom formatu.
Prozor
3 se zove indikatorski prozor. On prikazuje trenutno stanje flegova
indikatorskog (status) registra. Stanje svakog od flegova se moze promeniti, na isti nacin kao kod registarskog
prozora.
Memorijski
prozor oznacen je
brojem 4. U njemu je mogu´ e
prikazati sadrzaj
proizvoljne memorijske lokacije u heksadecimalnom i ASCII obliku. To se postize klikom na desni taster misa u ovom prozoru (ili <Alt>
+ <F10>). U dobijenom meniju treba selektovati opciju Goto, upisati
memorijsku adresu npr. ES:0 i pritisnuti <Enter>. Ukoliko zelimo izmeniti sadrzaj neke memorijske lokacije,
treba je selektovati i upisati vrednost u heksadecimalnom formatu sa nulom
ispred.
Na
kraju, peti prozor je stek prozor i on prikazuje sadrzaj steka. Strelica pokazuje na
vrh steka, tj. na adresu koja se nalazi u SP registru.
Glavni
meni u kome se nalaze opcije za konfigurisanje i rad debagera, aktivira se
tasterom <F10> ili sa <Alt> i pocetnim slovom podmenija. U podmeniju Run se nalaze
naredbe Run (<F9>), koja omogu´ ava izvrs enje
celog programa, Step over (<F8>) i Trace into (<F7>)
koje izvrsavaju
program instrukciju po instrukciju i Execute to...<Alt>+<F9>
koja izvrsava
program do instrukcije na zadatoj adresi.
Tacke prekida (breakpoints)
su mesta na kojima korisnik zeli da
zaustavi izvrsavanje
programa tokom debagovanja. Postavljaju se selektovanjem instrukcije u prozoru
instrukcija
na kojoj program treba da se zaustavi i selektovanjem opcije Toggle iz
menija Breakpoints, ili pritiskom na taster <F2>.
Ukoliko
zelimo pratiti vrednost neke
promenljive ili celog izraza u toku izvrsavanja programa, to mozemo uraditi selektovanjem opcije Add Watch iz menija Data
i unos enjem
naziva promenljive odnosno izraza, u odgovaraju´ e polje.
Izgled
ekrana u toku izvrs avanja
programa, preko koga se vrs i
komunikacija korisnika sa programom, dostupan je iz podmenija Window,
izborom opcije User screen ili pritiskom na kombinaciju tastera
<Alt> + <F5>.
Iz
debagera se izlazi biranjem opcije Quit podmenija File, ili sa
<Alt> + <X>.
Za sve
ostale opcije i nacine
njihovog koris tenja,
korisnik se upu´uje na
Help fajl integrisan u okviru ovog
softverskog alata.
Opsta
struktura asemblerskog programa
TITLE 'Ovde upisati naziv programa'
;Ime i prezime, broj indexa,
;************************************************************
;Sekcija za definisanje stek segmenta
SSEG SEGMENT STACK
DW 100 DUP(0FFFFH)
SSEG ENDS
;************************************************************
;Sekcija za definisanje segmenta podataka
DSEG SEGMENT 'data'
; ovde se pisu podaci
DSEG ENDS
;************************************************************
;Ova sekcija je kodni segment. Podprocedure definisati nakon
;glavne procedure
CSEG SEGMENT 'code'
ASSUME CS:CSEG,DS:DSEG,SS:SSEG
;********************************
;Glavna procedura
MAIN PROC FAR
MOV AX,DSEG
MOV DS,AX
;
Ovde se pise kod programa
CALL IME_PROCEDURE
EXIT: MOV AX,4C00H ;Povratak u DOS nakon
INT 21H ;zavrsetka programa
MAIN ENDP
;*********************************
;Podprocedura
; ulazni parametri:
;
; izlazni parametri:
;
IME_PROCEDURE PROC NEAR
; Ovde se pise kod procedure
RET
IME_PROCEDURE ENDP
;**********************************
CSEG ENDS
END
Mikroprocesorska
elektronika ć Vezba 2 16
VEZBA BROJ 1.
Rad sa tastaturom i
monitorom
Uvod
Ova vezba opisuje osnovne DOS funkcije
za rad sa tastaturom i monitorom racunara.
Koris ´enjem ovih funkcijskih poziva,
omogu´ava se
implementacija unosa i prikaza
podataka
preko tastature i monitora, cime se
ostvaruje jednostavna komunikacija
korisnika
sa programom. Pored toga, u vezbi ´ e biti navedeni neki BIOS
funkcijski
pozivi
koji vrs e iste
operacije, ali se koriste u slucaju
kada dobijeni kod ne sme da zavisi
od
operativnog sistema racunara.
Prikaz karaktera
Za
ispis ASCII kodiranog podatka na monitoru racunara, koriste se DOS funkcije 02h i
06h
prekida (interapta) 21h. Jedna od razlika izmeČu njih je u tome, s to se izvrs enje
funkcije
02h moze
prekinuti pritiskom na kombinaciju tastera <Ctrl> +<Break>, dok se
izvrs enje funkcije 06h ne moze prekinuti. Njihovim izvrs enjem prikazuje se karakter na
trenutnoj
poziciji kursora. Da bi izvrs ili ove
funkcije, potrebno je:
1.
Registar AH napuniti vrednos ´u 02h,
odnosno 06h koriste´ i
instrukcije MOV
AH,02H
odnosno MOV AH,06H
2. U
registar DL upisati ASCII kodiran karakter koji treba prikazati. Na primer,
ukoliko
treba
prikazati broj 2, koristiti instrukciju MOV DL,32H ili MOV DL,‘2‘.
3.
Nakon toga izvrs iti
prekid 21H, kako bi pristupili monitoru i prikazali ASCII kodiran
karakter.
Prikaz stringa
karaktera
Primenjuje
se kada je potrebno prikazati vis e od jednog karaktera. Za realizaciju ove
operacije,
koristi se DOS funkcijski poziv sa brojem 09h. String karaktera koji treba
prikazati,
mora se zavrs avati
znakom $ (odnosno 24h). Pri tome, treba uraditi slede´ e:
1. U
registar AH upisati vrednost 09h instrukcijom MOV AH,09H
2.
Napuniti adresu segmenta i ofseta stringa karaktera koga treba prikazati u
registarski
par
DS:DX. To se ostvaruje izvrs avanjem
instrukcije MOV DX,OFFSET STRING1
3. Na
kraju, izvrs iti INT
21H kako bi se na monitoru prikazao string karaktera -
STRING1
Na
slici 2 dat je primer ispisa stringa. Primetiti da string osim slovnih, sadrzi jos neke
karaktere.
Broj 13 (0Dh) predstavlja carriage return - specijalni karakter koji pomera
kursor
na krajnju levu ivicu ekrana, dok 10 (0Ah) predstavlja line feed ć karakter koji
CODE SEGMENT 'code'
ASSUME CS:CODE
MAIN PROC FAR
MOV AH,06H ;prikaz slova A
MOV DL,'A'
INT 21H
MOV DL,'B' ;prikaz slova B
INT 21H
MOV DL,'C' ;prikaz slova C
INT 21H
MOV AX,4C00H ;izlazak u DOS
INT 21H
MAIN ENDP
CODE ENDS
END
omogu´ ava prelazak u novi red. Vazno je napomenuti da su ASCII
karakteri oznaceni sa
apostrofima
(…).
Unos karaktera
Za ovu
svrhu se koriste DOS funkcije 01h i 07h. Funkcija 01h cita jedan karakter sa ehom
(cita ga i prikazuje na ekranu).
Funkcija 07h cita
unet karakter bez eha. Ako znak nije
unet,
ova funkcija ceka dok
se on ne unese. Bez obzira na to koja se funkcija koristi za
unos
karaktera, treba uraditi slede´ e:
1. U
registar AH smestiti vrednost 01h, odnosno 07h
2.
Pozvati INT 21h da bi unet karakter bio procitan.
Procitan ASCII kodiran karakter vra´ a se u registru AL.
Na
slici 3 dat je primer programa koji omogu´ava unos i prikaz unetih karaktera, sve dok
korisnik
ne pritisne taster <Enter>.
CODE SEGMENT 'code'
ASSUME CS:CODE
STRING1 DB 13,10,10,'Hello world!',13,10,10,'$'
MAIN PROC FAR
MOV AX,CS
MOV DS,AX
MOV AH,9
MOV DX,OFFSET STRING1
INT 21H
MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS
END
Ukoliko
treba napisati program tako da on ne zavisi od operativnog sistema racunara na
kome se
on izvrs ava,
moraju se koristiti BIOS (Basic I/O System) funkcijski pozivi. Oni
direktno
upravljaju radom hardverskih resursa, s to ima za posledicu smanjenje vremena
izvrs enja operacija. BIOS ekvivalent
DOS 07h funkcijskom pozivu je 00h funkcijski
poziv,
koji se aktiviraju sa INT 16h prekidom. Nacin koris ´ enja
ovih funkcija je slican
kao i
kod DOS funkcija ć u AH
registar se postavi odgovaraju´ a
vrednost (00h) i izvrs i se
INT
16H.U AL registru se vra´a ASCII
ekvivalent unetog karaktera, a u AH registru se
vra´ a njegov skan kod.
Unos stringa
karaktera
Za unos
stringa karaktera koristi se 0Ah DOS funkcijski poziv prekida 21h. On
omogu´ ava citanje stringa sa ehom i
njegovo smes tanje u
memoriju. Ukoliko doČe do
gres ke prilikom unosa, mogu´ e je vratiti kursor i ispraviti
pogres no unet
karakter. Drugim
recima, izvrs enjem ove funkcije, dobija se
jedna vrsta linijskog editora. Algoritam
koris tenja ove DOS funkcije, sastoji
se iz nekoliko koraka:
1. U AH
upisati vrednost 0Ah instrukcijom MOV AH,0AH
CODE SEGMENT 'code'
ASSUME CS:CODE
MAIN PROC FAR
MOV AH,1 ;citanje slova sa ehoom
INT 21H
CMP AL,0dh ;test za izlazak iz petlje
JNE MAIN ;skok ako nije 0dh (Enter)
MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS
END
Slika 3
2. U
DS:DX registarski par upisati segmentnu i ofset adresu prve memorijske lokacije
bafera
za smes taj
podataka koji se unose pomo´u
tastature. Pomenuti bafer mora
sadrzati prostor za podatke koji se
unose, kao i za dodatne informacije vezane za
maksimalnu
i stvarnu duzinu
stringa karaktera.
3. Izvrs iti INT 21h instrukciju kako bi
se podaci procitali i
smestili na unapred zadato
mesto u
memoriji. Unos se prekida ukoliko se pritisne taster <Enter> ili se
prepuni
bafer
za prijem podataka.
Slika
Na slici dat je primer koji omogu´ava unos maksimalno deset
karakera i smes ta ih u
memorijski
bafer BUF. Prvi bajt bafera sadrzi broj koji govori koliko maksimalno
karaktera
mozemo
upisati, a drugi bajt govori koliko je zaista karaktera uneto, pre nego
s to je pritisnut taster
<Enter>. Od tre´ eg
bajta pa nadalje nalaze se ASCII kodovi unetih
karaktera.
Primetiti
da se kao poslednji karakter u unetom stringu, u memoriju upisuje 0Dh, odnosno
carriage
return. To znaci, kada
string unet na ovaj nacin
treba prikazati koriste´ i 09h
funkcijski
DOS poziv, neophodno je 0Dh zameniti sa 24h tj …$‘ znakom.
CODE SEGMENT 'code'
ASSUME CS:CODE
BUF DB 10 ;broj karaktera koje treba procitati
DB ?
DB 11 DUP(?)
MAIN PROC FAR
MOV AX,CS
MOV DS,AX
MOV AH,0AH
MOV DX,OFFSET BUF
INT 21H
MOV AX,4C00H
INT 21H
MAIN ENDP
CODE ENDS
END
Programerski alati koji će se koristiti u ovladavanju sadržajima ovog kursa su:
EDIT - Editor (može se korisititi i neki drugi)
MASM - Makro asembler verzija 5.10
LINK - Segmentno-izvršni linker verzija 5.01.20
LIB - Program za rad sa bibliotekom asemblerskih procedura verzija 3.17
CREF - Korisnički program za razrešavanje unakrsnih referenci
CV - Dibager “Pogled u kod” verzija 2.2
Način korišćenja:
masm
[/options] source(.asm)[,[out(.obj)],[list(.lst)],[cref(.crf)][;]]
Korektne opcije su:
/a |
Upisuje segmente po alfabetskom redosledu |
/c |
Kreira datoteku sa ukrštenim referencama |
/d |
Kreira listing i pri prvom prolasku |
/D<simbol>[=<vrednost>] |
Definiše simbol |
/e |
Generiše kod koji emulira instrukcije u pokretnom zarezu |
/h |
Prikazuje stranu koja opisuje način korišćenja asemblera |
/I<put> |
Postavlja put do direktorijuma koji može da sadrži datoteke koje se uključuju |
/l[a] |
Generiše listing (a iznačava da listing sadrži sve) |
/M{lxu} |
Postavlja osetljivost na velika i mala slova kod labela |
/n |
Ne prikazuje tabelu sibola u asemblerskom listingu |
/p |
Proverava čistoću koda |
/s |
Upisuje segmente po redosledu čitanja |
/t |
Ne prikazuje poruku da je asembliranje uspešno proteklo |
/v |
Prikazuje ekstra statistiku o izvornom kodu |
/w{012} |
Postavlja nivo upozorenja: 0-Nema, 1-Ozbiljna, 2-Saveti |
/z |
Prikazuje izvornu liniju u kojo se dogodila grška |
/Zi |
Kreira simboličke informacije za CodeView |
/Zd |
Kreira informacije o broju linija |
Ukoliko se u komandnoj liniji ne navedu naziv objekt-datoteke, datoteke sa listingom ni datoteke sa unakrsnim referencama, asembler će tokom rada programera pitati da li želi kreiranje ovih datateka, i kako da se zovu.
Asembliranje se izvršava u dve faze: u prvoj se generiše tabela simbola, a u drugoj sa generiše kod.
Ako se program po kreiranju izvršnog koda treba dibagirati pomoću Code View-a, poželjno je da se uključi opcija /Zi
Način korišćenja:
link [/options] object(.obj)
[+object(.obj)...] [,[execute(.exe)], [mapping(.map)],[library(.lib)[+
library(.lib)...]]]
Neke od najvažnijih opcija su:
/CODEVIEW (/CO) |
Prenosi informacije o objektima, tako da Code View može bolje da radi |
/CPARMAXALLOC (/CP:n) |
Postavlja maksimalan broj ekstra memorijskih paragrafa na zadatu vrednost |
/DOSSEG (/DO) |
Uređuje segmente u skladu sa konvencijom za Microsoftove jezike |
/EXEPACK (/E) |
Kompresuje ponavljajuće sekvence bitova |
/FARCALLTRANSLATION (/FC) |
Generše se kod sa prevođenjem poziva u daleke pozive |
/HELP (/HE) |
Prikazuje stranu koja opisuje način korišćenja linkera |
/HIGH (/HI) |
Smešta izvršni kod u što je moguće višu memoriju |
/LINENUMBERS (/LI) |
Kopira informacije o brojevima linija |
/MAP (/M) |
Kopira u datoteku mapiranja listu svih javnih simbola deklarisanih u objekt datoteci |
/NODEFAULTLIBRARYSEARCH (/NOD) |
Pretaga za bibliotekama se svodi na pretragu biblioteka specificiranih u komandnoj liniji |
/NOFARCALLTRANSLATION (/NFC) |
Ne generše se kod sa prevođenjem poziva u daleke pozive |
/NOIGNORECASE (/NOI) |
Pravi razliku između velikih i malih slova |
/PAUSE (/P) |
Pauzira i pita korisnika da promeni disk pre upisa izvršne datoteke |
/SEGMENTS:n (/SE:n) |
Postavlja maksimalan broj segmenata koji mogu biti obrađeni |
/STACK (/ST:n) |
Postavlja veličinu steka |
Ako se program po kreiranju izvršnog koda treba dibagirati pomoću Code View-a, poželjno je da se uključi opcija /CO
Način korišćenja:
lib [/options]
library [options] [commands] [,listfile [,newlibrary]]
Neke od najvažnijih opcija su:
/IGNORECASE |
Ignoriše razliku između velikih i malih slova |
/NOEXTDICTIONARY |
Ne gradi rašireni rečnik |
/NOIGNORECASE |
Ne ignoriše razliku između velikih i malih slova |
/NOLOGO |
Ne prikazuje logo |
/PAGESIZE:n |
Postavlja veličinu strane u biblioteci |
Komande su:
+name |
Dodaje objekt datoteku u biblioteku |
-name |
Briše objekt datoteku iz biblioteke |
-+name |
Zamenjuje objekt datoteku u biblioteci |
*name |
Kopira (ekstrahuje) objekt datoteku iz biblioteke |
-*name |
Premešta (ekstrahuje i briše) objekt datoteku iz biblioteke |
Način korišćenja:
cv
[/options] file [arguments]
Neke od najvažnijih opcija su:
/T |
Startuje dibager u terminalskom modu |
/43 |
Radi u 43-kolonskom formatu, tj. prikaz teksta ide u 43 kolone |
/50 |
Radi u 50-kolonskom formatu, tj. prikaz teksta ide u 50 kolona |
Ako dibager Code View ne radi u terminalskom modu, pojavljuju se komandni (terminalski) prozor, prozor sa registrima (uključujući i registar flegova), te programski prozor. Prelazak iz jednog u drugi prozor realizuje se pritiskom na taster F6. Pored toga, postoji i padajući meni iz kog se opcije biraju na standardni način.
Instrukcije prenosa podataka se dele u tri grupe: prenos opšte namene, prenos specificiran akomulatorom i prenos flegova.
MOV D, S (eng. move - prenos) - S ® D. Ova dva operanda instrukcije MOV moraju biti iste dužine. Jedan od operanada mora biti registarski ili neposredno specificiran.
MOVZX D, S (eng. move zero extended - prenos sa raširenom nulom) - S ® (nulom raširen) D. Jedan od operanada ove instrukcije mora biti registarski ili neposredno specificiran. Ova instrukcija nije postojala kod prethodnika procesora 80386.
MOVSX D, S (eng. move sign extended - prenos sa raširenim znakom) - S ® (znakom raširen) D. Jedan od operanada ove instrukcije mora biti registarski ili neposredno specificiran. Ni ova instrukcija nije postojala kod prethodnika procesora 80386.
XCHG D, S (eng. exchange - razmena) - S « D. Razmenjuju se vrednosti izvornog i odredišnog operanda. Kod ove instrukcije jedan od operanada mora biti registarski ili neposredno specificiran.
Primer.
U sledećim instrukcijama je ilustrovan način korišćenja instrukcija MOV, MOVZX, MOVSX, XCHG.
MOV AH, BH MOV BX, DX MOV EAX, ESI MOV BL, 35 MOV CX, 850 |
MOV EAX, mem MOVSX AX, BL MOVZX BX, AL MOVSX EDX, mem MOVZX ECX, CX |
XCHG AL, AH
XCHG CX, DX
XCHG EAX, ESI
CBW (eng. convert byte to word - konvertuj bajt u reč) - AL ® (znakom raširen) AX. Instrukcija nema operanada.
CWD (eng. convert word to doubleword - konvertuj reč u dvostruku reč) - AX ® (znakom raširen) DXAX. Instrukcija nema operanada.
Ove dve prethodno pomenute instrukcije su postojale i kod prethodnika procesora 80386. Sa stanovišta procesora 80386, prethodno obrađena instrukcija MOVSX predstavlja uopštenje ovih instrukcija. O instrukcijama CBW i CWD će biti reči i pri obrađivanju instrukcija za celobrojno množenje i deljenje.
Da bi se moglo izvršavati guranje elemenata na stek, i skidanje elemenata sa steka, potrebno je specificirati veličinu memorijskog prostora odvojenog za stek. Nadalje, potrebno je postaviti segmentni registar SS na segmentnu adresu početka steka, tj. 16-bitni registar SS treba da pokazuje na početak prostora u memoriji (segmenta) u kom se stek nalazi (SS je tada stek segment, odnosno selektor steka). Na kraju, treba postaviti registar ESP (odnosno SP kod 16-bitnih segmenata) tako da ukazuje na vrh steka. Taj registar neće sadržati apsolutnu adresu vrha steka, već vrednost offset-a u odnosu na početak memorijskog segmenta koji je odvojen za stek (tj. offset-a u odnosu na vrednost registra SS). Dakle, ESP će pokazivati na poslednji element (reč ili dvostruku reč) koja je unesena na stek.
Ovo odvajanje memorijskog prostora i postavljanje vrednosti registara se može izvršiti automatski pomoću odgovarajućih pseudooperacija.
Primer.
Registri SS i SP će biti “automatski” postavljeni na prave vrednosti, zahvaljujući asembleru MASM i linkeru LINK, ako se u izvornom kodu nalazi sledeći konstrukt:
STEK SEGMENT STACK
DW 100H DUP(?)
STEK ENDS
Za ovako oformljen stek biće odvojeno 256 reči (512 bajtova), čija vrednost nije inicijalizovana.
Instrukcije za guranje na stek i skidanje sa steka su:
PUSH S (eng. push - gurni) - S ® stek. Izvorni operand se smešta na stek. Argumenat ove instrukcije je reč ili dvostruka reč, a počev od procesora 80386 kod ove instrukcije može figurisati i neposredno adresiranje.
POP D (eng. pop - skini) - stek ® D. Vrednost sa vrha steka se smešta u odredišni operand. Argumenat ove instrukcije je reč ili dvostruka reč.
Primer.
Opisuje način realizacije PUSH instrukcije.
Početno stanje
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
|
esp: |
f |
f |
f |
f |
9 |
0 |
7 |
0 |
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
eax: |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
|
|
|
||
|
ebx: |
9 |
a |
b |
c |
d |
e |
f |
0 |
|
|
|
||
|
|
|
|
|
|
|
|
|
|
ffff9070: |
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
PUSH EAX
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
|
esp: |
f |
f |
f |
f |
9 |
0 |
6 |
c |
ffff906c: |
7 |
8 |
||
|
|
|
|
|
|
|
|
|
|
|
5 |
6 |
||
|
eax: |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
|
3 |
4 |
||
|
ebx: |
9 |
a |
b |
c |
d |
e |
f |
0 |
|
1 |
2 |
||
|
|
|
|
|
|
|
|
|
|
ffff9070: |
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
POP BX
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
|
esp: |
f |
f |
f |
f |
9 |
0 |
6 |
e |
|
7 |
8 |
||
|
|
|
|
|
|
|
|
|
|
|
5 |
6 |
||
|
eax: |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
ffff906e: |
3 |
4 |
||
|
ebx: |
9 |
a |
b |
c |
5 |
6 |
7 |
8 |
|
1 |
2 |
||
|
|
|
|
|
|
|
|
|
|
ffff9070: |
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
Primećuje se da se pri stavljanu na stek vrednost ESP smanjuje, a da se pri skidanju sa steka vrednost ESP povećava.
Izvršenje instrukcije PUSH započinje sa umanjenjem sadržaja ESP za potrebnu veličinu, pa se tek potom vrši prenos u memoriju. Kod instrukcije POP se prvo vrši prenos podataka, a potom sa uvećava ESP.
PUSHAD (eng. push all doublewords - gurni sve dvostruke reči) - opšti registri ® stek. Sadržaj opštih registara se gura na stek. Ova instrukcija nema operanada. Ona postoji kod procesora 80386 i njegovih sledbenika (potomaka).
POPAD (eng. pop all doublewords - skini sve dvostruke reči) - stek ® opšti registri. Vrednosti sa steka se smeštaju u opšte registre. Ni ova instrukcija nema operande. Ta instrukcija nije postojala kod prethodnika procesora 80386.
Instrukcija PUSHAD će registre na stek gurnuti po sledećem redosledu: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, pri čemu se na stek gura vrednost koju je ESP imao pre izvršenja instrukcije PUSHAD. Instrukcija POPAD će, naravno, vrednosti sa steka skidati u obrnutom redosledu.
PUSHA (eng. push all - gurni sve) - 16-bitni opšti registri ® stek. Sadržaj opštih registara se gura na stek. Ova instrukcija nema operanada.
POPA (eng. pop all - skini sve) - stek ® 16-bitni opšti registri. Vrednosti sa steka se smeštaju u opšte registre. Ni ova instrukcija nema operande.
Instrukcije PUSHA i POPA izvršavaju ekvivalentne operacije kao PUSHAD i POPAD, samo sa 16-bitnim registrima, a osnovni razlog njihovog postojanja je kompatibilnost sa prethodnicima procesora 80386.
Primer.
PUSH AX PUSH ECX POP BX POP EBP |
POPAD POPA PUSHAD PUSHA |
Ilustruje primenu instrukcija za prenos podataka sa steka i na stek.
Kod ovih prenosa samo akumulator (registar AL, AX, EAX) može da se javi kao operand.
IN D, S (eng. in - u) - ulazni port ® akumulator. Ova instrukcija realizuje prenos odredjenog broja bitova sa ulaznog porta u akumulator (tj. registar AL, AX, EAX). Broj porta sa kog se unose podaci može biti specificiran bilo direktno, bajtom (tada je najveći broj porta 255), bilo indirektno, sadržajem DX registra.
OUT D, S (eng. out - napolje, van) - akumulator ® izlazni port. Instrukcija OUT realizuje prenos odredjenog broja bitova iz akumulatora (tj. registra AL, AX, EAX) u izlazni port. Broj porta na koji se šalju podaci može biti odredjen bilo direktno, bajtom (tada je najveći broj porta 255), bilo indirektno, sadržajem DX registra.
DX registar je jedini od registara koji kod ove dve instrukcije može služiti za specificiranje porta.
Primer.
IN AL, 1 IN AX, 10 IN EAX, 8 OUT 50, OUT 30, AX OUT 5, EAX |
MOV DX, 7 IN EAX, DX MOV DX, 5H OUT |
Ilustruje način korišćenja instrukcija IN i OUT.
XLATB (eng. translate - prenos prevodjenje) - niz (AL) ® AL. Prevodi vrednost AL-a. Ova instrukcija nema operande.
Ova instrukcija vrši prevodjenje tako što se vrednost u registru AL zameni sa AL-tim bajtom iz niza u memoriji na koji pokazuje registar EBX. Odbrojavanje u nizu počinje od 0. Kod ove instrukcije nijedan drugi registar sem EBX ne može da se koristi kao pokazivač na niz u memoriji. Dakle, ovakvo korišćenje registra EBX predstavlja još jedan slučaj specijalizovanog korišćenja registra (specijalizovano korišćenje registara je postojalo i kod insttrukcija IN i OUT).
Primer.
Ilustruje izvršavanje XLATB instrukcije.
Početno stanje:
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
|
ebx: |
5 |
6 |
3 |
4 |
F |
1 |
E |
2 |
|
E |
2 |
||
|
|
|
|
|
|
|
|
|
|
5634f1e2: |
F |
1 |
||
|
eax: |
a |
a |
b |
b |
5 |
5 |
0 |
4 |
|
3 |
4 |
||
|
|
|
|
|
|
|
|
a |
l |
|
5 |
6 |
||
|
|
|
|
|
|
|
|
|
|
|
7 |
8 |
||
|
|
|
|
|
|
|
|
|
|
5634f1e6 |
9 |
A |
||
|
|
|
|
|
|
|
|
|
|
|
0 |
1 |
||
|
|
|
|
|
|
|
|
|
|
|
0 |
2 |
||
|
|
|
|
|
|
|
|
|
|
|
0 |
3 |
||
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
XLATB
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
|
ebx: |
5 |
6 |
3 |
4 |
F |
1 |
E |
2 |
|
E |
2 |
||
|
|
|
|
|
|
|
|
|
|
5634f1e2: |
F |
1 |
||
|
eax: |
a |
a |
b |
b |
5 |
5 |
9 |
A |
|
3 |
4 |
||
|
|
|
|
|
|
|
|
a |
l |
|
5 |
6 |
||
|
|
|
|
|
|
|
|
|
|
|
7 |
8 |
||
|
|
|
|
|
|
|
|
|
|
5634f1e6 |
9 |
A |
||
|
|
|
|
|
|
|
|
|
|
|
0 |
1 |
||
|
|
|
|
|
|
|
|
|
|
|
0 |
2 |
||
|
|
|
|
|
|
|
|
|
|
|
0 |
3 |
||
|
|
|
|
|
|
|
|
|
|
|
... |
|
||
Dakle, izvršenjem instrukcije XLATB, vrednost registra AL se od 04H transformisala u 9AH.
Značaj i uloga flegova je opisana u poglavlju koje se odnosilo na arhitekturu procesora 80386.
Primer.
Pokazuje kako su raspoređene pozicije ćelija koje predstavljaju flegove u registru flegova EFLAGS.
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
VM |
RF |
0 |
NT |
IO PL |
OF |
DF |
IF |
TF |
SF |
ZF |
0 |
AF |
0 |
PF |
1 |
CF |
LAHF (eng. load AH with flags - napuni AH sa fllegovima) - SF, ZF. 0, AF, 0, PF, 1, CF ® AH. Bajt najmanje težine iz registra flegova EFLAGS se premešta u registar AH. Ova instrukcija nema operande.
SAHF (eng. store AH into flags - smesti AH u fllegove) - AH ® SF, ZF. X, AF, X, PF, X, CF. Sadržaj registra AH premešta u bajt najmanje težine registra flegova EFLAGS. Ni ova instrukcija nema operande.
Primer.
Ilustruje na kojim pozicijama se čuvaju flegovi u registru AH, po izvršenju instrukcije LAHF.
SF |
ZF |
0 |
AF |
0 |
PF |
1 |
CF |
PUSHFD (eng. push flags doubleword - gurni dvostruku reč flegova) - EFLAGS ® stek. Sadržaj registra EFLEGS ide na stek. Ova instrukcija nema operande. Ona postoji tek kod skupa instrukcija procesora 80386.
POPFD (eng. pop flags doubleword - skini dvostruku reč flegova) - stek ® EFLAGS. Sa steka se skidaju 4 bajta koji se smeštaju u registar EFLAGS. Ni ova instrukcija nema operande, a postoji tek kod procesora 80386 i njegovih potomaka.
PUSHF (eng. push flags - gurni flegove) - 0, NT, IOPL, OF, DF, IF, TF, SF, ZF, 0, AF, 0, PF, 1, CF ® srek. Reč manje težine iz registra EFLAGS smešta se na stek. Instrukcija ne sadrži operande.
POPF (eng. pop flags - skini flegove) - stek ® 0, NT, IOPL, OF, DF, IF, TF, SF, ZF, 0, AF, 0, PF, 1, CF. Sa steka se skidaju 2 bajta i smeštaju u donju polovinu registra EFLAGS. Instrukcija nema operande.
Primer.
Ilustruje na kako se flegovi čuvaju na steku.
|
|
|
|
. |
. |
. |
|
|
ESP® |
SF |
ZF |
0 |
AF |
0 |
PF |
1 |
CF |
|
0 |
NT |
IO |
PL |
OF |
DF |
IF |
TF |
|
0 |
0 |
0 |
0 |
0 |
0 |
VM |
RF |
|
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
|
|
|
|
. |
. |
. |
|
|
Aritmetičke instrukcije delimo u tri grupe: instrukcije sabiranja, instrukcije oduzimanja i instrukcije množenja i deljenja.
[est statusnih flegova su postavljeni ili obrisani (tj. statusne zastavice su dignute ili spuštene) kada se pri izvršenju instrukcije prepoznaju sledeći uslovi:
1) CF se postavlja kada rezultat operacije, tumačen kao neoznačen broj, dovede do iskakanja iz opsega.
2) OF se postavlja kada rezultat operacije, tumačen kao označen bbroj dovede do iskakanja iz opsega.
3) ZF se postavlja ako je rezultat operacije 0 tj. ako su sve binarne cifre rezultata nule.
4) SF se postavlja ako je bit najveće težine 1, i na taj način indicira da je rezultat negativan.
5) PF se postavlja ukoliko 8 bitova najmanje težine kod rezultata sadrži paran broj jedinica.
6) AF se postavlja kada je potrebna korekcija za decimalne operacije.
Već je istaknuto da PF ukazuje na parnost broja jedinica u poslednjem bajtu rezultata. To je kod rodonačelnika ove familije procesora omogućavalo kontrolu parnosti osmobitnog serijskog ulaza podataka. Iako se potreba vodjenja kontrole na ovakav način već odavno izgubila, fleg je ostao zbog očuvanja kompatibilnosti.
Rad sa brojevima dužim od 32 bita se izvršava tako što se ti brojevi razbijaju na delove dužine 8, 16, 32 i potom se operacije izvršavaju na tako dobijenim delovima, počev od delova najmanje težine.
Tu spadaju instrukcije ADD, ADC, INC.
ADD D, S (eng. add - saberi) - D+S ® D.
ADC D, S (eng. add with carry - saberi sa prenosom) - D+S+CF ® D.
INC D (eng. inerement - inkrementiraj, uvećaj za 1) - D+1 ® D.
Prve dve medju ovim instrukcijama imaju tačno dva operanda. One zahtevaju da bar jedan od operanada bude registarski ili neposredno adresiran.
Instrukcija INC ima jedan operand. Ova instrukcija je po svom dejstvu ista kao ADD insstrukcija čiji je drugi operand 1, osim što pri kodiranju zahteva manje bajtova i što njeno izvršenje ne utiče na CF.
Tu spadaju: SUB, SBB, DEC, NEG, CMP.
SUB D, S (eng. subtract - oduzmi) - D-S ® D.
SBB D, S (eng. subtract with borrowe - oduzmi sa pozajmljivanjem) - D-S-CF ® D.
DEC D (eng. decrement - dekrementiraj, umanji za 1) - D-1 ® D.
NEG D (eng. negate - negiraj, promeni znak) - 0-D ® D.
CMP D, S (eng. compare - uporedi) - odredi se D-S i u skladu sa tim postave se odgovarajući flegovi.
Prve tri medju ovim instrukcijama su analogne odgovarajućim, prethodno opisanim instrukcijama sabiranja.
Intrukcija NEG vrši promenu znaka operanda, pod uslovom da se broj tumači kao označen broj. Faktički, ova instrukcija u odredišni operand smešta njegov potpuni komplement.
Primer.
Ilustruje način izvršenja instrukcije NEG.
Početno stanje:
al: |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
= |
3 |
NEG
al: |
1 |
1 |
1 |
1 |
1 |
1 |
0 |
1 |
= |
-3 |
Instrukcija CMP odgovara instrukciji oduzimanja, samo što se dobijeni rezultat ne smešta nigde. Naime, odredišni operand ostaje nepromenjen. Značaj ove instrukcije je u postavljanju flegova. Flegovi indiciraju stanje razlike, koje faktički pokazuje kakav je odnos između operanada instrukcije CMP.
Postavljanje flegova je prikazano sledećom tabelom:
|
|
CF |
ZF |
SF |
OF |
|
jednako |
0 |
1 |
0 |
0 |
|
manji |
- |
0 |
1 |
0 |
Označeni operandi |
manji |
- |
0 |
0 |
1 |
|
veći |
- |
0 |
0 |
0 |
|
veći |
- |
0 |
1 |
1 |
|
jednako |
0 |
1 |
0 |
0 |
Neoznačeni operandi |
ispod |
1 |
0 |
- |
- |
|
iznad |
0 |
0 |
- |
- |
To su operacije: MUL, IMUL, DIV, IDIV.
MUL S (eng. multiply - pomnoži) -
AL*S8 ® AX,
ili AX*S16 ® DXAX,
ili EAX*S32 ® EDXEAX.
MUL D, S (eng. multiply - pomnoži) - D*S ® D. Ovakva forma instrukcije karakteriše procesor 80386 i njegove potomke.
MUL D, H, S (eng. multiply - pomnoži) - H*S ® D. Ovde S predstavlja neposredno zadat operand (tj. broj), a H je bilo memorijski bilo registarski operand. Ovakva forma instrukcije takođe karakteriše procesor 80386 i njegove potomke.
IMUL S (eng. imteger multiply - celobrojno množenje, množenje označenih brojeva) -
AL*S8 ® AX,
ili AX*S16® DXAX,
ili EAX*S32 ® EDXEAX.
IMUL D, S (eng. imteger multiply - celobrojno množenje, množenje označenih brojeva) - D*S ® D. Ovakva forma instrukcije karakteriše procesor 80386 i njegove potomke.
|
|
IMUL D, H, S (eng. imteger multiply - celobrojno množenje, množenje označenih brojeva) - H*S ® D. Kao i kod instrukcije MUL, i ovde S predstavlja neposredno zadat operand (tj. broj), a H je bilo memorijski bilo registarski operand. Ovakva forma instrukcije takođe postoji isključivo kod procesora 80386 i njegovih potomaka.
DIV S (eng. divide - podeli) -
AX div S8 ® AL i AX mod S8 ® AH,
ili DXAX div S16 ® AX i DXAX mod S16 ® DX,
ili EDXEAX div S32 ® EAX i EDXEAX mod S32 ® EDX.
IDIV S (eng. integer divide - celobrojno deljenje, deljenje označenih brojeva) -
AX div S8 ® AL i AX mod S8 ® AH,
ili DXAX div S16 ® AX i DXAX mod S16 ® DX,
ili EDXEAX div S32 ® EAX i EDXEAX mod S32 ® EDX.
|
|
Instrukcije deljenja za procesor 80386 (a i za njegove prethodnike) su dizajnirane tako da ponište ono što je urađeno instrukcijom množenja. Sledeće sheme prikazuju izvršenje operacije deljenja:
Ima jedna “nezgoda” sa instrukcijom deljenja. Ona se naziva prekoračenje pri deljenju (eng. divide overflow). Prekoračenje pri deljenju nastupa onda kada je količnik pri deljenju suviše veliki tako da se ne može smestiti u željeni registar (to se događa kada se nešto suviše veliko deli sa nečim mnogo malim). Za razliku od prekoračenja pri sabiranju i oduzimanju, nema smislenog načina za nastavak rada sa ovako dobijenim rezultatom, pa u ovom slučaju procesor generiše prekid (eng. interupt) tipa 0. Deljene sa nulom je samo jedna, ali ne i jedina mogućnost prekoračenja pri deljenju.
Da bi se pri radu sa označenim brojevima dobili tačni rezultati, potrebno je koristiti instrukcije IMUL i IDIV. [to se celobrojnog deljenja tiče, treba napomenuti da se ono izvršava tako da dobijeni količnik i ostatak budu istog znaka.
Primer.
Mada obe jednakosti važe, celobrojno deljenje se kod procesora 80386 realizuje na drugi način:
(-26):7=-4(+2)
(-26):7=-3(-5)
Primer.
mov al, 56 cbw idiv bl
mov AX, 56 cwd |
IDIV BX MUL BL ; AL*BL->AX IMUL CX ; AX*CX->DXAX IMUL EBX ; EAX*EBX->EDXEAX IMUL DX, BX,300 ; BX*300->DX IMUL CX,3 ; CX*3->CX IMUL EAX, EDX, 100000 ; EDX*100000->EAX IMUL EBP,500 ; EBP*500->EBP IMUL BX, CX ; BX*CX->BX IMUL EDX, EBP ; EDX*EBP->EDX |
Ilustruje korišenje instrukcija množenja i deljenja.
Primer.
mov al, 56 MOV AH, 0 div bl |
mov AX, 56 MOV DX, 0 DIV BX |
Ilustruje potrebu da se delilac proširi do potrebne dužine pre nego što se izvrši deljenje (korišćenjem forme instrukcije DIV ili IDIV sa jednim operandom).
Zadatak. Opisati
sadržaj opštih registara po izvršenju svake od instrukcija u sledećem
segmentu asmblerskog koda:
MOV AX, 5 MOV BX, 4 SUB AX, 2 IMUL BX |
MOV BX, AX MOV CX, AX MOV DX, AX INC CX |
a) b)
c)
MOV DX, 8
MOV AX, 9
SUB DX, 4
MUL DX
MOV CX, DX
INC CX
SUB CX, 1
MOV CX, 3 ADD CX, 5 MOV BX, CX INC BX MOV AX, BX |
MOV EAX, 6 MOV EBX, 4 MOV ECX, 5 ADD EAX, EBX SUB EAX, 3 IMUL EBX |
d) e)
Zadatak. Napisati
program na asemblerskom jeziku koji u registar CX smešta vrednost izraza
5*(7+1)-6.
Već je istaknuto da postoji više načina modifikacije operanda, tj. više različitih adresnih modova. Pokazano je da adresiranje pomoću neki od tih adresnih modova zahteva sabiranje vrednosti i/ili množenje vrednosti sa faktorima skaliranja. Stoga, mora da postoji hardver koji podržava te operacije, pa je poželjno da se programeru omogući direktniji pristup ovim mehanizmima.
LEA D, S (eng. load effective adress - napuni efektivnu adresu) - adresa(S) ® D. Ova instrukcija u odredište smešta efektivnu adresu izvornog memorijskog operanda.
Primer.
Opisuje najčešći način korišćenja instrukcije LEA: za dobijanje pokazivača na neku memorijsku adresu. Tako će registar ESI će sadržati efektivnu memorijsku adresu lokacije NIZ po izvršenju instrukcije
LEA ESI, NIZ.
Treba napomenuti da isti efekat ima i korišćenje pseudoinstrukcije OFFSET, pa se prethodna instrukcija može zameniti sa MOV ESI, OFFSET NIZ, koja će imati isti efekat. Druga varijanta oformljuje za bajt kraći program, ali ima situacija u kojima se ona ne može primeniti, već se mora raditi sa instrukcijom LEA.
Primer.
MOV ESI, 10 ADD ESI, EBX ADD ESI, EDI |
LEA ESI,[EBX+EDI+10] |
Ilustruje korišenje instrukcije LEA. Sledeća dva segmenta asemblerskog koda realizuju isti posao: smeštaju u ESI zbir EDI+EBX+10
Primer.
Ilustruje važnu osobinu instrukcije LEA: prilikom njenog izvršenja ne postavljaju se niti brišu flegovi. Neka treba uvećati sadržaj registra EBX za 4. Neka je već napravljen test memorijske lokacije na koju pokazuje EBX i neka tako dobijene flegove ne treba menjati (jer u zavisnosti od vrednosti tako postavljenih flegova se preduzimaju dalje akcije).
- jedan dobar način za uvećanje vrednosti EBX za 4, a da se ne promene vrednosti flegova je izvršenje PUSHFD (ili PUSHF) pre uvećanja EBX, i izvršenje POPFD (POPF) posle uvećanja EBX.
- drugi, bolji, način za postizanje istog cilja je instrukcija LEA EBX, [EBX+4].
Dekadni brojevi se dugo i mnogo koriste u računarstvu. Oni su izuzetno važni u poslovnim primenama računara.
0 1 2 3 4 5 6 7 8 9 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 |
Binarno kodirani dekadni (BCD) brojevi predstavljaju najpopularnije kodiranje dekadnih brojeva:
Kod BCD brojeva razlikuju se pakovani i nepakovani BCD brojevi. Kod pakovanih BCD brojeva, BCD cifra se pakuje (smešta) u polubajt. Kod nepakovanih BCD brojeva se u jedan bajt smešta jedna cifra.
Obično se decimalni brojevi kodiraju tako što se smeste u niz uzastopnih bajtova, pri čemu je na prvom mestu binarni broj koji predstavlja broj cifara potrebnih za zapis dekadnog broja.
Primer.
Broj -125 se na sledeći način predstaviti kao pakovani BCD broj:
tri cifre |
minus |
1 |
2 |
5 |
0011 |
1000 |
0001 |
0010 |
0101 |
Odmah se, logično, postavlja pitanje načina realizacije osnovnih aritmetičkih operacija sa pakovanim i nepakovanim BCD brojevima. Jasno je da se operacije sa BCD brojevima moraju izvršavati cifra po cifra. Ostaje tada pitanje načina izvršavanja operacija sa BCD ciframa. Treba istaći da ne postoje specijalne operacije za sabiranje, oduzimanje, množenje cifara BCD brojeva, već se na cifre primene poznate instrukcije ADD, SUB, MUL (IMUL) i DIV(IDIV). Budući da tako dobijeni rezultat (tumačen sa stanovišta BCD brojeva) nije korektan, potrebno je dodati popravku.
Primer.
Ilustruje kakve se popravke trebaju uvesti u raznim slučajevima sabiranja cifara pakovanih BCD brojeva.
1) Pri sabiranju dvocifrenih pakovanih BCD brojeva 23 i 14, treba da se dobije 37. Prostim bitovnim sabiranjem, tj. instrukcijom ADD se i dobija ta vrednost, tj. korektan rezultat.
2) Neka treba sabrati dva dvocifrena pakovana BCD broja 75 i 29. Po izvršenju bitovnog sabiranja, bajt rezultata će sadržati 9E. Korektan rezultat bi bio 04, pri čemu bi trebalo (jer ima prenosa sa mesta najveće težine rezultata) da se CF postavi na 1.
3) Neka treba sabrati dva dvocifrena pakovana BCD broja 38 i 29. Po izvršenju bitovnog sabiranja, bajt rezultata će sadržati 61. Korektan rezultat bi bio 67.
Dakle, uvođenje popravke kod sabiranja cifara pakovanih BCD brojeva svodi se na dodavanje broja 6 na donji polubajt rezultata, ukoliko je vrednost tog donjeg polubajta rezultata veća ili jednaka od deset ili je AF postavljen na 1. Potom se doda broj 6 na gornji polubajt, pod uslovom da je vrednost gornjeg polubajta ne manja od 10.
Na analogan način se može opisati kakve je vrste popravka koju treba uvesti pri sabiranju nepakovanih BCD brojeva, ili pri oduzimanju, množenju i deljenju. Instrukcije procesora 80386 za uvođenje popravki su:
DAA (eng. decimal adjust after adition - decimalno podešavanje posle sabiranja) - AL ® popravljen AL. Ova instrukcija u AL smešta popravljenu vrednost AL-a, da odgovara zbiru parova pakovanih BCD cifara, po prethodno izvršenom binarnom sabiranju. Dakle, ona vrši konverziju binarnog broja u odgovarajući pakovani BCD broj. Instrukcija nema operanada. Po uvođenju popravke, CF će biti postavljen ukoliko stvarno treba biti prenosa pri sabiranju pakovanih BCD cifara. U suprotnom, CF će biti obrisan.
DAS (eng. decimal adjust after subtraction - decimalno podešavanje posle oduzimanja) - AL ® popravljen AL. Instrukcija DAS smešta u AL popravljenu vrednost AL-a, da odgovara razlici parova pakovanih BCD cifara, po prethodno izvršenom binarnom oduzimanju. Ni ova instrukcija nema operanada. Po uvođenju popravke, CF će biti postavljeno ukoliko stvarno treba biti prenosa pri oduzimanju pakovanih BCD cifara. U suprotnom, CF će biti obrisano.
Primer.
MOV AL, 75D MOV BL, 29 ADD AL, BL DAA |
MOV AL, 75D MOV BL, 29 SUB AL, BL DAS |
Napisati delove asemblerskog koda za sabiranje i za oduzimanje brojeva 75 i 29, i testirati njegov rad.
Množenje i deljenje BCD brojeva moguće je samo u nepakovanom obliku.
Sledeća tabela pokazuje ASCII kodove svih sekadnih cifara (vidimo da se donji polubajt ASCII koda poklapa sa vrednošću odgovarajuće dekadne cifre).
cifra |
ASCII kod (heksadekadni) |
ASCII kod (dekadni) |
cifra |
ASCII kod (heksadekadni) |
ASCII kod (dekadni) |
0 |
30H |
48 |
5 |
35H |
53 |
1 |
31H |
49 |
6 |
36H |
54 |
2 |
32H |
50 |
7 |
37H |
55 |
3 |
33H |
51 |
8 |
38H |
56 |
4 |
34H |
52 |
9 |
39H |
57 |
Dakle, prelazak između ASCII koda cifre i njenog nepakovanog BCD zapisa je krajnje jednostavan, direktan i kratkotrajan.
Očigledno je da se za slučaj nepakovanih BCD brojeva popravka radi dobijanja korektnog zbira, odnosno korektne razlike, mora izvršiti drugačije nego u pakovanom slučaju.
Stoga, za uvođenje te popravke procesor 80386 ima druge instrukcije:
AAA (eng. ASCII adjust after adition - ASCII podešavanje posle sabiranja) - AL ® popravljen AL. Ova instrukcija u AL smešta popravljenu vrednost AL-a, da odgovara zbiru nepakovanih BCD cifara, po prethodno izvršenom binarnom sabiranju. Dakle, ona vrši konverziju binarnog broja u odgovarajući nepakovani BCD broj. Instrukcija nema operanada. Po uvođenju popravke, CF će biti postavljeno ukoliko stvarno treba biti prenosa pri sabiranju pakovanih BCD cifara. U suprotnom, CF će biti obrisano.
AAS (eng. ASCII adjust after subtraction - ASCII podešavanje posle oduzimanja) - AL ® popravljen AL. Instrukcija AAS smešta u AL popravljenu vrednost AL-a, da odgovara razlici pakovanih BCD cifara, po prethodno izvršenom binarnom oduzimanju. Ni ova instrukcija nema operanada. Po uvođenju popravke, CF će biti postavljeno ukoliko stvarno treba biti prenosa pri oduzimanju pakovanih BCD cifara. U suprotnom, CF će biti obrisano.
AAM (eng. ASCII adjust after multiplication - ASCII podešavanje posle množenja) - AX ® popravljen AX. Instrukcija AAM konvertuje binarni broj iz AX u odgovarajući dvocifren nepakovan BCD broj. Ona smešta u AX popravljenu vrednost iz AX, tako što se izvrši celobrojno deljenje broja u AL sa10, količnik se smesti u AH, a ostatak u AL. Dakle, ova instrukcija radi isto što i instrukcija deljenja, samo što se rezultati smeštaju u neke druge registre.
Primer.
Neka treba pomnožiti brojeve 9 i 4. Tada se u registar BL smesti broj 09H (MOV BL, 9), a u registar AL broj 04H (MOV AL, 4). Izvršenjem instrukcije IMUL BL dobija se 36D u registru AX, tj. 16-bitni registar AX sadrži 0024H. Jasno je da ovaj rezultat ne može da se tumači kao BCD broj. Međutim, po primeni instrukcije AAM dobija se u AL vrednost 06, a u AH 03, pa sada dva bajta registra AX sadrže cifre proizvoda u nepakovanom BCD formatu.
AAD (eng. ASCII adjust before division - ASCII podešavanje pre deljenja) - AX ® popravljen AX. Instrukcija AAM konvertuje dvocifren nepakovan BCD broj iz AX u odgovarajući binarni broj. Za razliku od prethodnih instrukcija, ovde dodavanje popravke treba izvršiti pre, a ne posle deljenja. Instrukcija AAD se izvršava tako što se vrednost iz AH pomnoži sa 10 i doda na vrednost u registru AL. Zbir se potom smesti u AX.
Primer.
Neka treba podeliti BCD brojeve 42 i 6. Dakle, količnik treba da bude 7, a ostatak 0. Tada se u registar AX smesti broj 0402H=1050D (što i predstavlja nepakovan BCD zapis broja 42D), a u registar AL broj 06H. Jasno je da će se, ukoliko se odmah izvrši deljenje, dobiti nekorektan rezultat. Popravka se uvodi izvršenjem instrukcije AAD. Po izvršenju ove instrukcije se u AX registar smešta 10*4+2=42D=002AH. Ako se sada primeni instrukcija IDIV, dobiće se korektan količnik (u registru AL) i ostatak (u registru AH).
Zadatak. Opisati
sadržaj opštih registara po izvršenju svake od instrukcija u sledećem
segmentu asmblerskog koda:
MOV AX, 8 ADD AL, 4 AAA ADD AL, 04 AAA |
MOV AX, 5 SUB AL, 4 AAS SUB AL, 04 AAS |
a) b)
c)
MOV AX, 0805H
AAD
AAM
Ove instrukcije se dele u dve grupe: Bulove instrukcije i instrukcije pomeranja i rotacije.
Ova grupa instrukcija izvodi logičke operacije nad parovima odgovarajućih bitova operanada, a rezultat se (sem kod instrukcije TEST) smešta u odredišni operand.
AND D, S (eng. and - i) - D Ů S® D. Ova instrukcija oformljuje bitovnu konjukciju odredišnog i izvornog operanda, pa dobijeni rezultat smešta u odredišni operand.
Instrukcija AND je pogodna za brisanje specifičnih pozicija (tzv. maskiranih pozicija) u sadržaju registra: jedan operand specificira bitovne pozicije (on se često naziva maska), dok drugi operand sadrži vrednost.
Primer.
Brisanje tri bita najveće težine u bajtu se može realizovati tako što se izvrši konjukcija tog bajta i broja 00011111B. Po izvršenju instrukcije AND, biće CF=OF=0, a flegovi SF, ZF i PF biće postavljeni u skladu sa dobijenim rezultatom.
Ova instrukcija se često koristi za brisanje gornjeg polubajta (polubajta veće težine) u bajtu pre izvršenja aritmetičkih instrukcija nad nepakovanim BCD brojevima.
OR D, S (eng. or - ili) - D Ú S® D. Instrukcija OR oformljuje bitovnu disjunkciju odredišnog i izvornog operanda, pa dobijeni rezultat smešta u odredišni operand.
Instrukcija OR se koristi za postavljanje bitova na maskiranim pozicijama. U tom slučaju izvorni operand (tj. maska) će sadržati jedinice na onim bitovnim pozicijama koje se postavljaju, dok će na pozicijama koje trebaju ostati nepromenjene u maski stajati 0.
XOR D, S (eng. exclusive or - ekskluzivno ili) - D Ú S® D. Ova instrukcija oformljuje bitovnu ekskluzivnu disjunkciju (u žargonu se često umesto ekskluzivna disjunkcija koristi izraz “ksorovanje”) odredišnog i izvornog operanda, pa dobijeni rezultat smešta u odredišni operand.
Instrukcija XOR koristi se za komplementiranje bitova na maskiranim pozicijama. Tada maska sadrži jedinice na onim bitovnim pozicijama koje se komplementiraju, dok za bitovne pozicije koje trebaju ostati nepromenjene u maski stoji 0.
XOR takođe omogućuje da se na efikasan način sadržaj određenog operanda postavi na nulu.
NOT D (eng. not - ne) - ŘD ® D. Instrukcija NOT formira bitovnu negaciju odredišnog operanda i smešta je u odredište.
Dakle, instrukcija NOT komplementira svaki bit odredišta. Kako je komplementiranje bita ekvivalentno sa eksluzivnom disjunkcijom sa jedinicom, to je izvršenje komplementiranja ekvivalentno “ksorovanju” kod koga se izvorni operand sastoji isključivo od jedinica.
TEST D, S (eng. test - testiranje, provera) - D Ů S® ?. Ova instrukcija oformljuje bitovnu konjukciju odredišnog i izvornog operanda i u zavisnosti od dobijene vrednosti postavljaju se flegovi: OF i CF se brišu, vrednosti SF, ZF i PF se postavljaju sa obzirom na dobijeni rezultat.
Dakle, instrukcija TEST kombinuje osobine instrukcija AND i CMP. Kao i AND instrukcija, TEST izvodi konjukciju; a slično CMP instrukciji, rezultat se nige ne smešta, već se ažuriraju odgovarajući flegovi. Ova instrukcija je korisna za utvrđivanje da li se na specificiranim bitovnim pozicijama u odredištu nalaze nule illi jedinice.
Zadatak. Opisati
sadržaj opštih registara po izvršenju svake od instrukcija u sledećem
segmentu asmblerskog koda:
MOV EAX, 0F0F011EEH AND AX, 0FFFCH AND AX, 0F5F5H AND AX, 3E12H AND EAX, 00F011EEH |
MOV AX, 0F1D2H XOR AX, 11H XOR AL 0F2H XOR AH, AH
|
a) b)
Dužina odredišnog operanda kod ovih instrukcija može biti 8, 16 ili 32. Izvorni operand specificira broj mesta za koje sa vrši pomeranje ili rotacija. Taj operand može biti zadat bilo neposredno, bilo pomoću registra CL. Nijedan drugi registar osim registra CL se ne može koristiti za određivanje broja mesta pri pomeranju ili rotaciji.
Instrukcije pomeranja (još se nazivaju i instrukcije šiftovanja) su:
SHL D, S (eng. shift logical left - pomeri logički ulevo) - CF ¬ D ¬ 0. Realizuje šiftovanje odredišnog operanda za određeni broj pozicija ulevo. Na mesta koja su “ispražnjena” prilikom pomeranja ulevo, smeštaju se nule. Bit koji je poslednji “izbačen” iz odredišnog operanda biva smešten u CF.
SHR D, S (eng. shift logical right - pomeri logički udesno) - 0 ® D ® CF. Realizuje šiftovanje odredišnog operanda za određeni broj pozicija udesno. Na mesta koja su “ispražnjena” prilikom pomeranja udesno, smeštaju se nule. Bit koji je poslednji “izbačen” iz odredišnog operanda biva smešten u CF.
SAL D, S (eng. shift arithmetic left - pomeri aritmetički ulevo) - CF ¬ D ¬ 0. Radi isto što i instrukcija SHL, tj. ima potpuno isto dejstvo. Različitim mnemonicima SHL i SAL odgovara isti opkod, tj. mnemonici SAL i SHL su sinonimni.
SAR D, S (eng. shift arithmetic right - pomeri aritmetički udesno) - SF ® D ® CF. Realizuje šiftovanje odredišnog operanda za određeni broj pozicija udesno. Na mesta koja su “ispražnjena” prilikom pomeranja udesno, smeštaju se nule, ako je inicijalno vrednost bita najveće težine bila nula. Međutim, ako je inicijalna vrednost bita najveće težine operanda bila jedinica, tada se “ispražnjene” pozicije popunjavaju sa jedinicama. Bit koji je poslednji “izbačen” iz odredišnog operanda biva smešten u CF.
Instrukcije pomeranja daju vrlo efikasan mehanizam za dupliranje i polovljenje celih brojeva, odnosno za njihovo množenje i deljenje stepenima dvojke. Taj mehanizam počiva na činjenici da se celi brojevi čuvaju u sistemu sa osnovom dva.
Budući da se pri pomeranju mora voditi računa o tome da li se sadržaj operanda tumači kao neoznačen ili kao označen broj, to se razlikuju logičko pomeranje (ne vodi računa o znaku) i aritmetičko pomeranje (vodi računa o znaku operanda). Uočava se da se razlikuju samo aritmetičko i logičko pomeranje u desnu stranu.
Polovljenje negativnih brojeva instrukcijom SAR ne mora dati isti rezultat kao celobrojno deljenje tog istog broja sa brojem 2.
Primer.
MOV AL, -5 MOV BL, 2 IDIV BL |
MOV AL, -5 SAR AL, 1
|
Pokazuje da se aritmetičkim šiftovanjem broja -5 za jedno mesto udesno ne dobija isto kao pri celobrojnom deljenu tog istog broja sa 2.
Po izvršenju segmenta asemblerskog koda na levoj strani, u AL će se nalaziti vrednost -3, a po izvršenju koda na desnoj strani, AL će sadržati -2.
Instrukcije rotacije obezbeđuju mogućnost rearanžiranja redosleda bitova. U instrukcije rotacije spadaju:
ROL D, S (eng. rotate left - rotiraj ulevo) - Realizuje rotaciju odredišnog operanda za određeni broj pozicija ulevo.
ROR D, S (eng. rotate right - rotiraj udesno) - . Realizuje rotaciju odredišnog operanda za određeni broj pozicija udesno.
RCL D, S (eng. rotate through carry left - rotiraj kroz fleg prenosa ulevo) - . Rotira odredišni operand zajedno sa flegom prenosa za određeni broj pozicija ulevo.
RCR D, S (eng. rotate through carry right - rotiraj kroz fleg prenosa udesno) - . Rotira odredišni operand zajedno sa flegom prenosa za određeni broj pozicija udesno.
Pored prethodno pobrojanih, u instrukcije šiftovanja i rotacije spadaju i SHLD i SHRD. Ove instrukcije se koriste za premeštanje blokova dužine do 64 bita, tj. koriste se za efikasan transfer bitova. One postoje samo kod procesora 80386 i njegovih potomaka i njihov rad je usko vezan sa instrukcijama za rad sa bitovnim nizovima. Stoga će instrukcije SHLD i SHRD biti obrađene kasnije, kada se bude opisivao rad procesora 80386 sa nizovima bitova.
Niska (eng. string) je sekvenca bajtova, reči ili dvostrukih reči u memoriji. Pored naziva niska, kod nas je u širokoj upotrebi i naziv string. Operacije nad niskama su operacije koje se izvode nad svakim elementom niske.
Skup instrukcija procesora 80386 bitno umanjuje vreme potrebno za izvršenje instrukcije nad niskama. To ubrzanje je postignuto pomoću:
1) formiranja moćnog skupa primitivnih instrukcija (tzv. niska-primitive ili string-primitive)
2) eliminisanja potrebe za održavanjem i zaglavljem koji se obično izvode između obrađivanja uzastopnih članova.
Da bi se ilustrovalo kako instrukcije za rad sa niskama ubrzavaju obradu niski, razmotrimo postupak za premeštanje neke sekvence bajtova.
Primer.
Neka neku nisku bajtova treba prebaciti sa jedne na drugu lokaciju u memoriji. Potrebno je na neki način označiti gde su bajtovi sada i gde bi trebali da budu. Neka se za tu svrhu koriste ESI i EDI. Neka na početku ESI pokazuje na prvi bajt u niski koji treba premestiti, dok EDI pokazuje na mesto na koje niska odlazi. Registar ECX će sadržati broj elemenata (u ovom slučaju broj bajtova) koji se premeštaju. Koraci pri izvršenju premeštanja su sledeći:
1. ?ECX=0, ako da
kraj
2. dohvati bajt na
koji ukazuje ESI
3. smesti bajt u
lokaciju na koju pokazuje EDI
4. uvećaj ESI
za 1
5. uvećaj EDI
za 1
6. umanji ECX za 1
7. idi na korak 1
Uočava se da su kod ovog algoritma koraci 4-6predstavljaju održavanje, a da korak 7 predstavlja zaglavlje. Može se oformiti sekvenca asemblerskih instrukcija kojom se realizuje ovaj algoritam, tako da svakom od koraka algoritma odgovara tačno jedna asemblerska instrukcija. Ali, to nije najbrži način za realizaciju ovog algoritma na asemblerskom jeziku.
Kod familije INTEL-ovih procesora uvode instrukcije kod kojih su koraci 2 i 3, te koraci održavanja 4 i 5 hardverski realizovani. Dakle, izvršenjem jedne instrukcije se izvrše koraci 2, 3, 4 i 5 iz algoritma u prethodnom primeru.
Takve instrukcije, tj. niska-primitive su:
MOVS (eng. move string element - premesti elemenat niske) - [ESI]®[EDI], i ažuriraju se vrednosti u ESI, EDI. Dakle, primitiva prenosa premešta elemenat niske na koji pokazuje ESI u lokaciju na koju pokazije EDI, uz ažuriranje sadržaja registara ESI i EDI.
CMPS (eng. compare string elements - uporedi elemente niski) - računa se [ESI]-[EDI], u zavisnosti od rezultata se postavljaju flegovi, i ažuriraju se vrednosti u ESI, EDI. Dakle, primitiva poređenja upoređuje elemenat niske na koji pokazuje ESI sa elementom koju pokazije EDI, uz ažuriranje sadržaja registara ESI i EDI.
SCAS (eng. scan string element - skeniraj elemenat niske) - računa se akumulator-[EDI], u zavisnosti od rezultata se postavljaju flegovi, i ažurira se vrednost u EDI. Dakle, primitiva skeniranja elemenat niske na koji pokazuje EDI poredi sa vrednošu u akumulatoru, uz ažuriranje sadržaja registra EDI.
INS (eng. input string element - unesi elemenat niske) - ulazni port ®[EDI], i ažurira se vrednost u EDI. Dakle, primitiva unosa sa ulaznog porta specificiranog registrom DX premešta elememenat niske u lokaciju na koju pokazuje EDI, uz ažuriranje sadržaja registra EDI.
OUTS (eng. output string element - pošalji elemenat niske) - [ESI] ® izlazni port, i ažurira se vrednost u ESI. Dakle, primitiva odašiljanja šalje elememenat niske na koji pokazuje ESI u izlazni port specificiran registrom DX, uz ažuriranje sadržaja registra ESI.
STOS (eng. store string element - smesti elemenat niske) - akumulator ®[EDI], i ažurira se vrednost u EDI. Dakle, primitiva smeštanja premešta elememenat niske u lokaciju na koju pokazuje EDI u akumulator, uz ažuriranje sadržaja registra EDI.
LOADS (eng. load string element - uzmi elemenat niske) - [ESI] ® akumulator, i ažurira se vrednost u ESI. Dakle, primitiva uzimanja prenosi elememenat niske na koji pokazuje ESI u akumulator, uz ažuriranje sadržaja registra ESI.
Termin akumulator označava registrar AL, AX, EAX, u zavisnosti od toga da li se operacija skeniranja vrši nad bajtovima, rečima ili dvostrukim rečima.
Ove instrukcije nemaju operande. One manipulišu sa bitovnim niskama dužine 8, 16 ili 32. Postoje posebni opkodovi i posebni mnemonici za svaku od ovih istrukcija i fiksiranu veličinu bitovnog niza. Naime mnemonik sa sufiksom B eksplicitno označava da se niska primitiva vrši nad bajtovima, mnemonik sa sufiksom W označava da instrukcija operiše sa rečima, dok mnemonik sa sufiksom D označava da se radi o string primitivi nad dvostrukim rečima. Tako, pored već pobrojanih niska-primitiva, kod procesora 80386, postoje i instrukcije MOVSB, MOVSW, MOVSD, CMPSB, CMPSW, CMPSD, SCASB, SCASW, SCASD, INSB, INSW, INSD, OUTSB, OUTSW, OUTSD, STOSB, STOSW, STOSD, LODSB, LODSW, LODSD.
Preciznije rečeno, instrukcije kod kojih nije eksplicitno specificirana dužina elementa niske se tokom asembliranja svode na neku od prethodno popisanih instrukcija.
Da bi se ilustrovao značaj i način korišćenja prefiksa ponavljanja, ponovo razmotrimo postupak za premeštanje neke sekvence bajtova.
Primer.
Neka neku nisku bajtova treba prebaciti sa jedne na drugu lokaciju u memoriji. Neka na početku ESI pokazuje na prvi bajt u niski koji treba premestiti, dok EDI pokazuje na mesto na koje niska odlazi. Registar ECX će sadržati broj elemenata (u ovom slučaju broj bajtova) koji se premeštaju. Sada, kada raspolažemo sa primitivom prenosa, koraci pri izvršenju premeštanja će biti:
1. ?ECX=0, ako da -
kraj
2. izvrši primitivu
prenosa
3. umanji ECX za 1
4. idi na korak 1
Uočavamo da se opet može oformiti sekvenca asemblerskih instrukcija kojom se realizuje ovaj algoritam, tako da svakom od koraka algoritma odgovara tačno jedna asemblerska instrukcija. Tako napravljen asemblerski kod radio brže od asemblerskog koda iz prethodnog primera.
Koraci 1,3 i 4 se mogu eliminisati, jer je primitiva prenosa pomeša sa testiranjem, umanjivanjem i ponavljanjem baziranim na ECX, a sve to se može postići pomoću prefiksa ponavljanja REP.
REP (eng repeat - ponavljanje) - ukazuje da se primitiva ponavlja ECX puta.
Primer.
Algoritam iz prethodnog primera realizuje se jednom instrukcijom: REP MOVS.
Kao što je već istaknuto, niska-primitive mogu da se izvršavaju nad bajtovima, rečima ili dvostrukim rečima. Primitiva prenosa kod reči i dvostrukih reči radi slično kao primitiva prenosa kod bajtova, s tim što se EDI i ESI ne uvećavaju (odnosno umanjuju) za 1, već za 2 (kod reči) ili za 4 (kod dvostrukih reči).
Primer.
MOV ESI, OFFSET MEM_DWORD1 MOV EDI, OFFSET MEM_DWORD2 MOV ECX, DWORDS_BROJ REP MOVS |
MOV ESI, OFFSET MEM_WORD1 MOV EDI, OFFSET MEM_WORD2 MOV ECX, WORDS_BROJ REP MOVS |
Ilustruje zajedničko korišćenje niska-primitiva i prefiksa ponavljanja:
MOV ESI, OFFSET MEM_BYTE1
MOV EDI, OFFSET MEM_ BYTE2
MOV ECX, BYTES_BROJ
REP MOVS
Asembler će na osnovu konteksta da odredi broj bitova kod elementa niske i da u objekt datoteci generiše ispravan opkod. Naravno, moguće je koristiti i mnemonike koji tačno specificiraju veličinu operanda, tj. umesto REP MOVS koristiti REP MOVSB ili REP MOVSW ili REP MOVSD
Prilikom premeštanja podataka može se javiti problem ako se prostor koji na početku zauzima niska preklapa sa prostorom koji niska treba zauzeti posle premeštanja.
Primer.
Kao što se vidi, bajt iz lokacije 100 se kopira u lokaciju 102, pa u 104, itd. Na taj način je originalni sadržaj lokacija 102 i 104 uništen.
Ponekad je preklapanje poželjno, npr. kada ponavljajući obrazac bajtova mora smestiti u memoriju. Ali, jasan je značaj pravca prenošenja bajtova i potreba da se nekad prenos vrši unapred, a nekad unazad.
Registar flegova procesora 80386 sadrži DF (fleg pravca), koji upravlja pravcem obrade niski. Ako je DF=0, niske će se obrađivati od početka prema kraju, tj. ESI i EDI će se pri radu uvećavati. Ako je DF=1, onda se obrada vrši otpozadi, pa se ESI i EDI umanjuju. Ažuriranje registara ESI i EDI, koje se pominje u opisu niska-primitiva, se svodi na jednu od sledećih operacija: uvećanje za 1 (ako se radi sa bajtovima i DF=0), uvećanje za 2 (ako se radi sa rečima i DF=0), uvećanje za 4 (ako se radi sa dvostrukim rečima i DF=0), umanjenje za 1 (ako se radi sa bajtovima i DF=1), umanjenje za 2 (ako se radi sa rečima i DF=1) i umanjenje za 4 (ako se radi sa dvostrukim rečima i DF=1).
Dakle, kada je EDI<ESI a prostor koji zauzima izvorna niska se preklapa sa prostorom koji će zauzimati odredišna niska, prenos treba izvršiti unapred. Kada je EDI>ESI a prostor koji zauzima izvorna niska se preklapa sa prostorom koji će zauzimati odredišna niska, prenos treba izvršiti unazad.
Instrukcije kojima se postavlja, odnosno briše, registar flegova DF će biti razmatrane kasnije - u paketu sa ostalim instrukcijama za rad sa flegovima.
Razmotrimo sad drugu operaciju nad niskama: skeniranje niske u potrazi za bilo kojom vrednošću različitom od zadate.
Primer.
Neka treba naći prvi elemenat u datom nizu bajtova koji ima zadatu vrednost. Neka se ta zadata vrednost nalazi u registru AL. Neka EDI pokazuje na nisku i neka ECX sadrži broj bajtova u sekvenci. Koraci algoritma za izvršenje skeniranja su
1. ?ECX=0, ako da -
kraj
2. uporedi AL sa
bajtom na koji pokazuje EDI
3. uvećaj
(umanji ako je DF=1) EDI za 1
4. umanji ECX za 1
5. ?ZF=1, ako da -
nađen bajt, ako ne - idi na korak 1
Uočava se da je kod ovog algoritma “u igri” i nula fleg ZF, tj. tokom skaniranja se testira postavljenje nula flega.
Kod procesora 80386, stoga, postoje prefiksi ponavljanja koji tokom ponavljanja primitive testiraju vrednost nula flega. Način testiranja vrednosti nula flega je određen nazivom prefiksa ponavljanja. Dakle, prefiks ponavljanja mora iskazati koja od vrednosti ZF izaziva ponavljanje.
Mnemonici za ova ponavljanja su:
REPZ (eng repeat while ZF is set- ponavljanje sve dok je nula fleg postavljen) - ukazuje da se primitiva ponavlja sve dok je ZF=1, a najviše ECX puta.
REPE (eng repeat while equal- ponavljanje sve dok je jednako) - ukazuje da se primitiva ponavlja sve dok su prethodno upoređeni elementi jednaki, a maksimalno ECX puta. Ovaj prefiks ponavljanja je sinoniman prefiksu REPZ.
REPNZ (eng repeat while not ZF is set- ponavljanje sve dok nije nula fleg postavljen) - ukazuje da se primitiva ponavlja sve dok je ZF=0, a najviše ECX puta.
REPNE (eng repeat while not equal- ponavljanje sve dok nije jednako) - ukazuje da se primitiva ponavlja sve dok su prethodno upoređeni elementi različiti, a maksimalno ECX puta. Ovaj prefiks ponavljanja je sinoniman prefiksu REPNZ.
Primer.
Algoritam iz prethodnog primera realizuje se jednom instrukcijom:
REPNZ SCAS.
Kako se u prošlom primeru radilo o skeniranju niske bajtova, to se gornja instrukcija može zameniti sa nešto eksplicitnijim:
REPNZ SCASB.
Razmotrimo sad operaciju poređenja niski. U tom slučaju, neophodno je odrediti poziciju prvog elementa na kom se dve niske razlikuju.
Primer.
Neka treba za dva data niza bajtova jednake dužine odrediti na kojoj se poziciji te niske počinju razlikovati. Neka ESI pokazuje na prvu, a EDI na drugu nisku, i neka ECX sadrži broj bajtova u njoj. Koraci algoritma su:
1. ?ECX=0, ako da -
kraj
2. dohvati bajt na
koji pokazuije ESI
3. uporedi sa
bajtom na koji ukazuje EDI
4. ažuriraj ESI
5. ažuriraj EDI
6. umanji ECX za 1
7. ?ZF=1, ako da -
idi na 1
Ovaj algoritam se realizuje jednom instrukcijom:
REPZ CMPS
ili
REPZ CMPSB.
Primećuje se da se na ovaj način prešlo preko pozicije na kojoj se elementi razlikuju, ali da su na ovaj način flegovi postavljeni upravo tako da odslikavaju leksikografski poredak prve i druge niske.
Nisu napravljene, niti je moguće napraviti, primitive za realizaciju svake od potreba koja može iskrsnuti pri radu sa niskama. Tako se neke druge operacije moraju realizovati kao sekvenca više asemblerskih instrukcija.
Primer.
Neka treba komplementirati elemente datog niza bajtova i prepisati ih na neko drugo mesto u memoriji. Neka ESI pokazuje na nisku koja se komplementira i prepisuje, a EDI na lokaciju u memoriji od koje se trebaju smestiti bajtovi niske, i neka ECX sadrži broj bajtova u njoj. Koraci algoritma su:
1. ?ECX=0, ako da -
kraj
2. dohvati bajt na
koji pokazuije ESI
3. komplementiraj
dohvaćeni bajt
4. smesti bajt u
lokaciju na koju pokazuje EDI
5. ažuriraj ESI
6. ažuriraj EDI
7. umanji ECX za 1
8. ?ECX=0, ako ne -
idi na 2
Analogno prethodnim primerima, bilo bi logično koristiti primitivu koja bi izvršila korake 2, 3, 4, 5, 6. Međutim, takva primitiva ne postoji! Prirodno je i logično da ne mogu postojati primitive za sve potrebe.
Primer.
Za rešavanje problema postavljenog u prethodnom primeru koraci 2 i 5 mogu biti zamenjeni sa load primitivom, koraci 4 i 6 sa store primitivom, a korak 3 sa instrukcijom NEG. Ovo prethodni algoritam uprošćava na:
1. ?ECX=0, ako da -
kraj
2. izvrši load
primitivu
3. komplementiraj
bajt u AL-u
4. izvrši store
primitivu
5. umanji ECX za 1
6. ?ECX=0, ako ne -
idi na 2
Koraci 1, 5 i 6 su u prethodnim primerima bili obezbeđeni mešanjem string primitive sa prefiksom ponavljanja. Kako se u ovom slučaju telo petlje sastoji od više instrukcija, to prefiks ponavljanja ne može biti korišćen.
Dakle, neophodno je postojanje efikasnih instrukcija koje će simulirati kompleksne akcije prefiksa ponavljanja.
Analiza prethodnog primera ukazuje na željene osobine koje bi trebalo da imaju te nove instrukcije.
Korak 1 zahteva postojanje takvog uslovnog prelaska, da se skok izvršava u slučaju kada je ECX=0. Odredište skoka bi trebalo da bude specificirano u što je moguće manje bitova.
JECXZ D (eng. jump if ECX is zerro - skoži ukoliko je ECX nula) - izvršava skok na labelu datu odredišnim operandom ukoliko je ECX nula.
JCXZ D (eng. jump if CX is zerro - skoži ukoliko je CX nula) - izvršava skok na labelu datu odredišnim operandom ukoliko je sadržaj registra CX nula.
Odredište skoka je enkodira u jednom bajtu instrukcije. Taj bajt sadrži označen broj koji predstavlja rastojanje (u bajtovima) od J(E)CXZ instrukcije do odredišta. Iz ovoga je jasno da je odredište J(E)CXZ instrukcije specificirano neposredno.
Koraci 5 i 6 zahtevaju da postoji i instrukcija koja umanjuje ECX i potom skače ukoliko ECX nije nula.
LOOP D (eng. loop - petlja) - umanjuje ECX i potom izvršavanje prelazi na neposredno zadato odredište ukoliko ECX nije nula.
Odredište prelaska (skoka) u LOOP instrukciji je specificirano na isti način kao i kod JECXZ instrukcije.
Primer.
Algoritam iz prethodnog primera može da se realizuje i na sledeći način:
1. JECXZ preko
sledećih koraka
2. izvrši load
primitivu
3. komplementiraj
bajt u AL-u
4. izvrši store
primitivu
5. LOOP nazad na 2
Kako u ovom algoritmu svaki korak predstavlja jednu instrukciju, to se algoritam može predstaviti sledećom sekvencom naredbi:
JECXZ DALJE
PETLJA:
LODS
NEG
STOS
LOOP PETLJA
DALJE:
Uočava se da dejstvo prethodno uvedena LOOP instrukcije zavisi isključivo od sadržaja registra ECX. Međutim, već je istanuto da je kod nekih operacija za rad sa niskama poželjno da se odluka o ostanku u petlji donese i na osnovu postavljenja flega ZF.
LOOPZ D (eng loop while ZF is set- petlja sve dok je nula fleg postavljen) - umanjuje se ECX i realizuje prelazak izvršavanja na labelu specificiranu odredištem ako je ZF=1 i ECX<>0.
LOOPE D (eng loop while equal - petlja sve dok je jednako) - umanjuje se ECX i vrši se prelazak na labelu specificiranu odredištem ako su prethodno upoređeni elementi jednaki i ECX<>0. Ova instrukcija je sinonimna instrukciji LOOPZ.
LOOPNZ D (eng loop while not ZF is set- petlja sve dok nije nula fleg postavljen) - umanjuje se ECX i realizuje prelazak izvršavanja na labelu specificiranu odredištem ako je ZF=0 i ECX<>0.
LOOPNE D (eng loop while not equal - petlja sve dok je različito) - umanjuje se ECX i vrši se prelazak na labelu specificiranu odredištem ako su prethodno upoređeni elementi različiti i ECX<>0. Ova instrukcija je sinonimna instrukciji LOOPNZ.
Primer.
0 0000 0000 1 0001 0001 2 0010 0011 3 0011 0010 4 0100 0110 5 0101 0100 6 0110 0101 7 0111 0111 |
8 1000 1111 9 1001 1110 10 1010 1100 11 1011 1101 12 1100 1001 13 1101 1011 14 1110 1010 15 1111 1000 |
Vrši se konverzija niza brojeva iz intervala između 0 i 15 u odgovarajući Grejov kod, te njihov prepis u neku drugu lokaciju. Grejov kod (tj. jedna njegova varijanta) data je sledećom tabelom:
Kao što se i može videti iz prethodne tabele, osnovna osobina Grejovog koda je da se bitovni zapisi susednih brojeva razlikuju na tačno jednom bitovnom mestu. Neka sekvenca bajtova, koja sadrži binarne brojeve između 0 i 15, počinje od memorijske lokacije MEMBYTE1. Neka je broj bajtova u sekvenci koji treba konvertovati sadržan u registru ECX, i neka je MEMBYTE2 lokacija počev od koje treba smestiti konvertovane bajtove. Nadalje, neka je GRAY niz bajtova koji sadrži tabelu Grejovih kodova.
Tada su koraci kojima se realizuje konverzija i prenos sledeći:
MOV ESI, OFFSET MEMBYTE1
MOV EDI, OFFSET MEMBYTE2
MOV EBX, OFFSTE GRAY
JECX GOTOVO
PETLJA:
LODS
XLATB
STOS
LOOP PETLJA
GOTOVO:
Glavni tipovi instrukcija bezuslovnog prelaska procesora 80386 su skokovi, pozivi i vraćanja.
JMP D (eng. jump - skok) - D ® EIP. Naredba bezuslovnog skoka učitava vrednost odredišta u brojač naredbe EIP i na taj način prekida se sekvencijalno izvršavanje instrukcija.
CALL D (eng call - poziv) - D ® stek, D ® EIP. Naredba poziva radi isto što i naredba skoka, ali prvo se gurne tekuća vrednost brojača naredbe EIP na stek, tako da se, u nekom trenutku u budućnosti, izvršavanje može nastaviti od mesta gde je bilo prekinuto.
RET D (eng return - povratak) - stek ® EIP; ako je specifcirano D, D+ESP ® ESP. Naredba vraćanja se dešava u tom trenutku u budućnosti. Ona uklanja prethodno gurnuti elemenat sa steka i uklonjenu vrednost smešta u brojač naredbi EIP.
Operandi instrukcija skokova i poziva javljaju se kao direktni i indirektni. Najveći broj je direktan i direktno specificiran operand odmah kaže gde se izvršavanje nastavlja. Indirektni prelazak se ređe koristi, npr. indirektan prelazak je od koristi kada se ne zna gde će se nastaviti izvršavanje, već se to mora prvo izračunati.
Primer.
Indirektan skok
JMP NIZ[EBX*4]
dohvata odredište iz niza NIZ u memoriji koji je indeksiran pomoću EBX registra (sa faktorom skaliranja 4).
[to se načina izvršavanja svih instrukcija tiče, prvo se kod svih njih uveća EIP, kako bi pokazivalo na sledeću naredbu. Da bi dizajn procesora ostao jednostavan, uvećavanje EIP će se izvršavati i kod ovih instrukcija prelaska - iako izvršenjem instrukcija prelaska sadržaj EIP biva ponovo modifikovan.
Koraci JMP instrukcije su:
1) Uvećava se sadržaj registra EIP;
2) U registar EIP se smešta vrednost odredišnog operanda.
Koraci CALL instrukcije su:
1) Uvećava se sadržaj registra EIP;
2) Prethodno povećana vrednost EIP se gura na stek;
3) U registar EIP se smešta vrednost odredišnog operanda.
Koraci RET instrukcije su:
1) Uvećava se sadržaj registra EIP;
2) U registar EIP se smešta vrednost skinuta sa steka.
Direktni skokovi i pozivi ne specificiraju odredište eksplicitno, već kao razliku, tj. rastojanje od odredišta skoka do tekuće pozicije. Ukoliko je rastojanje (iskazano u bajtovima) toliko da se može smestiti u 8 bitova (što je vrlo čest slučaj), onda se može koristiti kraći oblik instrukcije skoka. Taj kraći oblik instrukcije je za tri bajta kraći od regularnog oblika. U tom slučaju (kao i u svim ostalim) se prvo uveća EIP, pa se odredište računa tako što se na prethodno već uvećanu vrednost EIP dodaje pomeranje tj. razlika. Tako, razlika nije razlika od odredišta do instrukcije bezuslovnog skoka, već od odredišta do instrukcije koja neposredno sledi iza instrukcije bezuslovnog skoka.
Pri asemblerskom programiranju ne mora da se računa razlika tj. rastojanje, već se (korišćenjem simboličkih imena adresa) ostavlja asembleru da sam razreši ova pitanja.
Kod indirektnih skokova i poziva se, naravno, ne koriste relativna pomeranja, jer indirektni operand samo ukazuje gde se nalazi odredište.
[to se instrukcije vraćanja tiče, uočava se da postoji varijanta ove instrukcije koja, posle obnavljanja brojačan naredbi EIP skidanjem njegove vrednosti sa steka, dodaje konstantu (neposredno specificiranu odredišnim operandom) na pokazivač steka ESP. Ovim se postiže efekat skidanja i uništavanja dodatnih elemenata na steku. Takvi elementi su se mogli naći na steku odmah po izvršenju CALL instrukcije i služiti za prenos parametara iz pozivajuće procedure. Kad procedura završi sa radom i kad usledi povratak, te vrednosti više neće biti potrebne, pa se ovaj oblik instrukcije vraćanja predstavlja uobičajen način da procedura poništi svoje parametre.
Instrukcija vraćanja u varijanti povratka i poništenja koristi 16 bitova za smeštaj neposredno zadatog operanda, tj. za smeštaj vrednosti koja se treba dodati na ESP. Na odluku o ovakvom efektu instrukcije vraćanja je presudno uticalo to što, iako je za specificiranje broja bajtova koji se skidaju sa steka najčešće dovoljan jedan bajt, slučaj kada jedan bajt nije dovoljan za smeštaj operanda postaje izuzetno nezgodan za rad.
Primer.
CALL PROGLOK CALL [EBX] CALL MEMDWORD |
JMP PROGLOK JMP [EBX] JMP MEMDWORD |
Raznovrsni načini korišćenja instrukcija skoka, poziva i vraćanja:
RET
RET 17
Podprogram (još se koristi i izraz procedura) na asemblerskom jeziku je, jednostavno, sekvenca asemblerskih instrukcija u kojoj prva ima simboličko ime (labelu), a kod koje je poslednja instrukcija instrukcija povratka.
Primer.
Procedura za sabiranje registara AX, BX, CX i DX je:
zbir_regist:
MOV SI, 0
ADD SI, AX
ADD SI, BX
ADD SI, CX
ADD SI, DX
RET
Izračunati rezultat je, kao što se vidi, smešten u registru SI. Ovako oformljena procedura bi se mogla pozvati na sledeći način:
MOV AX, 0
MOV BX, 0
MOV CX, 0
MOV DX, 1
CALL zbir_regis ;SI ce biti postavljen na 1
MOV AX, 2
CALL zbir regis ;SI ce biti postavljen na 3
MOV BX, 3
MOV CX, 4
CALL zbir regis ;SI ce biti postavljen na 10D
Sledeći dijagram opisuje tok izvršavanja jednog dela prethodnog asemblerskog programa:
Primena instrukcija CALL i RET u prethodno urađenom primeru je unutarsegmentna primena CALL i RET instrukcija.
Međutim, dosta često se procedure u jednom segmentu pozivaju iz drugog memorijskog segmenta. Instrukcije međusegmentnih poziva i povrataka se na nivou objektnog koda razlikuju od unutarsegmentnih poziva i povrataka.
Da bi asembler unapred znao da li se poziv pretvara u međusegmentni, potrebno je da programer koji želi da radi sa više segmenata mora da zatvori svaki deo koda tako da asembleru bude očigledno šta je međusegmentno (eng. far - daleko), a šta je unutarsegmentno (eng. near - blisko).
Primer.
PODPROGRAM PROC NEAR MOV AX, 4 INC BX … RET PODPROGRAM ENDP |
PODPROGRAM: MOV AX, 4 INC BX … RET |
Uočimo sedeće podprograme:
PODPROGRAM PROC FAR
MOV AX, 4
INC BX
…
RET
PODPROGRAM ENDP
Svaki od ovih tri podprograma prilikom asemliranja dovode do istog objektnog koda, s tim što će u prvom i drugom slučaju instrukcija RET biti unutarsegmentna, dok će u trećem slučaju biti generisana međusegmentna instrukcija povratka.
Napomena.
Razlika između unutarsegmentne i međusegmentne instrukcije može se videti i pri radu sa dibagerom.
Najjednostavniji način za prenos parametara između pozivajuće i pozvane procedure je preko opštih registara: pre poziva procedure parametri se smeste u opšte registre, a po povratku u pozivajuću proceduru izmenjeni sadržaji registara predstavljaju vrednosti izlaznih parametara. Pri ovakvom prenosu parametara, opšti registri mogu sadržati bilo vrednosti parametara, bilo adrese parametara. Ovim putem se argumenti relativno lako prenose, ali problem je relativno mali broj registara opšte namene.
Pojavljuje se još jedan problem: treba podržati kreiranje i rad sa rekurzivnim procedurama. Već je poznato da programi na višim programskim jezicima imaju mogućnost za smeštaj parametara i lokalnih promenljivih procedure tako da ne mođe doći do uništenja (ili oštećenja) starih vrednosti zato što se pre kraja izvršenja procedure pozvala neka druga, ili čak ista procedura, eventualno sa drugim parametrima.
Dakle, procesor i asemblerski jezik moraju imati i mogućnost prenosa parametara i smeštaja lokalnih promenljivih tako da se uspešno mogu kreirati rekurzivne procedure. Tu se pri svakom pozivu procedure treba alocirati memorija za parametre i lokalne promenljive. Niz memorijskih lokacija koji služi u ovu svrhu se naziva aktivacijski slog. Kako kompajleri aktivacijski slog obično drže na steku, to se ponegde u literaturi aktivacijski slog još naziva i stek-okvir (eng. stack-frame).
Način korišćenja steka u mehanizmu poziva neke procedure i povratka u pozivajuću proceduru direktno prizilazi iz efekata CALL i RET instrukcija. Jednostavnije iskazano, pri izvršenju instrukcije CALL se na vrhu steku sačuva adresa instrukcije koja neposredno sledi iza instrukcije poziva (tj. adresa povratka), sve dok se ne izvrši instrukcija povratka RET. Da bi se korektno vratilo u pozivajuću proceduru, potrebno je da se u trenutku izvršenja instrukcije RET na vrhu steka nalazi adresa povratka.
U slučaju kada se vrednosti parametara (bilo ulaznih, bilo izlaznih) prenose preko steka, potrebno je da se te vrednosti gurnu na stek neposredno pre poziva procedure. Postavlja se pitanje: na koji način će pozvana procedura pristupiti njenim parametrima?
Napomena.
Korišćenje neke od varijanti POP instrukcija neće dati zadovoljavajući rezultat - pojavljuje se previše komplikacija. Jer, sa steka biva skinuta adresa povratka, koja potom treba biti sačuvanana na nekom drugom mestu, a po “uzimanju” parametara ta adresa treba biti ponovo gurnuta na stek - kako bi korektno funkcionisala instrukcija RET. Sadržaj stek-memorije pri pozivu neke procedure prikazan je na sledećem dijagamu:
|
|
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(E)SP® |
|
|
adresa |
|
|
|
|
|
povratka |
|
|
|
|
|
parametrri |
|
|
|
... |
|
procedure |
|
|
|
|
|
|
|
|
|
|
|
elementi na |
|
|
|
|
|
steku pre |
|
|
|
... |
|
poziva |
|
Uobičajen je, dakle, drugi mehanizam: procedura će vrednostima parametara pristupati korišćenjem registra pokazivač baze (E)BP. Taj registar se postavi tako da pokazuje na vrh steka, a potom se (adresiranjem baza+pomeraj) lako radi sa parametrima.
Primer.
Sledeća instrukcija učitava u AX reč čija je adresa BP.
MOV AX, [BP]
Instrukcija
MOV AX, [BP+2]
učitava u AX reč čija je adresa određena zbirom vrednosti BP i 2.
Primer.
Sledeći dijagram prikazuje korišćenjeregistra (E)BP za pristup parametrima procedure:
|
|
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(E)BP, (E)SP® |
|
|
adresa |
|
|
|
|
|
povratka |
|
|
[BP+2]: |
|
|
|
|
|
|
|
|
|
|
|
[BP+4]: |
|
|
parametri |
|
|
|
|
|
procedure |
|
|
[BP+6]: |
|
|
|
|
|
|
|
|
|
|
|
|
... |
|
|
|
Gornji dijagram je korektan samo ukoliko su sadrtžaji registara (E)BP i (E)SP jednaki.
Još se postavlja pitanje kako sa steka skinuti elemente koji su na njega gurnuti pre poziva procedure. To se najlakše, najjednostavnije i najbrže radi korišćenjem instrukcije RET X. Ta instrukcija na uobičajen način izvrši povratak, a zatim uveća (E)SP za X.
Primer.
Dijagram prikazuje efekat izvršenja instrukcije RET X:
Početno stanje
|
|
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(E)SP® |
|
|
adresa |
|
|
|
|
|
povratka |
|
|
n: |
|
|
parametri |
|
|
|
... |
|
procedure |
|
|
|
|
|
|
|
|
n+X |
|
|
elementi na |
|
|
|
|
|
steku pre |
|
|
|
... |
|
poziva |
|
RET X
|
|
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
n: |
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
|
|
|
(E)SP® |
|
|
elementi na |
|
|
|
|
|
steku pre |
|
|
|
... |
|
poziva |
|
Veoma često je neophodno da se lokalni parametri procedure smeštaju na stek. Na ovaj način procedura postaje nezavisnija u svom radu. Kod rekurzivnih procedura, zbog očiglednih razloga, i nije moguće smeštati lokalne parametre u fiksne memorijske lokacije, a istovremeno se zahteva da se u okviru te procedure lokalnim parametrima pristupa na uniforman način.
Stoga se lokalne promenljive procedure čuvaju na steku, i to neposredno iznad aktuelnog vrha steka u trenutku poziva procedure.
Primer.
Dijagram prikazuje prostor u kom treba smestiti lokalne promenljive:
|
|
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lokalne |
|
|
|
... |
|
promeljive |
|
|
|
|
|
procedure |
|
|
(E)SP® |
|
|
adresa |
|
|
|
|
|
povratka |
|
|
|
|
|
parametri |
|
|
|
... |
|
procedure |
|
|
|
|
|
|
|
|
|
|
|
elementi na |
|
|
|
|
|
steku pre |
|
|
|
... |
|
poziva |
|
Da bi smeštaj lokalnih parametara na stek bio korektno izvršen, potrebno je da se odmah po ulasku u proceduru veličina registra (E)SP umanji za broj bajtova koje zauzimaju lokalne promenljive, i na taj način preduprredi eventualno “gaženje” vrednosti lokalnih promenljivih sa novogurnutim vrednostima. Naravno, neposredno pre povratka u pozivajuću proceduru treba vrednost (E)SP uvećati za istu vrednost za koju je bila prethodno umanjena.
Sam pristup lokalnim promenljivima se obično izvodi preko registra (E)BP - potpuno analogno pristupu parametrima procedure (s tim što se umesto uvećanja vrednosti (E)BP vrši njeno umanjenje).
Primer.
Sledeći dijagram prikazuje korišćenjeregistra (E)BP za pristup lokalnim promenljivama procedure:
|
|
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(E)SP®[BP-6]: |
|
|
|
|
|
|
|
|
lokalne |
|
|
[BP-4]: |
|
|
promenljive |
|
|
|
|
|
procedure |
|
|
[BP-2]: |
|
|
|
|
|
|
|
|
|
|
|
(E)BP ® |
|
|
adresa |
|
|
|
|
|
povratka |
|
|
|
... |
|
|
|
Naravno, gornji dijagram je korektan samo ukoliko su sadrtžaji registara (E)BP i (E)SP postavljeni kao na slici.
Procesor 80386 obezbeđuje instrukcije uslovnog skoka koje, zajedno sa instrukcijama poređenja, realizuju prelaske na osnovu odnosa dva broja.
Ovo se radi u dva koraka:
- porede se brojevi tako što se oformi njihova razlika i u zavisnosti od te razlike postave se flegovi;
- izvršava se instrukcija uslovnog skoka koja testira vrednosti flegova i izvodi skok ukoliko flegovi indiciraju da upoređeni brojevi zadovoljavaju odgovarajuću relaciju.
Kod instrukcija uslovnog skoka može biti samo jedan operand, i to mora biti direktan memorijski operand.
Uslovni skokovi su:
JE D (eng. jump on equal - skoči ukoliko su jednaki) - ? ZF, ako da D® EIP.
JNE D (eng. jump on not equal - skoči ukoliko nisu jednaki) - ? ŘZF, ako da D® EIP.
JL D (eng. jump on less than - skoči ukoliko je manji) - ? (SFÚOF), ako da D® EIP.
JNL D (eng. jump on not less than - skoči ukoliko nije manji) - ? Ř(SFÚOF), ako da D® EIP.
JG D (eng. jump on greater than - skoči ukoliko je veći) - ? Ř((SFÚOF)ÚZF), ako da D® EIP.
JNG D (eng. jump on not greater than - skoči ukoliko nije veći) - ? ((SFÚOF)ÚZF), ako da D® EIP.
JB D (eng. jump on below - skoči ukoliko je ispod) - ? CF, ako da D® EIP.
JNB D (eng. jump on not below - skoči ukoliko nije ispod) - ? ŘCF, ako da D® EIP.
JA D (eng. jump on above - skoči ukoliko je iznad) - ? Ř(CFÚZF), ako da D® EIP.
JNA D (eng. jump on not above - skoči ukoliko nije iznad) - ? (CFÚZF), ako da D® EIP.
Mnemonici prethodnih instrukcija uslovnog skoka imaju svoje sinonime:
JE « JZ (eng. jump on zerro - skoči ukoliko je postavljen nula fleg).
JNE « JNZ (eng. jump on not zerro - skoči ukoliko nije postavljen nula fleg).
JL « JNGE (eng. jump on not greater or equal - skoči ukoliko nije veći ili jednak).
JNL « JGE (eng. jump on greater or equal - skoči ukoliko je veći ili jednak).
JG « JNLE (eng. jump on not less or equal - skoči ukoliko nije manji ili jednak).
JNG « JLE (eng. jump on less or equal - skoči ukoliko je manji ili jednak).
JB « JNAE (eng. jump on not above or equal - skoči ukoliko nije iznad ili jednak).
JNB « JAE (eng. jump on above or equal - skoči ukoliko je iznad ili jednak).
JA « JNBE (eng. jump on not bellow or equal - skoči ukoliko nije ispod ili jednak).
JNA « JBE (eng. jump on bellow or equal - skoči ukoliko je ispod ili jednak).
Postoje instrukcije uslovnih skokova kod kojih izvršavanje prelaska zavisi isključivo od postavljanja flegova. Uočava se da su takve i prethodno opisane instrukcije JZ (JE) i JNZ (JNE) koji testiraju sadržaj nula-flega, te JB (JNAE) i JNB (JAE) koje testiraju sadržaj CF. Pored prethodno pobrojanih, uslovni prelasci koji zavise isključivo od postavljanja jednog flega su:
JS D (eng. jump on sign - skoči ukoliko je postavljen fleg znaka) - ? SF, ako da D® EIP.
JNS D (eng. jump on not sign - skoči ukoliko nije postavljen fleg znaka) - ? ŘSF, ako da D® EIP.
JO D (eng. jump on overflow - skoči ukoliko je postavljen fleg prekoračenja) - ? OF, ako da D® EIP.
JNO D (eng. jump on not overflow - skoči ukoliko nije postavljen fleg prekoračenja) - ? ŘOF, ako da D® EIP.
JP D (eng. jump on parity - skoči ukoliko je postavljen fleg parnosti) - ? PF, ako da D® EIP.
JNP D (eng. jump on not parity - skoči ukoliko nije postavljen fleg parnosti) - ? ŘPF, ako da D® EIP.
Mnemonici instrukcija uslovnog skoka koji testiraju fleg parnosti imaju svoje sinonime:
JP « JPE (eng. jump on parity even - skoči ukoliko je parnost parna).
JNP « JPO (eng. jump on parity odd - skoči ukoliko je parnost neparna).
Kao i kod instrukcija bezuslovnog skoka, odredišni operand je enkodiran relativno u odnosu na instrukciju koja neposredno sledi iza instrukcije skoka.
Dok su prethodnici procesora 80386 dopuštali samo kraći oblik instrukcija uslovnog prelaska (pa se odredište moralo nalaziti do 128 bajtova ispred, odnosno 127 bajtova iza linije koja sledi instrukciju uslovnog skoka), kod ovog procesora se dopušta da odredište ma koje instrukcije uslovnog skoka (sem instrukcija JCXZ i JECXZ) bude bilo gde u memorijskom prostoru. Korištenje te duže forme, naravno, ima svoju cenu: u tom slučaju instrukcija zauzima tri bajta više nego odgovarajuća kraća forma, jer iza 16-bitnog opkoda sledi četvorobajtni pomak.
Postavlja se pitanje: zašto uvoditi nove opkodove, tj. zašto dodavati duži oblik za uslovne prelaske? Zar najveći broj uslovnih prelazaka nisu skokovi na bliske instrukcije, a skokovi na daleke labele se mogu realizovati preko sekvence instrukcija, kao kod sledećeg primera:
Primer.
JNC L1 JMP ODRED L1: |
JC ODRED ; |
Realizovanje dugog uslovnog pomoću kratkog uslovnog i bezuslovnog skoka.
Odgovor zašto su instrukcije baš ovako dizajnirane, počiva na sledećim argumentima:
- uočeno je da prevodioci sa jezika visokog nivoa generišu veliki broj dalekih uslovnih skokova, koristeći sekvencu instrukcija analogno prethodnom primeru;
- nova forma dalekog skoka je, zbog arhitekture procesora 80386, efikasnija od njene alternative.
Primer.
CLD MOV DI, 200H MOV CX, 201H SLEDECI: MOV AL, ‘X’ REPNZ SCASB JNZ KRAJ DEC DI MOV AL, ‘Y’ STOSB INC CX LOOP SLEDECI KRAJ: |
CLD MOV DI, 200H MOV CX, 201H SLEDECI: MOV AL, ‘X’ REPNZ SCASB JNZ KRAJ DEC DI MOV AL, ‘Y’ STOSB JCXZ KRAJ JMP SLEDECI KRAJ: |
Pretražuje se 200 bajtova iz opsega 200H - 400H (relativno u odnosu na ES registar) i svaka pojava ASCII koda slova X biva zamenjena slovom Y:
Svaka od prethodno opisanih instrukcija uslovnog skoka ima analognu instrukciju uslovnog postavljanja bajtova. Ove instrukcije nisu postojale kod prethodnika procesora 80386, a dodate su kako bi prevodioci za jezike visokog nivoa lakše evaluirali bulove izraze.
Primer.
Neka je u nekom jeziku visokog nivoa deklarisana logička promenljiva UGRANICAMA, i naka je deklarisana celobrojna promenljiva PROM. Razmotrimo kako bi prevodilac generisao kod za naredbu dodele: UGRANICAMA = (PROM <= 10000).
Ukoliko ne bi postojala instrukcija uslovnog postavljanja bajtova, prevodioc bi generisao kod sledećeg oblika:
CMP PROM, 1000
MOV UGRANICAMA, 1
JG L1
DEC UGRANICAMA
L1:
Kod sličan onom iz prethodnog primera se pojavljuje vrlo često. Na primer, u prevođenju naredbe IF(PROM<=10000)OR(PROM>=20000) će najverovatnije na prethodno opisan način biti obrađen svaki od uslova PROM<=10000 i PROM>=20000.
Instrukcije za uslovno postavljanje bajtova su:
SETE D (eng. set on equal - postavi ukoliko su jednaki) - ? ZF, ako da 1® D, ako ne 0® D.
SETNE D (eng. set on not equal - postavi ukoliko nisu jednaki) - ? ŘZF, ako da 1® D, ako ne 0® D.
SETL D (eng. set on less than - postavi ukoliko je manji) - ? (SFÚOF), ako da 1® D, ako ne 0® D.
SETNL D (eng. set on not less than - postavi ukoliko nije manji) - ? Ř(SFÚOF), ako da 1® D, ako ne 0® D.
SETG D (eng. set on greater than - postavi ukoliko je veći) - ? Ř((SFÚOF)ÚZF), ako da 1® D, ako ne 0® D.
SETNG D (eng. set on not greater than - postavi ukoliko nije veći) - ? ((SFÚOF)ÚZF), ako da 1® D, ako ne 0®D.
SETB D (eng. set on below - postavi ukoliko je ispod) - ? CF, ako da 1® D, ako ne 0® D.
SETNB D (eng. set on not below - postavi ukoliko nije ispod) - ? ŘCF, ako da 1® D, ako ne 0® D.
SETA D (eng. set on above - postavi ukoliko je iznad) - ? Ř(CFÚZF), ako da 1® D, ako ne 0® D.
SETNA D (eng. set on not above - postavi ukoliko nije iznad) - ? (CFÚZF), ako da 1® D, ako ne 0® D.
SETS D (eng. set on sign - postavi ukoliko je postavljen fleg znaka) - ? SF, ako da 1® D, ako ne 0® D.
SETNS D (eng. set on not sign - postavi ukoliko nije postavljen fleg znaka) - ? ŘSF, ako da 1® D, ako ne 0®D.
SETO D (eng. set on overflow - postavi ukoliko je postavljen fleg prekoračenja) - ? OF, ako da 1® D, ako ne 0®D.
SETNO D (eng. set on not overflow - postavi ukoliko nije postavljen fleg prekoračenja) - ? ŘOF, ako da 1®D, ako ne 0® D.
SETP D (eng. set on parity - postavi ukoliko je postavljen fleg parnosti) - ? PF, ako da 1® D, ako ne 0® D.
SETNP D (eng. set on not parity - postavi ukoliko nije postavljen fleg parnosti) - ? ŘPF, ako da 1® D, ako ne 0® D.
Mnemonici prethodnih instrukcija za uslovno postavljanje bajtova imaju svoje sinonime:
SETE « SETZ (eng. set on zerro - postavi ukoliko je postavljen nula fleg).
SETNE « SETNZ (eng. set on not zerro - postavi ukoliko nije postavljen nula fleg).
SETL « SETNGE (eng. set on not greater or equal - postavi ukoliko nije veći ili jednak).
SETNL « SETGE (eng. set on greater or equal - postavi ukoliko je veći ili jednak).
SETG « SETNLE (eng. set on not less or equal - postavi ukoliko nije manji ili jednak).
SETNG « SETLE (eng. set on less or equal - postavi ukoliko je manji ili jednak).
SETB « SETNAE (eng. set on not above or equal - postavi ukoliko nije iznad ili jednak).
SETNB « SETAE (eng. set on above or equal - postavi ukoliko je iznad ili jednak).
SETA « SETNBE (eng. set on not bellow or equal - postavi ukoliko nije ispod ili jednak).
SETNA « SETBE (eng. set on bellow or equal - postavi ukoliko je ispod ili jednak).
SETP « SETPE (eng. set on parity even - postavi ukoliko je parnost parna).
SETNP « SETPO (eng. set on parity odd - postavi ukoliko je parnost neparna).
Dakle, instrukcija postavljanja bajta na osnovu uslova uprošćava sekvencu instrukcija dopuštanjem da se smeste rezultati ma kog testa direktno u registar ili memorijsku promenljivu. Uslov koji se postavlja je određen kao deo mnemonika, dok je odredište registar ili memorijska promenljiva dužine jednog bajta, u koju će se smestiti 1 ukoliko je spsecificirani uslov ispunjen, odnosno 0 ukolliko taj uslov nije ispunjen.
Primer.
Za slučaj naredbe iz prethodnog primera, generiše se otprilike sledeći kod:
CMP PROM, 1000
SETLE UGRANICAMA
Primer.
SETZ SETGE CH SETO BL |
SETC BVAR SETNZ BVAR SETA BVAR |
Ilustruje razne varijante korišćenja instrukcija za uslovno postavljanje bajtova:
Procesor 80386 ima instrukcije za brisanje i postavljanje flega prenosa (CF), flega pravca (DF), flega omogućavanja prekida (IF).
CLC (eng. clear carry flag - obriši fleg prenosa) - 0® CF.
CMC (eng. complement carry flag - komplementiraj fleg prenosa) - 1-CF® CF.
STC (eng. set carry flag - postavi fleg prenosa) - 1® CF.
CLD (eng. clear direction flag - obriši fleg pravca) - 0® DF.
STD (eng. set direction flag - postavi fleg pravca) - 1® DF.
CLI (eng. clear interrupt enable flag - obriši fleg omogućavanja prekida) - 0® IF.
STI (eng. set clear interrupt enable flag - postavi fleg omogućavanja prekida) - 1® IF.
Primer.
Ilustruje razne varijante korišćenja instrukcija za uslovno postavljanje bajtova:
CLD
CMC
STI
Razlikuju se dva načina rada sa spoljašnjim uređajima: poliranje (ili prozivanje, eng. polling) i prekidi (eng. interrupts).
U prvom slučaju procesor u regularnim vremenskim trenutcima proverava da lli je izvršena operacija sa spoljašnjim uređajem. Kako će se u najvećem broju slučajeva dobiti negativan odgovor, jasno je da se nepotrebno gubi vreme.
Kod prekida postoji mehanizam pomoću koga procesor dopušta spoljašnjem uređaju (npr. tastaturi, zvučnoj kartici itd.) da privuče procesorovu pažnju. Najveći broj modernih procesora radi sa spoljašnjim uređajima pomoću prekida.
Na procesoru 80386 postoje dva pina (eng. pin - iglica), nazvani NMI (eng. nonmaskable interrupt - nemaskirajući prekid) i INTR (eng. interrupt - prekid), koji omogućavaju da sa spoljašnjih uređaja dođu signali do procesora.
Kada spoljašnji uređaj pošalje signal na NMI pin, procesor će se zaustaviti bez obzira šta da je radio (naravno, neće se zaustaviti na polovini izvršenja jedne instrukcije) i povešće računa o prekidu. Međutim, može se dogoditi da se ovako procesor prekida u sred nekog veoma važnog posla, tako da se ovaj način prekidanja rada procesora treba izvršiti samo u stvarno kritičnim slučajevima. Takav slučaj je gubitak napona do kog dolazi neposredno pred nestanak struje (eng. power faliture), kada treba “javiti” procesoru da “spašava što se spasti može”.
Dakle, u najvećem broju slučajeva, spoljašnji uređaji trebaju slati signale na INTR pin procesora. Za signale koji dolaze kroz taj pin, može se postaviti da (ako je to potrebno) ti signali budu ignorisani od strane mikroprocesora. To ignorisanje postiže se brisanjem IF flega, tj. flega za omogućavanje prekida. Dakle, prekidi kroz INTR pin će biti omogućeni samo ukoliko je IF postavlljen. Instrukcije za postavljanje i brisanje flega za omogućavanje prekida biće opisane nešto kasnije.
Pored slanja signala na INTR pin, spoljašnji uređaj mora saopštiti i razlog za prekid rada procesora. Za procesor 80386 se razlog za prekid rada procesora naziva tip prekida i to je broj 0-255. Za svaki od tipova prekida procesor ima program koji mora izvršiti pre povratka na normalne zadatke. Rad tih programa često zavisi i od sadržaja opštih registara. Adrese početaka tih programa nalaze se u tabeli od 256 elementa, pri čemu je lokacija tabele određena operativnim sistemom. Programe koji se izvršavaju kada dođe do prekida nazivaju se prekidne procedure, ili prekidne rutine, ili rutine za opsluživanje prekida.
[ta će se, dakle, dogoditi kada procesor primi signal za prekid na svoj INTR pin, pri čemu je IF već postavljen? Po završetku izvršavanja tekuće instrukcije, procesor zaustavlja tekući rad i sprema se da izvrši proceduru koja odgovara tipu prekida:
1) Procesor sačuva sve relevantne informacije o tome šta radi, tako da se po završetku izvršavanja prekidne procedure može da se vrati na prethodno prekinuti posao. Uobičajeno mesto na kom se čuvaju takve relevantne informacije je stek. Vrednosti koje se čuvaju su tekuće postavljenje svih flegova i sadržaj brojača naredbi.
2) Procesor prima od spoljašnjeg uređaja tip prekida i postavlja IP na vrednost koja u tabeli prekida odgovara broju prekida. Tako će sledeća instrukcija koja se izvršava biti prva instrukcija prekidne procedure koja odgovara signaliziranom tipu prekida.
[ta će se dogoditi ako procesor primi signal na njegov NMI pin? U tom slučaju se ne testira vrednost IF, jer zahtev za prekid mora biti opslužen. Postupak opsluživanja je isti kao u prethodno opisanom slučaju, s tim što se ne šalje tip prekida, već se zna da je prekid tipa 2 u tabeli prekida rezervisan za prekidnu proceduru koja obrađuje nemaskirajuće prekide, odnosno za NMI prekidnu proceduru.
Dosad se govorilo isključivo o spoljašnjim, tj. eksternim prekidima. U pojedinim situacijama, kada se pri izvršavanju instrukcija dogodi nešto neočekivano, i sam procesor generiše prekide. Ti prekidi se nazivaju unutrašnji, tj. interni prekidi. Primeri unutrašnjih prekida su već opisivani - prekoračenje prilikom deljenja dovodi do generisanja prekida tipa 0.
Kod procesora 80386 su prvih 32 elementa tabele prekida rezervisani za unutrašnje prekide i nemaskirajući prekid. Prethodnici procesora 80386 su imali rezervisana 32 elementa tabele, ali su u upotrebi bili samo prvih pet među njima (prekidi tipa 0-4).
Tip prekida |
Rezervisano za |
0 |
Divide overflow for DIV and IDIV |
1 |
Debugger trapping |
2 |
External NMI |
3 |
One-byte debugger breakpoint trap |
4 |
Overflow interrupt: executes INTO when OF=1 |
5 |
BOUND instruction fault |
6 |
Illegal instruction fault |
7 |
No floating point processor avaliable |
8 |
Double fault |
9 |
Floating point segment overrun fault |
10 |
Invalid task state segment fault |
11 |
Segment not present fault |
12 |
Stack fault |
13 |
General protection fault |
14 |
Page fault |
15 |
Reserved by INTEL for future use |
16 |
Floating-point processor error |
17-31 |
Reserved by INTEL for future use |
Kao što je već poznato, u slučaju da dođe do prekoračenja ne generiše se odmah prekid, jer u mnogim slučajevima (uvek kada se radi sa neoznačenim brojevima) rezultat u kom je došlo do prekoračenja može smisleno da se obradi. Ipak, postoji efikasna (jednobajtna) instrukcija koja omogućava da dođe do prekida u zavisnosti od postavljenja OF.
INTO (eng. interrupt on overflow - prekid ukoliko je postavljen fleg prekoračenja) - ? OF, ako da procesor generiše prekid tipa 4.
Instrukcija INTO bi trebala da sledi iza svakog računanja sa označenim brojevima, kako bi se u tom slučaju obezbedilo da se ne dobije nekorektan rezultat usled prekoračenja.
Prekidna procesura treba da na kraju svog rada izvršavanje vrati tamo gde je prekinuto. To se svodi na restaurisanje vrednosti registra EIP i registra flegova, koji su do tada bili čuvani na steku. To restaurisanje sadržaja EIP i EFLAGS se realizuje pomoću posebne instrukcije.
IRETD (eng. interrupt return doublewors - povratak iz prekida sa dvostrukim rečima) - stek®EIP, stek®EFLAGS.
Instrukcija IRETD se razlikuje od instrukcije RET u tome što instrukcija povratak RET ne skida flegove sa steka.
Ukoliko procesor 80386 emulira nekog od prethodnika u familiji, tada je registar pokazivač insrukcije, isto kao i registar flegova, 16-bitan, pa se za povratak iz prekidne procedura koristi instrukcija IRET.
IRET (eng. interrupt return - povratak iz prekida sa) - stek®IP, stek®FLAGS.
Još jedna instrukcija koja se često javlja uz prekide je instrukcija zaustavljanja.
HLT (nem. halt - stani, zaustavi se) - zaustavlja procesor dok se ne dogodi prekid.
Instrukcija HLT zaustavlja procesor i EIP postavlja na adresu instrukcije koja neposredno sledi iza nje. Kada potom dođe do prekida, vrednost EIP i EFLAGS se šalju na stek, i procesor nastavlja sa izvršenjem instrukcija prekidne procedure. Po izvršenju IRETD instrukcije na kraju rada prekidne procedure, restauriše se vrednost EIP, pa se izvršavanje nastavlja od instrukcije koja se nalazi neposredno iza HLT instrukcije.
Kao što se iz dosada izloženog moglo zaključiti, u memoriji se nalaze 256 prekidnih procedura. Te procedure čekaju da se dogodi prekid, kako bi mogle da ga opsluže svojim izvršavanjem. ^esto bi imalo smisla pozvati neku od ovih procedura, čak iako se ne dogodi prekid. Budući da lokacija svake od ovih procedura postoji u tabeli, izgleda da bi se njihovo izvršavanje iz programerovog programa moglo lepo realizovati jednim indirektnim pozivom. Međutim, da bi sve to funkcionisalo (poznat je način funkcionisanja IRETD i IRET instrukcije) neophodno je da se pre izvršenja indirektnog poziva (E)FLAGS registar gurne na stek. Budući da se ovakva tehnika dosta često koristi, dizajneri procesora 80386 su predvideli jednu instrukciju koja radi sve što treba da se procesor ponaša kao da je dobio prekid sa spoljašnjeg uređaja, pri čemu je tip prekida specificiran u okviru same instrukcije.
INT D (eng. interrupt - prekid) - (E)FLAGS ® stek, (E)IP ® stek, tabela prekida(D) ® (E)IP.
Tip prekida je odredišni operand instrukcije, zadat je neposredno, i to je broj između 0 i 255. Prethodno opisani mehanizam poziva se pokazao toliko efikasnim da najveći broj današnjih računara ima prekidne porcedure koje se nikad ne izvršavaju na osnovu spoljašnjih zahteva.
Primer.
Ilustruje razne varijante korišćenja instrukcija vezanih za prekide:
INT 3 ; prekid tipa 3
INTO ; prekid pri prekoracenju
IRET
IRETD
HLT
Način korišćenja prekida, pa i DOS prekida, u programima je standardizovan na sledeći način:
MOV AH, broj_funkcije
MOV ostali_registri, parametri
INT broj_prekida
Interapt 21H u sebi objedinjuje preko 80 funkcija. Pored njega, za realizaciju operacija koje zahteva DOS koriste se još i INT 20H (prekid programa), INT 25H (direktno čitanje sektora diska), INT 26H (direktan upis u sektore diska) i INT 27H (prekid programa sa permanentnim zadržavanjem u memoriji). Prvi i poslednji među pobrojanima su zamenjeni odgovarajućim funkcijama u okviru INT 21H koje pružaju i dodatne pogodnosti, tako da se sve ređe koriste.
Napomena.
U DOS sistemu za programera imaju veliku važnost dva prekida, iako se ne pozivaju direktno iz programa. To su INT 23H koji DOS poziva kada detektuje pritisak na <Ctrl>-C ili na <Ctrl>-<Break>, te INT 24H (prekid zbog kritične greške) koji se poziva kada nastane neka od alarmantnih situacija (npr. obraćanje disk jedinici u kojoj nema diskete, štampanje na neuključeni štampač itd.). Ova dva prekida imaju vrlo neugodne posledice u programima koji žele da imaju totalnu kontrolu nad računarom.
Napomena.
Veliki broj funkcija INT 21H odnosi se na rad sa datotekama. Datoteka sa podacima se na disku opisuje na klasičan način: prostim ređanjem podataka. U datoteci nema nikakvih zaglavlja niti drugih posebnih informacija. Podaci o svakoj datoteci su zapisani u direktorijumu koji čuva, između ostalog, i sledeće podatke:
1. naziv datoteke;
2. tačnu dužinu u bajtovima; prostor koji datoteka zauzima na disku je uvek veći, jer se odvajanje prostora vrši u tzv. jedinicama alokacije “klasterima” koji objedinjuju više fizičkih sektora diska;
3. vreme i datum nastanke/izmene datoteke
4. atribut datoteke (jedan bajt) u kom svaki od sledećih bitova ima tačno specificirano značenje: bit 0 označava da je datoteka samo za čitanje (eng. read only), bit 1 označava da je datoteka skrivena (eng. hidden), bit 2 označava da li je datoteka sistemska (eng. system), bit 3 ukazuje da ulaz u direktorijum nije datoteka već globalni naziv diskete (eng. volume), bit 4 označava da je datoteka poddirektorijum i da u sebi sadrži na isti način struktuirane podatke za sve datoteke koje se nalaze unutar tog poddirektorijuma (eng. sub directory), bit 5 je arhiv bit (eng. archive) koji ukazuje da je sadržaj datoteke menjan od poslednjeg pravljenja zaštitnih kopija tj. od poslednjeg bekapa (eng. back up).
DOS nudi dva pristupa podacima - sekvencijalan i direktan. Dužina sloga podataka koji se koristi u datotekama sa direktnim rpistupom nigde se ne zapisuje, tako da drugi programi koji koriste iste podatke moraju ovu informaciju imati ugrađenu kao unapred poznatu veličinu. U funkcijama višeg nivoa koje se danas koriste najpreciznije bi bilo reći da DOS koristi neku vrstu mešavine ova dva pristupa: mesto sa koga će sledeći podatak iz datoteke biti pročitan može se u bilo kom trenutku proizvoljno postaviti, kao što se u svakom trenutku može pročitati i proizvoljno dugačak slog.
U tabeli koji sledi opisane su neke od tzv. DOS
funkcija, tj. rezultati koji se dobijaju pozivom prekidne procedure za prekid
tipa 21H. Kao što već istaknuto, u registru AH se smešta tzv. broj
funkcije.
011 - ^itanje znaka sa standardnog ulaza sa ehom
Izlaz: AL = znak
021 - Upis znaka na standardni izlaz
Ulaz: DL = znak
031 - ^itanje znaka sa RS232 interfejsa
Izlaz: AL = znak
041 - Upis znaka na RS232 interfejs
Ulaz: DL = znak
051 - Upis znaka na štampač
Ulaz: DL = znak
06 - Direktno čitanje/upis sa konzole
Ulaz: DL = znak - zahtev za upis
DL = FF - zahtev za citanje
Izlaz: ZF = 1 - taster nije pritisnut
ZF = 0 - taster jeste pritisnut
AL = taster
07 - Nefiltrirano čitanje sa standardnog ulaza bez eha
Izlaz: AL = znak
081 - Upis znaka sa standardnog ulaza bez eha
Ulaz: AL = znak
091 - Upis niske na standardni izlaz
Ulaz: DS:DX = niska (završava se sa $)
0A1 - ^itanje niske sa editovanjem
Ulaz: DS:DX = bafer
DS:[DX] = dužina bafera
Izlaz: DS:[DX+1] = dužina niske
DS:DX+2 = niska
0B - Status ulaza
Izlaz: AL = 0 - znak spreman za čitanje
AL = FF - nema spremnog znaka
0C - Restovanje ulaznog bafera i čitanje znaka ili niske
Ulaz: AL = broj funkcije za čitanje (01, 06, 07, 08, 0A)
Izlaz = kao kod pozvane funkcije
0D - Resetovanje disk jedinice
0E - Postavljanje aktivne disk jedinice
Ulaz: AL = broj disk jedinice (0=A, 1=B,...)
Izlaz: AL = broj logičkih disk jedinica u sistemu
0F2 - Otvaranje datoteke
Ulaz: DS:DX = FCB
Izlaz: AL = 0 - FCB je popunjen
Greška: AL = FF - datoteka ne postoji
102 - Zatvaranje datoteke
Ulaz: DS:DX = FCB
Izlaz: AL = 0
Greška: AL = FF - datoteka ne postoji
112 - Nalaženje prve odgovarajuće datoteke
Ulaz: DS:DX = FCB
Izlaz: AL = 0 - DTA je popunjen kao standardni ili prošireni FCB
Greška: AL = FF - ni jedna datoteka ne odgovara postavljenom nazivu
122 - Nalaženje sledeće datoteke
Ulaz: DS:DX = FCB
Izlaz: AL = 0 - DTA je popunjen kao standardni ili prošireni FCB podacima za sledeću datoteku
Greška: AL = FF - nema više datoteka čiji naziv odgovara
132 - Brisanje datoteke
Ulaz: DS:DX = FCB
Izlaz: AL = 0
Greška: AL = FF - nijedna datoteka nije obrisana
142 - Sekvencijalno čitanje
Ulaz: DS:DX = FCB
Izlaz: AL = 0
Greška: AL = 1 - kraj datoteke
= 2 - prekoračenje granice segmenta
= 3 - pročitan samo kraj bloka kad se naišlo na kraj datoteke
152 - Sekvencijalni upis
Ulaz: DS:DX = FCB
Izlaz: AL = 0
Greška: AL = 1 - disk pun
= 2 - prekoračenje granice segmenta
162 - Kreiranje datoteke
Ulaz: DS:DX = FCB
Izlaz: AL = 0
Greška: AL = FF - nema mesta u direktorijumu
172 - Preimenovanje datoteke
Ulaz: DS:DX = FCB
Izlaz: AL = 0
Greška: AL = FF - originalni naziv ne postoji, ili novi naziv već postoji
19 - Informacija o aktivnoj disk jedinici
Izlaz: AL = broj diska (0=A, 1=B,...)
1A2 - Postavljanje DTA
Ulaz: DS:DX = DTA
1B - Informacija o odvajanju prostora na aktivnom disku
Izlaz: AL = broj sektora po klasteru
CX = veličina fizičkog sektora na disku
DX = broj klastera na disku
DS:[BX] = FF - dvostrani flopi, 8 sektora po traci
=FE - jednostrani flopi, 8 sektora po traci
= FD - dvostrani flopi, 9 sektora po traci
= FC - jednostrani flopi, 9 sektora po traci
= F9 - dvostrani flopi, 15 sektora po traci
= F8 - tvrdi disk.
1C - Informacija o odvajanju prostora na disku
Ulaz: DL = broj disk jedinice (0=A, 1=B,...)
Izlaz: AL = broj sektora po klasteru
CX = veličina fizičkog sektora na disku
DX = broj klastera na disku
DS:[BX] = FF - dvostrani flopi, 8 sektora po traci
=FE - jednostrani flopi, 8 sektora po traci
= FD - dvostrani flopi, 9 sektora po traci
= FC - jednostrani flopi, 9 sektora po traci
= F9 - dvostrani flopi, 15 sektora po traci
= F8 - tvrdi disk.
212 - ^itanje sa direktnim pristupom
Ulaz: DS:DX = FCB
Izlaz: AL = 0
Greška: AL = 1 - kraj datoteke
= 2 - prekoračenje granice segmenta
= 3 - pročitan samo kraj bloka kad se naišlo na kraj datoteke
222 - Upis sa direktnim pristupom
Ulaz: DS:DX = FCB
Izlaz: AL = 0
Greška: AL = 1 - disk pun
= 2 - prekoračenje granice segmenta
232 - Veličina datoteke u slogovima
Ulaz: DS:DX = FCB
Izlaz: AL = 0
FCB popunjen od ofseta 21H
Greška: AL = FF - datoteka ne postoji
242 - Postavljanje rednog broj sloga
Ulaz: DS:DX = FCB
Izlaz: nodifikovani podaci u FCB
Greška: AL = FF - datoteka ne postoji
25 - Postavljanje vektora prekida, tj. elementa u tabeli prekida
Ulaz: DS:DX = tabela prekida
AL = broj prekida
Greška: AL = FF - datoteka ne postoji
27 - ^itanje proizvoljnog broja slogova
Ulaz: DS:DX = FCB
CX = broj slogova
Izlaz: AL = 0
CX = broj pročitanih slogova
Greška: AL = 1 - kraj datoteke
= 2 - prekoračenje granice segmenta
= 3 - pročitan samo kraj bloka kad se naišlo na kraj datoteke
28 - Upis proizvoljnog broja slogova
Ulaz: DS:DX = FCB
CX = broj slogova
Izlaz: AL = 0
CX = broj pročitanih slogova
Greška: AL = 1 - disk pun
= 2 - prekoračenje granice segmenta
292 - Raščlanjivanje naziva datoteke
Ulaz: DS:DX = naziv
bit 3 AL-a = 1 - menja polje za ekstenziju samo ako je ona zadata u nazivu
bit 3 AL-a = 0 - menja polje za ekstenziju u svakom slučaju, a ako ne postoji u nazivu popunjava prostor blankovima
bit 2 AL-a = 1 - menja polje za ime samo ako je isto zadato u nazivu
bit 2 AL-a = 0 - menja polje za ime u svakom slučaju, a ako ne postoji u nazivu popunjava prostor blankovima
bit 1 AL-a = 1 - menja broj diska samo ako je disk zadat u nazivu
bit 1 AL-a = 0 - menja broj diska u svakom slučaju
bit 0 AL-a = 1 - ignoriše razmak ispred naziva
bit 0 AL-a = 0 - uzima i razmak ispred naziva
Izlaz: AL = 0 - sve u redu
AL = 1 - naziv sadrži džoker znake
ES:DI = FCB
Greška: AL = FF - oznaka diska je nevažeća
2A - ^itanje datuma sa sistemskog kalendara
Izlaz: CX = godina (1980-2099)
DH = mesec
DL = dan
AL = dan u nedelji (0=nedelja)
2B - Postravljanje datuma na sistemskom kalendaru
Ulaz: CX = godina (1980-2099)
DH = mesec
DL = dan
AL = dan u nedelji (0=nedelja)
Izlaz: AL = 0
Greška: AL = FF - neka od vrednosti je van opsega
2C - ^itanje vremena sa sistemskog časovnika
Izlaz: CH = sat (0-23)
CL = minut
DH = sekunda
DL = stotinka
2D - Postravljanje vremena na sistemskom časovniku
Ulaz: CH = sat (0-23)
CL = minut
DH = sekunda
DL = stotinka
Izlaz: AL = 0
Greška: AL = FF - neka od vrednosti je van opsega
2E - Određivanje da li vršiti proveru nakon upisa na disk
Ulaz: AL = 0 - isključi proveru nakon upisa
AL = 0 - uključi proveru nakon upisa
2F2 - Informacija o adresi aktivnog DTA
Izlaz: ES:BX = DTA
30 - Informacija o verziji operativnog sistema
Izlaz: AL = 0 - radi se o verziji 1.00
AL > 0 - tzv. viši broj verzije (npr. za MS DOS 6.20 će AL sadržati broj 6)
AH - tzv. niži broj verzije (npr. za MS DOS 6.20 će AH sadržati broj 2)
31 - Prekid programa uz njegovo zadržavanje u memoriji
Ulaz: AL = izlazni kod
DX = potrebna količina memorije u paragrafima
33 - ^itanje/postavljanje stanja posle <Ctrl>+<Break> prekida
Ulaz: AL = 0 - čita stanje
= 1 - postavlja stanje
DL = 0 - isključuje proveru
= 1 - uključuje proveru
35 - ^itanje vektora prekida, tj. elementa u tabeli prekida
Ulaz: AL = broj prekida
Izlaz: ES:BX = vektor prekida
36 - Informacija o količini slobodnog prostora na disku
Ulaz: DL = broj disk jedinice (0=aktivna, 1=A, 2=B,...)
Izlaz: AX = broj sektora po klasteru
BX = broj slobodnih klastera
CX = fizička veličina sektora
DX = ukupan broj klastera na disku
Greška: AX = FFFF - pogrešan broj disk jedinice
393 - Kreiranje poddirektorijuma
Ulaz: DS:DX = naziv poddirektorijuma
Greška: 3-5-6-16
3A3 - Brisanje poddirektorijuma
Ulaz: DS:DX = naziv poddirektorijuma
Greška: 3-5-6-16
3B3 - Postavljanje tekućeg direktorijuma
Ulaz: DS:DX = naziv direktorijuma
Greška: 3
3C3 4 - Kreiranje datoteke
Ulaz: DS:DX = naziv datoteke
CX = atribut koji će biti korišćen
bit 0 - read only
bit 1 - hidden
bit 2 - system
bit 3 - volume
bit 4 - subdirectory (ignoriše se 1)
bit 5 - archive (ignoriše se 1)
Izlaz: AX = rukovalac datoteke
Greška: 3-4-5
3D3 4 - Otvaranje datoteke
Ulaz: DS:DX = naziv datoteke
AL = 0 - samo čitanje
= 1 - samo upisivanje
= 2 - čitanje i upisivanje
Izlaz: AX = rukovalac datoteke
Greška: 1-2-3-4-5-12
3E3 4 - Zatvaranje datoteke
Ulaz: BX = rukovalac datoteke
Greška: 6
3F3 4 - ^itanje sadržaja datoteke
Ulaz: BX = rukovalac datoteke
CX = broj bajtova koji se čitaju
DS:DX = bafer
Izlaz: AX = broj pročitanih bajtova
Greška: 5-6
403 4 - Upis u datoteku
Ulaz: BX = rukovalac datoteke
CX = broj bajtova koji se upisuje
DS:DX = bafer
Izlaz: AX = broj upisanih bajtova
Greška: 5-6
AX = 0 - disk je pun
413 - Brisanje datoteke
Ulaz: DS:DX = naziv datoteke (mogu i džokeri)
Greška: 2-5
423 4 - Menjanje pokazivača pozicije za čitanje/upis kod datoteke
Ulaz: BX = rukovalac datoteke
CX = viša reč vrednosti pomeranja
DX = niža reč vrednosti pomeranja
AL = 0 - pomeranje se vrši apsolutno od početka datoteke
= 1 - pomeranje se vrši relativno od tekuće pozicije
= 2 - pomeranje se vrši apsolutno od kraja datoteke
Izlaz: DX = viša reč nove apsolutne pozicije u odnosu na početak datoteke
AX = niža reč nove apsolutne pozicije u odnosu na početak datoteke
Greška: 1-6
433 - ^itanje/postavljanje atributa datoteke
Ulaz: DS:DX = naziv datoteke
AL = 0 - čita atribut bajt
= 1 - menja atribut bajt
CX = novi atribut (ako se radi o menjanju)
Izlaz: CX = pročitani atribut
Greška: 1-2-3-5
473 - ^itanje tekućeg direktorijuma
Ulaz: DS:DX = bafer
DL = broj disk jedinice (0=aktivna, 1=A, 2=B,...)
Izlaz: bafer popunjen nazivom tekućeg direktorijuma (sa celim putem).
Greška: 15
483 - Odvajanje memorijskog bloka
Ulaz: BX = veličina bloka u paragrafima
Izlaz: AX = segmentna adresa bloka
BX = maksimalna izdvojena veličina (ako nema dovoljno prostora)
Greška: 7-8
493 - Oslobađanje prethodno odvojenog memorijskog bloka
Ulaz: ES = segmentna adresa bloka
Greška: 7-8
4A3 - Menjanje količine dodeljene memorije
Ulaz: ES = segmentna adresa bloka
BH = nova veličina bloka (u paragrafima)
Izlaz: BX = maksimalna novoizdvojena veličina (ako nema dovoljno prostora)
Greška: 7-8
4B3 5 - Izvršavanje programa
Ulaz: AL = 0
ES = segmentna adresa parametar bloka
BX= ofset parametar bloka
DS = segmentna adresa naziva programa
DX= ofset naziva programa
Izlaz: Uništen je sadržaj svih registara sem CS i IP
4C - Prekidanje program i određivanje izlaznog statusa
Ulaz: AL = izlazni status
Napomene:
1) Broj 1 kod rednih brojeva funkcije označava da se detektuje pritisak na <Ctrl>+C ili na <Ctrl>+<Break>, pa se potom opslužuje prekid tipa 23.
2) Broj 2 kod rednih brojeva funkcije označava da se radi o starijim funkcijama za rad sa datotekama koje koriste FCB strukture (eng. file control block - blok za kontrolu datoteka). FCB struktura je u osnovnoj varijanti dugačka 37 bajtova, i sadrži sledeća polja:
5. broj disk jedinice (ofset 00H),
6. levo poravnato ime datoteke (ofset 01H),
7. levo poravnata ekstenzija (ofset 09H),
8. redni broj bloka koji se trenutno čita (ofset 0CH),
9. dužina sloga (ofset 0EH),
10. veličina datoteke u bajtovima (ofset 11H),
11. datum kreiranja/izmene datoteke (ofset 14H),
12. vreme kreiranja/izmene datoteke (ofset 16H),
13. rezervisano sistemsko područje (ofset 18H),
14. redni broj sloga (ofset 20H),
redni broj sloga za datoteke sa direktnim pristupom (ofset 21H-24H).
Za korektan rad sa datotekama pomoću FCB strukture, neophodno je da postoji i DTA (eng. data transfer area - prostor za prenos podataka) deo memorije koji sluči za prenos podataka, tj. kao bafer (eng. buffer - bafer, tampon). Odgovarajućom DOS funkcijom se DOS-u stavlja na znanje koja je početna adresa ovog područja.
U ovom slučaju, postupak otvaranja datoteke teče na sledeći način:
1. program odvaja 37 bajtova za FCB;
2. program postavlja naziv i ekstenziju datoteke;
3. program poziva odgovarajuću DOS funkciju za otvaranje datoteke;
4. DOS pronalazi datoteku na disku;
5. DOS popunjava polja sa vremenom, datumom i dužinom datoteke;
6. DOS postavlja dužinu sloga (ofset 0EH) na inicijalnu vrednost 128.
Pored standardne strukture FCB, uvedena je i proširena FCB. Kod proširenog FCB-a prvi bajt ima vrednost 0FFH (što ne može biti broj disk-jedinice, pa se tako prošireni FCB razlikuje od standardnog), zatim slede 5 bajtova rezervisanog DOS područja, pa atribut. Ostatak je identičan standardnom FCB. Ukupna dužina proširenog FCB je 44 bajta.
Rad sa datotekama pomoću FCB struktura karakterišu sledeći nedostaci:
ne može se koristiti hijerarhijska struktura direktorijuma, jer se u FCB definiše samo naziv datoteke, a ne i put - pa datoteka mora biti u aktivnom direktorijumu;
metod rada sa datotekama preko FCB struktura je veoma komplikovan i zahteva mnogo predradnji;
pozicioniranje i čitanje blokova unutar datoteke je nepraktično.
3) Broj 3 kod rednih brojeva funkcije označava da se radi o novom mehanizmu za prijavljivanje grešaka tokom izvršavanja prekidne procedure. Tu se koristi fleg prenosa CF. Ako je tokom izvršenja prekidne procedure došlo do greške, tada se CF postavlja, a u registru AX se nalazi broj greške.
Brojevi koji se prilikom pojave greške nalaze u AX imaju sledeća značenja:
1 |
nevažeći broj funkcije; |
2 |
datoteka ne postoji; |
3 |
staza (eng. path put) ne postoji; |
4 |
previše otvorenih datoteka, pa nema slobodnih rukovaoca datoteka; |
5 |
pristup nije odobren, što se javlja pri pokušaju upisa u datoteku sa postavljenim RO (eng. read only); |
6 |
upotreblen je nepostojeći rukovalac datoteke; |
7 |
uništeni su blokovi za kontrolu raspodele memorije; |
8 |
nedovoljno memorije da se zadovolji zahtev; |
9 |
upotrebljena je adresa koja ne odgovara nijednom od blokova u sistemu odvajanja memorije; |
10 |
nevažeći blok okruženja (eng. enviroment); |
11 |
nevažeći format; |
12 |
nevažeći kod za pristup; |
13 |
nevažeći podaci; |
14 |
|
15 |
nevažeći broj disk jedinice; |
16 |
pokušaj brisanja tekućeg direktorijuma; |
17 |
ne radi se o istom uređaju; |
18 |
nema više odgovarajućih datoteka. |
4) Broj 4 kod rednih brojeva DOS funkcija za rad sa datotekama označava da se radi o novijim funkcijama za rad sa datotekama koje koriste rukovaoce datoteka (zastupnike datoteka - eng. file handler). Naime, za otvaranje datoteke dovoljno je zadati njen naziv, uključujući i put. Na osnovu ove informacije DOS interno kreira blokove podataka potrebne za rad sa datotekama, a programu vraća mali ceo broj kojim će u toku čitanja i pisanja identifikovati ovu vezu. Taj broj se naziva rukovalac datoteke. Kada treba pročitati n bajtova iz datoteke, program poziva odgovarajuću funkciju navodeći rukovalac datoteke, adresu od koje treba smeštati podatke i broj bajtova. Rukovalac datoteke je obavezno ulazni parametar svih funkcija ove vrste koje rade sa datotekama.
Prilikom podizanja DOS-a otvara se određen broj datoteka. Stoga su za rukovaoce datoteka upotrebljeni sledeći brojevi:
0 - CON kao ulaz - standardni ulaz
1 - CON kao izlaz - standardni izlaz
2 - CON kao izlaz - standardni kanal za ispis greške
3 - AUX kao ulaz/izlaz - standardni pomoćni uređaj (RS232)
4 - LST kao izlaz - standardni kanal za ispis na štampač
Za prethodno popisane veze nije potrebno otvarati kanale - dovoljno je koristiti dati rukovalac datoteke.
Ovakvom metodom se može lako ostvariti preusmeravanje standardnog ulaza/izlaza. Osobina brojeva koji se koriste kao rukovaci datoteka je da se za svaku novu datoteku bira najmanji slobodan broj. Ako se tako, pomoću odgovarajuće DOS funkcije, zatvori veza za vrednost rukovaoca datoteke 1 i potom otvori ma koja druga datoteka, rukovalac nove datoteke će dobiti vrednost 1, čime je svaki ispis preko standardnog izlaza usmeren u nju. Ovakav metod koristi komandni interpretator COMMAND.COM, kada u komandnoj liniji naiđe na znak preusmeravanja. U tom kontekstu se nazire i smisao datoteke sa rukovaocem jednakim 2: ako se izlaz i preusmeri u neku datoteku, programu je i dalje na rasplolaganju kanal za ispis na ekran, kako bi poruke o greškama bile vidljive u toku rada programa.
5) Broj 5 kod DOS funkcije označava da parametar blok ima sledeću strukturu: segmentna adresa okruženja (ofset 0-1), ofset parametara programa (ofset 2-3), segmentna adresa parametara programa (ofset 4-5), ofset prvog FCB iz PSP (6-7), segmentna adresa prvog FCB iz PSP (8-9), ofset drugog FCB iz PSP (A-B), segmentna adresa drugog FCB iz PSP (C-D)
Procesor 80386 ima tri instrukcije za pojednostavljivanje koda potrebnog da podrži određene karakteristike viših programskih jezika. Te instrukcije služe za lakše izvršavanje provere da li je indeks niza izašao van za to predviđene dimenzije, kao i za lakšu implementaciju podrške za rad procedura i funkcija kod viših programskih jezika.
Nijedna od ovih instrukcija nije postojala kod 286-tice i njenih prethodnika. Prva među prethodno pomenutim instrukcijama je:
BOUND D, S (eng. bound - ograniči, omeđi) - generiše prekid tipa 5 ukoliko se D ne nalazi između vrednosti koje su specificirane pomoću S.
Odredišni operand D je registarski, dok je S memorijski. Instrukcija BOUND proverava da li označena vrednost u registru dužine 16, odnosno 32, leži unutar određenih granica. Granice se nalaze u dvema uzastopnim rečima, odnosno dvostrukim rečima, u memoriji. Vrednost u registru treba da bude veća ili jednaka od prve, a manja ili jednaka od druge memorijske vrednosti.
Primer.
Sledeća instrukcija vrši proveru da li je indeks niza (u registru EBX) izašao iz dozvoljenog intervala (specificiranog dvema dvostrukim rečima koje se nalaze u memoriji, počev od lokacije DMEMLOCS), i ako je indeks niza van opsega, generiše se prekid tipa 5.
BOUND EBX, DMEMLOCS
Da bi se lepo upoznali sa drugim dvema instrukcijama, neophodno je shvatiti mehanizam poziva funkcije, odnosno procedure, u višem programskom jeziku. Za primer će se koristiti programski jezik PASCAL.
Primer.
PASCAL procedura sadrži odeljak deklaracije procedure i telo procedure:
procedure A; šodeljak deklaracije procedureć
var
a1, a2: integer;
begin štelo procedureć
a1:= a2+1;
end;
Primer.
Kod PASCAL procedure u odeljku deklaracije mogu biti deklarisane i druge procedure:
procedure A;
var
a1, a2: integer;
procedure B;
var
b1, b2: integer;
begin
b2:= a1+2;
end;
procedure C;
var
c1, c2: integer;
begin
c1:= a2+3;
end;
begin
a1:= a2+1;
end;
Primećuje se da objekti (promenljive, procedure) deklarisane u odeljku deklaracija procedure A mogu biti korišćeni kako u telu procedure A, tako i u telu procedura B i C. Ali, objekti deklarisani u odeljku deklaracija procedure B mogu biti korišćeni samo unutar tela procedure B.
Napomena.
Situaciju dodatno komplikuje i postojanje rekurzivnih procedura u PASCAL-u. Jer, jasno je (o tome je bilo reči kada je opisivana uloga steka kod podprograma) da svaki poziv rekurzivne procedure mora imati svoj prostor za smeštaj promenljivih koje su deklarisane unutar procedure. Stoga, promenljive moraju biti alocirane pri svakom od poziva i dealocirane po završetku rada procedure. Uobičajeno mesto za smeštaj ovakvih promenljivih je stek.
PASCAL kompajleri obično generišu kod koji pri pozivu procedure izvodi sledeće akcije:
1) alocira memorijski prostor (nazvan stek-okvir) na steku, za promenljive koje su deklarisane u proceduri;
2) postavlja (E)BP da pokazuje na memorijsku lokaciju, tj. tačku početka (odnosno najnižu adresu) stek-okvira.
Primer.
Sledeći dijagrami prikazuju stek-okvire procedure A i procedure B datih u trećem primeru ovog poglavlja.
|
veće memorijske adrese Ż |
... |
|
|||
|
|
|
|
|
||
|
(E)BP ® |
|
|
stek-okvir procedure B |
||
|
|
|
|
|
||
|
|
|
|
|
||
|
|
|
|
|
||
|
|
|
|
|
||
|
|
|
|
|
||
|
|
|
|
|
||
|
|
|
|
stek-okvir procedure A |
||
|
|
|
|
|
||
|
|
... |
rast steka |
|||
Sada se za pristup promenljivoj deklarisanoj u proceduri (tzv. lokalnoj promenljivoj procedure) koristi fiksna veličina: razmak tj. rastojanje adrese promenljive od početka stek-okvira. Ovakvo adresiranje naziva se stek-okvir relativno adresiranje.
Primer.
Uočimo drugi primer u ovom poglavlju. Ako je promenljiva a2 smeštena 8 bajtova od početka stek-okvira, a promenljiva a1 6 bajtova od početka stek-okvira, onada bi pri prevođenju tela procedure A, PASCAL kompajler generisao otprilike sledeći kod:
MOV AL, [EBP-8]
INC AL
MOV [EBP-6], AL
Pri implementaciji PASCAL procedura mora se voditi računa o tome da je svaka promenljiva kojoj se može pristupiti u nekoj proceduri smeštena bilo u stek-okviru date procedure, bilo u stek-okviru procedure u kojoj je data procedura umetnuta. Stoga, stek-okvir mora sadržati pokazivače na svaki od prethodno pobrojanih stek-okvira. Lista ovakvih pokazivača naziva se displej (eng. display - prikaz). Može se reći da displej neke procedure opisuje statičke veze koje postoje između te procedure i svih procedura u kojima je ona ugnježdena.
Primer.
Na sledećoj slici vidimo iste stek-okvire iz prethodnog primera na kojima su prikazani displeji i alocirane promjenjljive.
|
veće memorijske adrese Ż |
... |
|
|
|
|
|
|
|
|
|
b2 |
|
|
|
|
b1 |
prostor za promenljive |
|
|
|
· |
|
|
|
|
· |
displej |
|
|
(E)BP ® |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a2 |
|
|
|
|
a1 |
prostor za promenljive |
|
|
|
· |
displej |
|
|
|
|
|
|
|
|
|
|
|
|
|
... |
rast steka |
|
Po izlasku iz date procedure, moraju se izvršiti sledeće akcije:
1) stek okvir mora biti dealociran;
2) registar (E)BP se mora postaviti tako da pokazuje na stek okvir koji je bio tekući u trenutku kada je data procedura bila pozvana.
Veza između pozivajuće i pozvane procedure naziva se dinamička veza (eng. dynamic link - dinamička veza). Jasno je da stek-okvir procedure koja podziva datu proceduru ne mora biti isti sa stek-okvirom procedure u kojoj je data procedura ugnježdena, tj. dinamička veza se ne mora poklapati sa statičkom vezom.
Primer.
Procedura B iz trećeg primera u ovm poglavlju je ugnježdena u proceduri A, ali može biti pozvana i iz procedure A i iz procedure C.
Dealokacija (oslobađanje, uništavanje) stek-okvira se postiže stavljanjem tekuće vrednosti registra (E)BP u registar (E)SP, tj. postavljanjem (E)SP-a na početak tekućeg stek-okvira.
Izmena (E)BP-a pri izlasku iz procedure tako da on pokazuje na prethodno aktivni stek-okvir neće biti moguća ukoliko se pre poziva date procedure u stek-okviru te procedure, a pri njegovom formiranju, ne sačuva dotadašnja vrednost (E)BP-a. Ta vrednost, tj. dinamička veza se obično stavlja u stek-okvir neposredno pre displeja.
Dakle, pre svakog povratka iz procedure, kompajler mora generisati kod za delokaciju stek-okvira i restaurisanje registra EBP.
Primer.
Slika prikazuje stek-okvir sa dinamičkim vezama za PASCAL kod opisan u trećem primeru ovog poglavlja, a uz pretpostavku da se u telu procedure A nalazi i poziv procedure B.
|
veće memorijske adrese Ż |
... |
|
|
|
|
|
|
|
|
|
b2 |
|
|
|
|
b1 |
prostor za promenljive |
|
|
|
· |
|
|
|
|
· |
displej |
|
|
(E)BP ® |
· |
dinamička veza |
|
|
|
|
|
|
|
|
|
|
|
|
|
a2 |
|
|
|
|
a1 |
prostor za promenljive |
|
|
|
· |
displej |
|
|
|
· |
dinamička veza |
|
|
|
|
|
|
|
|
... |
rast steka |
|
Instrukcije ENTER i LEAVE obavljaju upravo te zadatke.
LEAVE (eng. leave - napusti) instrukcija nema argumenata. Izvršava operacije neophodne za korektan povratak iz procedure. Njen efekat bi se mogao predstaviti na sledeći način:
ESP ¬ EBP
POP EBP
ENTER D, S (eng. enter - uđi) ima dva operanda. Ova instrukcija izvršava operacije neophodne za korektan ulazak u proceduru. Drugi operand predstavlja nivo ugnježdavanja date procedure, koji procesoru saopštava kolika je veličina displeja. Najspoljašnjiji nivo je 1. Prvi operand je broj bajtova u memoriji potreban za promenljive deklarisane u proceduri. Formalni opis ove instrukcije je dat sledećim algoritmom:
;formiranje dinamicke veze
PUSH EBP
;formiranje displeja
privremena vrednost STEK_OKVIR_PTR ¬ ESP
if D > 0 then
repeat D -1 put:
EBP ¬ EBP-2
PUSH rec na koji pokazuje EBP
end repeat
PUSH STEK_OKVIR_PTR
endif
ESP ¬ FRAME_PTR
;formiranje prostora za lokalne promenljive
ESP ¬ ESP-S
Dakle, ukoliko je drugi operand nula, to znači da instrukcija ne uključuje displej u stek-okvir. Ovo je korisno za jezike poput C - a, u kojima nema ugnježdenih procedura.
Primećuje se da, kada procesor 80386 emulira neki od predhodnika, instrukcije ENTER i LEAVE rade na osnovu 16-bitnih vrijednosti registara BP i SP.
Kao što je u poglavlju XI i istaknuto, sistem prekida obezbeđuje sinhronizaciju procesora 80386 sa spoljnim uređajima. Arhitektura procesora 80386 obezbeđuje još dva oblika sinhronizacije:
Prvi oblik uključuje korišćenje podređenog procesora (koprocesora) za implementaciju skupa instrukcija za rad sa brojevima u pokretnom zarezu. Tokom postojanja i razvoja procesora iz familije 80x86, izvršenje instrukcija u pokretnom zarezu je bilo dodeljeno podređenom procesoru. Konkurentni rad procesora i koprocesora će biti opisan u delu koji se bavi arhitekturom i načinom funkcionisanja samog koprocesora. Zasad će samo biti istaknuto da procesor 80386 interpretira instrukcije za rad sa brojevima u pokretnom zarrezu kao direktive za sinhronizovanje sa podređenim procesorom, za komunikaciju sa tim procesorom, i za upravljanje memorijskim pristupom za taj procesor.
Drugi oblik sinhronizacije između dva procesora je deljenje zajedničkih resursa. Odranije je poznato da konkurentan rad nad istim resursom može da proizvede probleme tj. naruši integritet podataka. Takođe je poznato da je uvođenje semafora put za prevazilaženje problema nastalih usled konkurentnog rada. Ovde se semafor realizuje kao memorijska lokacija koja procesoru signalizira da li neko drugi trenutno koristi deljenu memoriju. Jasno je da pri radu sa semafora mora postojati nedjeljiva operacija, tj. između očitavanja vrijednosti da je slobodna i postavljanja na zauzeto ne smije ništa da se desi.
Primer.
Sledeća sekvenca operacija predstavlja primer nekorektnog rada sa lokacijom koja predstavlja semafor.
1 - I čita 0
(slobodno)
2 - II čita 0
(slobodno)
3 - I postavlja 1
(zauzima)
4 - II postavlja 1
(zauzima)
Uočava se da je postavljanje jedinice (koja signalizira zauzetost) od strane procesa I, prekinuto, i da je u tom prekidu od strane procesa II očitana neadekvatna vrednost semafora. Tako se dogodilo da i proces I i proces II imaju informaciju da je delejni resurs njima stavljen na raspolaganje.
Da bi se čitanje raspoloživosti i postavljanje zauzetosti nekog resursa obavili pomoću jedne instrukcije, koristi se XCHG instrukcija.
Primer.
Sledeća sekvenca instrukcija se koristi da dohvati vrednosti iz bajt-memorijske promjenljive SEMA, i da, ukoliko SEMA indicira da je resurs slobodan, postavi da je resurs zauzet.
MOV AL,1
L1:
XCHG AL,SEMA
CMP AL,0
JNE L1
Ako se na ovakav način realizuje čekanje sve dok kritični resurs ne bude dostupan i njegovo zauzimanje kada postane dostupan, tada se nedeljiva sekvenca operacija realizuje samo jednom XCHG instrukcijom.
Na nesreću, iako se u prethodnom primeru koraci provere dostupnosti i eventualnog signaliziranja zauzetosti izvršavaju jednom naredbom, hardver ih ne izvršava simultano, tako da između operacije čitanja i upisa postoji kratak vremenski period, tokom koga izvršavanje ove instrukcije može biti prekinuto.
Problem je rešen na hardverskom nivou sa izlaznim pinom (eng. pin - iglica) na procesoru 80386 koji se naziva lock pin (eng. lock - zaključavanje), ili pin zaključavanja. Taj pin zaključavanja šalje signal za vrijeme trajanja XCHG instrukcije. Na taj način se može dati ekskluzivan memorijski pristup na kom procesoru koji je poslao signal zaključivanja.
Pitanje je koliko se često treba slati signal zaključavanja? Ako bi uz svaku instrukciju imao signal zaključavanja, to bi degradiralo performanse sistema toliko mnogo da bi se sva prednost postojanja više od jednog procesora izgubila.
Zbog toga se dopušta programska kontrola nad pinom zaključavanja, eventualnim postavljanjem prefiksa instrukcije LOCK. Instrukcija koja ima prefiks LOCK će izazvati da pin zaključavanja bude aktiviran za vreme trajanja instrukcije.
U sljedećem poglavlju će biti opisani primeri korišćenja LOCK prefiksa pri manipulaciji bitovima.
Još treba napomenuti da LOCK prefiks nije neophodan kod XCHG instrukcije, zato što procesor 80386 automatski aktivira pin zaključavanja kod svih XCHG instrukcija koje uključuju memorijski operand.
Ove instrukcije postoje tek kod procesora 80386 i njegovih sljedbenika. Instrukcije su dizajnirane za obezbeđenje kompletnih mogućnosti za manipulaciju nizovima pojedinačnih bitova.
Opet se postavlja pitanje: “[ta će nam sve to? ^emu bi (korisnom) takve instrukcije služile? Zar te instrukcije, odnosno njihovo uvođenje, nisu u suprotnosti sa pravcem razvoja familije procesora 80x86? Jer, 32-bitne mašine su dizajnirane za manipulisanje većim skupinama podataka, a ne manjim.”
Posmatranjem razvoja računara, uočavaju se dva glavna razloga koja određuju značaj razvoja instrukcija za manipulaciju sa bitovima:
1) Razvoj memorijskih uređaja je učinio mogućim da računar manipuliše sa audio i video zapisima. Za razliku od numeričkih i tekstovnih podataka, slika se teško može smisleno orgnizovati u blokove slogova koji sadrže više bitova. Sposobnost adresiranja individualnih bitova je, dakle, od vitalne važnosti za laku i brzu manipulaciju sa ovakvim podacima.
2) Uvećana snaga jezika visokog nivoa je napravila poželjnom bit manipulaciju koda generisanog od strane kompajlera. Najveći broj kompajlera je prisiljen da za svaki elemenat logičkog niza rezerviše ceo bajt. Direktno adresiranje bitova omogućava prevodiocu da spakuje logički niz (niz logičkih objekata) sa maksimalnom preciznošću.
Da bi se ovo moglo postići, potrebne su nam instrukcije za čitanje i upis individualnih bitova, za pretragu kroz niz bitova i za premeštanje bitovnog niza.
Nadalje se koristi sledeća konvencija za adresiranje bitova:
31 |
16 |
15 |
8 |
7 |
0 |
|
|
|
|
tj bit najmanje težine ima adresu 0, sljedeći bit adresu 1 itd. bit najveće težine u bajtu ima adresu 7, u reči 15, a u dvostrukoj reči 31.
Postoje samo 4 načina na koji se može manipulisati sa pojedinačnim bitom:
1) Postavljanje - vrednost postaje 1
2) Brisanje - vrednost postaje 0
3) Komplementiranje
4) Ostavljanje u nepromijenjenoj vrijednosti.
Svaka od ovih manipulacija sa bitom se obavlja tačno jednom od sledećih instrukcija:
BTS D, S (eng. bit set - postavi bit) - DS®CF, 1®DS, tj. bit odredišta D čija je adresa specificirana sa S se postavlja na 1, a stara vrednost tog bita smešta se u CF.
BTR D, S (eng. bit reset - obriši bit) - DS®CF, 0®DS, tj. bit odredišta D čija je adresa specificirana sa S se postavlja na 0, a stara vrednost tog bita smešta se u CF.
BTC D, S (eng. bit complement - komplementiraj bit) - DS®CF, 1-DS®DS, tj. komplementira se bit odredišta D čija je adresa specificirana sa S, a stara vrednost tog bita smešta se u CF.
BT D, S (eng. bit - bit) - DS®CF, tj. bit odredišta D čija je adresa specificirana sa S se smešta bit u CF
Svaka od ovih instrukcija ima dva operanda: prvi je reč ili dvostruka reč koja sadrži bit koji se čita i sa kojim se manipuliše. Drugi operand sadrži adresu bita unutar reči ili dvostruke reči. Adresa može biti neposredna vrednost, ili može biti sadržaj registra.
Primer.
Efekat dejstva instrukcije
BTC AX,2
(pri čemu je najniža četvorka AX-a tj. posljednja heksa cifra u AX-u 1111) se svodi na promjenu te četvorke u 1011, pri čemu će CF biti postavljen na 1.
Primećuje se da kada bit dođe u registar, bitovna adresa ne može preći adresu bita najveće težine u registru. Ovakva restrikcija ne bi smjela postojati u slučaju kada bitovi dolaze iz memorije. Međutim, nije tako.
Primer.
Promena bita na adresi 100 realizuje kao pomjeranje za 12 bajova (12*8=96) pa se promieni peti bit u trinaestom bajtu od početka - već je istaknuto da numeracija bitova počinje od 0.
Primer.
Ovo korišćenje bitovnog testiranja uključuje nizove semafora u rad sa semaforom. Segment programskog koda na asemblerskom jeziku obavlja isti rad sa semaforom kao i prethodni primjer koji je radio sa semaforom (s tim što se čita EAX-ta pozicija bita u lokaciji SEMA, koji sadrži niz semafora):
L1: ;neka se petlja postavi sve dok semafor postavi na 0
LOCK BTS SEMA,EAX ;cita se bit u CF, a ovaj postavi na 1
JC L1 ;ako je bit vec bio 1, ostaje se u petlji
^esto je od interesa tražiti specificiranu vrijednost bita kroz bitovni niz, jer se bitovni niz koristi za indikaciju alokacija resursa.
Primer.
Preko logičkog tj. bitovnog niza se može realizovati određivanje koji su sektori na disku slobodni: ako je sektor N slobodan, onda će N-ti bit u bitovnom nizu biti biti 1, inače će biti 0.
Tako, ako operativni sistem treba da alocira sektor, mora naći bit 1 u logičkom nizu.
Vrlo brzo se može naći dvostruka riječ koja sadrrži bar jedan bit postavljen na 1 - sa REPZ SCASD. Još samo treba da se brže odredi bit u nađenoj dvostrukoj reči - pri čemu se dvostruka reč može čitati odnapred ili odpozadi.
BSF D, S (eng. bit scan forward - skeniranje bitova unapred) - pozicija ne nula bita najmanje težine u S ®D.
BSR D, S (eng. bit scan reverse - skeniranje bitova unazad) pozicija ne nula bita najveće težine u S ®D.
Obe ove instrukcije zahtevaju da prvi operand bude registarski.
Primer.
Neka se bitovni niz zove MAPA_SEKT, a broj bitova u mapi je neposredna konstanta BR_SEKT. Da bi se uprostio problem, pretpostaviće se da MAPA_SEKT zauzima ceo broj dvostrukih riječi. Sljedeći segment programa određuje broj slobodnog sektora, vraće tu vrijednost u EAX i markira taj sektor kao zauzet.
MOV EDI, MAPA_SEKT ;pokazi na bitovni niz sektora
MOV ECX, BR_SEKT/32 ;unesi broj dvostrukih reci sektora
SUB EAX, EAX ;obrazac za uporedjivanje je dvostruka rec ispunjena 0
REPZ SCASD ;nadji ne nula dvostruku rec u nizu
JZ greska ;ako su sve dvostruke reci 0, radi se o gresci
BSF EAX,[EDI-1] ;odredi adresu prvog bita u nenula dvostrukoj reci
SUB EDI, MAPA_SEKT+1 ;izracunaj broj preskocenih dvostrukih reci
SHL EDI, 5 ;i konvertuj taj broj u broj preskocenih bitova
ADD EDX, EDI ;dodaj broj preskocenih bitova na bitovnu adresu
BTR MAPA_SEKT, EAX
greska:
Primer.
Neki primeri korišćenja prethodnih instrukcija:
BSF AX, BX ;postavlja AX na poziciju najnize jedinice u BX-u
BSF CX, M_W ;postavlja CX na poziciju najnize jedinice u reci M_W u memoriji
BSR EBX, EAX ;postavlja EBX na poziciju najvise jedinice u EAX-u
BSR EDX, M_DW ;postavlja EDX na poziciju najvise jedinice u dvostrukoj reci M_DW
Razmotrimo za početak probleme koji odgovaraju bit- mapiranim vizuelnim slikama. Da bi se implementirale osobine kao što su proporcionalno širenje (tj. razmicanje) mora posojati mogućnost da npr. bit najmanje težine u dvostrukoj reči-izvoru prekopiramo u bit na poziciji 10 dvostruke reči - odredišta, pa sve tako do kraja.
Lako se uočava, za konkretan slučaj, da se svaka dvostruka reč u odredišnoj niski (stringu), sem prve i poslednje, sastoji od 10 bitova izvorne dvostruke reči i 22 bita sljedeće izvorne dvostruke riječi. Tako, podaci dolaze iz dve dvostruke reči (tj. dužina izvora je 64 bita).
Instrukcije pomeranja i rotacije koje su dosad opisane rade nad podacima od maksimalno 32-bita.
Procesor 80386 poseduje dve instrukcije specijalne namene, za 64-bitovno pomeranje:
SHLD D, H, S (eng. shift logical left double precision - pomeri logički ulevo dvostruko precizno) CF ¬ D ¬ H. Realizuje pomeranje odredišnog operanda za izvorom određen broj pozicija ulevo. Na mesta koja su “ispražnjena” prilikom pomeranja ulevo, smeštaju se niži (tj. donji) bitovi središnjeg operanda.
SHRD D, H, S (eng. shift logical right double precision - pomeri logički udesno dvostruko precizno) H ® D ® CF. Realizuje šiftovanje odredišnog operanda za izvorom određen broj pozicija udesno. Na mesta koja su “ispražnjena” prilikom pomeranja udesno, smeštaju se viši bitovi (tj. gornji bitovi ili bitovi veće težine) središnjeg operanda.
Ove dve instrukcije, dakle, imaju tri operanda. Prvi i poslednji su isti kao kod “normalnih” instrukcija pomjeranja: ukazuju na onaj registar (ili memorijsku lokaciju) nad kojim se vrši pomeranje i na to za koliko se mjesta pomjeranje izvršava. Razlika je u tome što SHLD i SHRD, za razliku od SHL i SHD koje ubacuju nule, na nova mesta ubacuju bitove iz srednjeg operanda. Pritom srednji operand izvršenjem ove instrukcije ne biva promenjen.
Primer.
Instrukcija
SHRD EAX, EBX, 10
pomera sadržaje EAX registra za deset mesta udesno, pri čemu se gornjih deset bitova registra EAX puni iz deset najnižih bitova registra EBX. Po izvršetku instrukcije će registar EBX ostati nepromenjen.
Potpuno analogno kao kod instrukcija pomeranja i rotacije, treći operand, tj. broj pozicija za koje se vrši pomeranje može biti dat bilo neposredno, bilo kao sadržaj registra CL.
Primer.
Da bi se ilustrovalo korišćenje instrukcija SHLD i SHRD, neka se posmatra rutina koja izvršava pomeranje blokova bitova. Neka se izvorni blok bitova sastoji od (E)DX dvostrukih reči, na koje pokazuje (E)SI. Radi jednostavnosti, pretpostavićemo da se izvor sastoji od celog broja dvostrukih reči, poravnatih tako da počinju od bita 0 izvora. Odredište počinje od CH-tog bita dvostruke reči na koju pokazuje (E)DI.
Premeštanje se prikazuje sledećom shemom:
|
0 31 |
0 31 |
0 31 |
0 31 |
|
|||||||||
(E)SI® |
|
|
|
|
|
|||||||||
|
Ż Ż |
Ż Ż |
Ż Ż |
Ż Ż |
|
|||||||||
|
|
0 |
31 |
0 31 |
0 31 |
0 31 |
0 |
31 |
||||||
|
(E)SI® |
|
|
|
|
|
|
|
||||||
Kod kojim se realizuje premeštanje sastojaće se iz tri dela: deo za prenos u prvu dvostruku reč, deo za prenos srednjih dvostrukih reči i deo za prenos u sledeću dvostruku reč.
Kod je sledećeg oblika:
MOV CL, 32
SUB CL, CH ;racunamo 32-CH - za toliko se vrsi pomeranje
MOV EAX, [EDI] ;dohvati prvu rec sa odredista
ROL EAX, CL ;pomeri donjih CH bitova na vrh - kod u petlji ce ih ponovo vratiti na dno
L1:
MOV EBX, [ESI] ;dohvati dvostruku rec sa izvora
ADD SI, 4 ;uvecaj pokazivac na dvostruke reci sa izvora
SHRD EAX, EBX, CL ;pomeri nanize CL bitova iz te i sledece reci
STOSD ;smesti dobijeni rezultat
MOV EAX, EBX ;sledeca izvorna rec postaje aktuelna
DEC EDX ;umanji broj dvostrukih reci
JNZ L1
MOV CL, CH ;CL se koristi za oformljenje poslednje reci odredista
SHR DWORD PTR [EDI], CL ;pomeri 32-CH bitova na dno - kako bi sledecom instrukcijom bili vraceni
SHLD [EDI], EAX, CL ;pomeri bitove iz poslednje dvostruke reci izvora
Napomena.
U prethodnom primeru nije korišćena instrukcija LODS (tj. LODSD) zato što je dvostruka reč sa izvora trebala da se smesti u EBX, a ne u EAX. Ipak, umesto
MOV EBX, [ESI]
ADD SI, 4
moglo se napisati:
XCHG EAX, EBX
LODSD
XCHG EBX, EAX
Kao što je već istaknuto, instrukcije SHLD i SHRD su uključene kako bi se obezbedilo 64-bitovno pomeranje, i skoro uvek su argumenti, tj. operandi, dvostruke reči. Međutim, zbog potpune simetrije između reči i dvostrukih reči kod procesora 80386, mnemonici SHLD i SHRD prihvataju i 16-bitne operande. Nataj način se dobija egzotičnija forma 32-bitnog pomeranja. Kod ovih instrukcija operandi ne mogu biti dužine 8.
Primer.
Neki od načina korišćenja instrukcija SHLD i SHRD:
SHLD AX, BX, 3 ;gornja rec od AX BX SHL 3 ® AX
SHRD AX, BX, 3 ;donja rec od BX AX SHR 3 ® AX
SHLD M_W, DX, 9 ;gornja rec od M_W DX SHL 9 ® M_W
SHRD M_W, DX, 9 ;donja rec od DX M_W SHR 9 ® M_W
SHLD ECX, EDX, 23 ;gornja dvostruka rec od ECX EAX SHL 23 ® ECX
SHRD M_DW, EAX, 2 ;donja dvostruka rec od EAX M_DW SHR 2 ® M_DW
Postoji ukupno pet prefiksa instrukcija: REP, LOCK, prefiks veličine operanda, prefiks adresne dužine i prefiks označavanja segmenta. U ovom poglavlju će biti govora isljučivo o prefiksima REP i LOCK.
REP prefiks je valjan samo za string primitive.
LOCK prefiks je valjan samo za instrukcije koje čitaju i upisuju u istu memorijsku lokaciju. Sledeća tabela prikazuje valjane forme instrukcija za LOCK prefiks.
Valjane forme instrukcija za LOCK |
||
ADD mem, reg |
ADD mem, nep |
DEC mem |
ADC mem, reg |
ADC mem, nep |
INC mem |
AND mem, reg |
AND mem, nep |
NEG mem |
OR mem, reg |
OR mem, nep |
NOT mem |
SBB mem, reg |
SBB mem, nep |
XCHG reg, mem |
SUB mem, reg |
SUB mem, nep |
XCHG mem, reg |
XOR mem, reg |
XOR mem, nep |
|
BT mem, reg |
BT mem, nep |
|
BTR mem, reg |
BTR mem, nep |
|
BTS mem, reg |
BTS mem, nep |
|
BTC mem, reg |
BTC mem, nep |
|
Ukoliko se neki od ova dva prefiksa koristi sa neodgovarajućom instrukcijom, tada dolazi do prekida tipa 6, tj. do invalidnog operacionog koda (eng. invalid opcode exception - izuzetak invalidnog opkoda).
Kako prefiksi REP i LOCK imaju disjunktne skupove instrukcija za koje su valjani, jasno je da se ta dva prefiksa ne mogu istovremeno primeniti.
Ukoliko se prekid prinudi da čeka, (jer prekidi se obično izvršavaju između instrukcija) sve dok se u potpunosti ne izvrši neka string primitiva sa prefiksom ponavljanja, to može da traje isuviše dugo. Stoga je procesor dizajniran tako da dopušta opsluživanje prekida poosle nekog broja ponavljanja repetirajuće string-primitive, a pre njenog kraja. Po opsluženju prekida će se ta repetirajuća instrukcija ponovo izvršiti.
U tabelama koje slede biće opisano postavljanje statusnih flegova: OF, CF, AF, SF, ZF, PF i nekih od kontrolnih flegova: DF, IF, TF.
Instrukcija |
OF |
CF |
AF |
SF |
ZF |
PF |
ADD ADC SUB SBB |
+ |
+ |
+ |
+ |
+ |
+ |
CMP NEG CMPS SCAS |
+ |
+ |
+ |
+ |
+ |
+ |
INC DEC |
+ |
- |
+ |
+ |
+ |
+ |
MUL IMUL |
+ |
+ |
? |
? |
? |
? |
DIV IDIV |
? |
? |
? |
? |
? |
? |
DAA DAS |
? |
+ |
+ |
+ |
+ |
+ |
AAA AAS |
? |
+ |
+ |
? |
? |
? |
AAM AAD |
? |
? |
? |
+ |
+ |
+ |
AND OR XOR TEST |
0 |
0 |
? |
+ |
+ |
+ |
SHL SHR (jedinično) |
+ |
+ |
? |
+ |
+ |
+ |
SHL SHR (promenljivo) |
? |
+ |
? |
+ |
+ |
+ |
SAR |
+ |
+ |
- |
- |
- |
- |
ROL ROR RCL RCR (jedinično) |
+ |
+ |
- |
- |
- |
- |
ROL ROR RCL RCR (promenljivo) |
? |
+ |
- |
- |
- |
- |
POPF POPFD IRET IRETD |
+ |
+ |
+ |
+ |
+ |
+ |
SAHF |
- |
+ |
+ |
+ |
+ |
+ |
CLC |
- |
0 |
- |
- |
- |
- |
STC |
- |
1 |
- |
- |
- |
- |
CMC |
- |
* |
- |
- |
- |
- |
BT BTS BTR BTC |
- |
+ |
- |
- |
- |
- |
BSF BSR |
- |
- |
- |
- |
+ |
- |
SHLD SHRD |
? |
+ |
? |
- |
- |
- |
Legenda.
|
+ |
pogađa tj. utiče |
1 |
postavlja (vrednost postaje 1) |
||||
|
- |
ne pogađa tj. ne utiče; |
0 |
briše (vrednost postaje 0) |
||||
|
? |
nedefinisan |
* |
komplementira |
||||
Instrukcija |
DF |
IF |
TF |
|
||||
POPF POPFD IRET IRETD |
+ |
+ |
+ |
|
||||
INT INTO |
- |
0 |
0 |
|
||||
STD |
1 |
- |
- |
|
||||
CLD |
0 |
- |
- |
|
||||
STI |
- |
1 |
- |
|
||||
CLI |
- |
0 |
- |
|
||||
Napomena.
Instrukcije inkrementiranja i dekrementiranja ne utiču na CF (što se i vidi iz tabele u kojoj je opisano postavljanje statusnih flegova). Ta činjenica omogućava da se petljom (čiji opis sledi) izvrši aritmetička operacija nad dugim brojevima:
1. postavi ESI na
bajt anajmanje težine u prvom operandu
2. postavi EDI na
bajt anajmanje težine u drugom operandu
3. obriši fleg
prenosa CF
4. izvrši ADC između
bajta na koji pokazuje EDI i bajta na koji pokazuje ESI
5. inkrementiraj
ESI tako da pokazuje na sledeći bajt prvog operanda
6. inkrementiraj
EDI tako da pokazuje na sledeći bajt drugog operanda
7. sve dok ima još
bajtova, vraćaj se na korak 4
Primećuje se da, ukoliko bi INC instrukcija u koracima 5. i 6. bila zamenjena sa instrukcijom sabiranja, ta instrukcija bi delovala na CF, pa sabiranje u koraku 4 ne bi nužno dalo korektan rezultat.
Pseudoinstrukcije i pseudooperacije figurišu u asemblerskim programima, ali nisu prave instrukcije procesora, što se lako može uočiti uporednim pregledom asemblerskog koda i odgovarajućeg objektnog koda. Kako neke od pseudoinstrukcija faktički ukazuju asembleru i linkeru kako da se izvrši kreiranje izvršnog koda, to se pseudoinstrukcije ponekad nazivaju i direktivama.
Asembler MASM dopušta da program saopšti linkeru na koji način će biti alociran memorijski prostor u finalnom izvršnom programu.
To se postiže pseudoinstrukcijom SEGMENT. Ova pseudoinstrukcija omogućava kreiranje segmentiranog programa.
<ime segmenta> SEGMENT [ <tip poravnanja>][<tip kombinovanja>][ <ime klase>] (eng segment - isečak) - saopštava asembleru da otpočinje novi segment.
Parametar za određivanje tipa poravnanja može biti PARA, PAGE, WORD ili BYTE i određuje na kakvu će vrstu granice u memoriji linker smestiti početak segmenta.
Tipovi poravnanja omogućavaju da se prevaziđu ograničenja zasnovana na segmentiranoj memoriji.
Tip poravnanja |
Efekat |
Adresa |
PARA |
PARA segment mora počinjati na granici pargrafa, tj. adresa početka segmenta mora biti daljiva sa 16D (ovo je podrazumevano poravnanje). |
xxxx0H |
PAGE |
PAGE segment mora počinjati na granici strane, tj. adresa početka segmenta mora biti daljiva sa 256D. |
xxx00H |
WORD |
WORD segment počinje na granici reči, tj. na parnim adresama. |
xxxxYH |
BYTE |
BYTE segment može početi bilo gde. |
xxxxxH |
Pseudoinstrukcija SEGMENT može biti praćena sa još dve opcione vrednosti, koje određuju vrstu kombinovanja segmenata i ime klase.
Jedan segment može biti kombinovan sa drugim segmentima u istom modulu i/ili sa segmentima koji su definisani u drugim modulima. Kada se iskombinuju, ti segmenti će obrazovati jedan fizički segment koji se smešta u memoriju i na koji ukazuju segmentni registri krajnjeg izvršnog programa. Tip kombinovanja (onda kada postoji) može biti: PUBLIC, STACK, COMMON, MEMORY, AT.
Sledeća tabela sumarno prikazuje tipove kombinovanja:
Način kombinovanja |
Efekat |
ne postoji |
Segmenti se ne kombinuju (ovo je podrazumevano kombinovanje). |
PUBLIC |
Svi PUBLIC segmenti sa istim imenom se pri linkovanju spajaju u jedan fizički segment (nadodajući se jedan na drugi). |
STACK |
Svi STACK segmenti sa istim imenom tretiraju se kao da su PUBLIC. Linker zahteva da postoji bar jedan STACK segment. Pokazivač steka (E)SP se inicijalizuje na dužinu segmenta. Segmentni registar SS se automatski postavlja. |
COMMON |
Svi COMMON segmenti sa istim imenom počinju od iste fizičke adrese i na taj način zauzimaju zajednički prostor. Dužina COMMON segmenta biće jednaka daužini najvećeg među COMMON segmentima. |
MEMORY |
MEMORY segment se smešta u memoriju u adresama višim od ostalih segmenata. Ako nekoliko segmenata ima tip kombinovanja MEMORY i zajedno su linkovani, tada prvi na koji se pri linkovanju naišlo se smatra takvim, dok se sa ostalim radi kao sa COMMON segmentima. |
AT <izraz> |
Segment je smešten na poziciju čija je apsolutna segmentna adresa zadata izrazom |
Sledeća slika predstavlja ilustraciju prethodno prikazanih tipova kombinovanja:
Pre kombinovanja od strsna linkera |
|
Posle kombinovanja od strane linkera |
|
Prvatni segmenti |
|
|
PUBLIC STACK |
|
|
COMMON MEMORY |
|
Parametar ime klase sastoji se od imena uokvirenog apsotrofima (npr. ‘TIMER’). Kada se iz individualnog modula konstruiše izvšni program, linker će zajedno grupisati segmente sa istom vrednošću parametra ime klase, tako da će ti segmenti zauzeti lokacije u kontinuitetu. Segmenti će, unutar dela memorije koji je dodeljen klasi, biti smešteni onim redom kako na njih nailazi linker tokom povezivanja.
Tako, svim programskim segmentima se može dati klasno ime ‘CODE’, dok se klasno ime ‘DATA’ može dati svim segmentima podataka, a klasno ime ‘STACK’ svim stek-segmentima u raznovrsnim modulima, u zavisnosti da li tip kombinacije omogućava da to ima smisla.
Primer.
Sledeći segment ima klasno ime OURDATA:
DATA SEGMENT ‘OURDATA’
Napomena.
Pseudoinstrukcija SEGMENT može uključiti ma koju kombinaciju tipova poravnanja, tipova kombinovanja i parametara imena klase. Uobičajeno je da redosled bude kao u sledećem kodu:
MY_SEGMENT SEGMENT PARA COMMON ‘VIDEO’
MY_SEG SEGMENT AT 3CB0H ‘DISPLAY’
CODE SEGMENT BYTE ‘EXAMPLE’
Ova pseudoinstrukcija dopušta programeru da instruiše linker kako bi ovaj sakupio listu segmenata koji će se naći u jednom fizičkom segmentu. Pri tome asembler ne proverava da li je suma veličina segmenata u grupi prevazišla limit koji predstavlja veličina fizičkog segmenta.
<ime grupe> GROUP <ime segmenta>{ <ime segmenta>} (eng group - grupa) - saopštava asembleru da koji se sve segmenti sadrže u grupi.
Primer.
Neka jedan od modula sadrži sledeći kod:
SMALL_MEMEORY GROUP CODESEG1, CODESEG2
CODESEG1 SEGMENT
ASSUME CS:SMALL_MEMEORY
.
.
.
CODESEG1 ENDS
CODESEG2 SEGMENT
ASSUME CS:SMALL_MEMEORY
.
.
.
CODESEG2 ENDS
END
Neka se, istovremeno, u drugom modulu nalazi sledeći kod:
SMALL_MEMEORY GROUP OTHER_MODULE_SEG
OTHER_MODULE_SEG SEGMENT
ASSUME CS:SMALL_MEMEORY
.
.
.
OTHER_MODULE_SEG ENDS
END
Na ovaj način su sva tri segmenta skupljena u isti fizički prostor, a pod imenom SMALL_MEMORY. Kad je jednom na ovaj način definisana grupa, njeno ime može biti korišćeno kao bilo koje drugo ime segmenta.
Memorijski objekti (promenljive i labele) imaju tri atributa: segment, offset i tip. Operatori iz ove grupe za odgovarajući memorijski objekat vraću vrednost njegovog atributra
SEG <memoriski objekat> (eng. segment - isečak) - vraća ceo 16-bitni broj koji predstavlja segmentnu adresu memorijskog objekta.
Primer.
Instrukcija
MOV BX, SEG RUN_ERR
će pri asembliranju biti prevedena u instrukciju ekvivalentnu sa
MOV BX, n
gde je n broj tj. fikirana vrednost - segmentna adresa promenljive RUN_ERR.
OFFSET <memoriski objekat> (eng. offset - pomeraj) - vraća ceo broj koji predstavlja broj bajtova između memorijskog objekta i početka segmenta u kom je definisan taj objekat.
TYPE <memoriski objekat> (eng. type - tip) - vraća broj bajtova koje zauzima podatak na koji se u instrukciji referiše.
Primer.
Neka asemblerski kod sadrži sledeće pseudoinstrukcije i instrukcije:
NEW_CENT DW 2000D
MOV AX, TYPE NEW_CENT
Poslednja (i jedina) instrukcija će pri asembliranju biti prevedana u instrukciju ekvivalentnu instrukciji
MOV AX, 2
Napomena.
Jasno se uočava neophodnost da asembler, tokom svog rada, odredi segmentnu adresu, offset i tip memoriskog objekta koji figuriše u asemblerskom programu. Dakle, te veličine su konstante sa stanovišta asemblera i to pre nego što asembller pristupi generisanju koda.
Ovi operatori dopuštaju programeru da izbegne računanje broja bajtova koje zauzima dugačka ili složena struktura podataka. Preciznije rečeno, to računanje se prepušta asembleru.
LENGTH <memoriski objekat> (eng. length - dužina) - vraća broj podobjekata koje obuhvata komplekan objekat na koji se u instrukciji referiše.
Korišćenjem ovih operatora se smanjuje obim izračunavanja tokom rada programa, čime je smanjena mogućnost greške. Na ovaj način takođe se smanjuje i zavisnost instrukcija programa od konkretnih konstanti.
Primer.
Ako je:
SA DB 80H DUP(0)
DA DW 100H DUP(1924D)
Pri asembliranju instrukcija:
MOV AX, LENGTH SA
MOV BX, LENGTH DA
biće dobijen objekt kod koji sadrži instrukcije ekvivalentne sa:
MOV AX, 80H
MOV BX, 100H
Ukoliko je, iz nekih razloga, potrebno imatis veći niz SA, tada se pseudooperacija DB može promeniti, a da to uopšte ne utiče na izmene u kodu za instrukciju MOV AX, LENGTH SA.
Primer.
Sledeći fragment programa realizuje kopiranje niska ASTRING u nisku BSTRING.
MOV SI, OFFSET ASTRING
MOV DI OFFSET BSTRING
MOV CX LENGTH ASTRING
CLD
REP MOVSB
SIZE <memoriski objekat> (eng. size - veličina) - vraća proizvod operatora LENGTH i TYPE, tj. broj bajtova koje zauzima komplekan objekat.
Primer.
Instrukcije
MOV AX, SIZE SA
MOV BX, SIZE DA
će biti asemblirane u objekt kod ekvivalentan sa instrukcijama
MOV AX, 80H
MOV BX, 200H
Ipak, korišćenje ovih pseudooperatora ne sme biti univerzalno.
Primer.
Ako je:
TEST_VALUES DB 2,4,6,8,0AH, 0CH, 0EH
MOV AX, LENGTH TEST_VALUES
MOV BX, TYPE TEST_VALUES
MOV CX, SIZE TEST_VALUES
poslednje tri instrukcije će biti asemblirane kao
MOV AX, 1
MOV BX, 1
MOV CX, 1
jer ime TEST_VALUES u ovom slučaju referiše samo na prvi definišući bajt.
Neka treba izračunati vrednost izraza u kom figurišu isključivo konstantne vrednosti (nijedan od operanada u izrazu nije promenljiv).
Primer.
Neka treba izračunati vrednost izraza (40*32*15)/6, jer on npr. predstavlja indeks traženog člana niza. Asebler dopušta da se ovakav izraz javi kao operand instrukcije i na taj način programer biva pošteđen izračunavanja njegove vrednosti. Stoga je sasvim korektna sledeća instrukcija:
MOV CX, (40D*32D*15D)/6D
Ta instrukcija će biti asemblirana u ekvivalent
MOX CX, 0B6H
tj. u instrukciju
MOV CX, 3200D
U aritmetičke operatore spadaju:
HIGH <operand> (eng. high - visok) - vraća gornji bajt reči operanda.
LOW <operand> (eng. low - nizak) - vraća donji bajt reči operanda.
<operand 1> * <operand 2> - računa proizvod operanada.
<operand 1> / <operand 2> - računa celobrojni količnik operanada.
<operand 1> MOD <operand 2> - računa ostatak pri deljenju prvog operanda sa drugim.
<operand 1> SHL <operand 2> - računa prvi operand šiftovan ulevo za onoliko bitova kolika je vrednost drugog operanda.
<operand 1> SHR <operand 2> - računa prvi operand šiftovan udesno za onoliko bitova kolika je vrednost drugog operanda.
<operand 1> + <operand 2> - računa zbir operanada.
<operand 1> - <operand 2> - računa razliku operanada.
+ <operand> - potvrđuje znak operanada.
- <operand> - menja znak operanada.
Primer.
Ilustruje korišćenje aritmetičkih operatora kod asemblerskih instrukcija:
MOV AL, LOW(0ABC1H)
CMP DX, (132*15)/3 MOD 4
CMP AH, 14H SHR 6
MOV AL, RECORD_START+2
Primer.
Instrukcije
MOV AX, 100H MOD 17D
MOV BX, 0EFH SHL 2
će pri asembliranju biti prevedene u isti kod kao instrukcije
MOV AX, 1
MOV BX, 0BCH
Binarna relacija je neki podskup direktnog proizvoda dva skupa. Dakle, za svaki par elemenata se može utvrditi da li su oni u relaciji (odgovor je tada true) ili nisu (odgovor je false). Kod relacionih operatora u asemblerskom jeziku, logička konstanta true je predstavljena binarnim brojem koji se sastoji isključivo od jedinica, dok je logička knstanta false predstavljena nulom.
Relacioni operatori su:
<operand 1> EQ <operand 2> (eng. equal - jednako) - određuje da li su operandi međusobno jednaki.
<operand 1> NE <operand 2> (eng. not equal - različito) - određuje da li su operandi međusobno različiti.
<operand 1> LT <operand 2> (eng. less than - manji od) - određuje da li je prvi operand manji od drugog.
<operand 1> LE <operand 2> (eng. less than or equal- manji ili jednak sa) - određuje da li je prvi operand manji ili jednak sa drugim.
<operand 1> GT <operand 2> (eng. greater than - veći od) - određuje da li je prvi operand veći od drugog.
<operand 1> GE <operand 2> (eng. greater than or equal- veći ili jednak sa) - određuje da li je prvi operand veći ili jednak sa drugim.
Primer.
Instrukcije
MOV AL, 16 LT 17
MOV DL, 5EH GT 6EH
su ekvivalentne sa:
MOV
MOV DL, 0
Asembler MASM dopušta da izrazi sadrže operatore NOT, AND, OR i XOR. Značenje ovih operatora je isto kao značenje odgovarajućih bitovnih logičkih instrukcija.
Dakle,
<operand 1> AND <operand 2> (eng. and - i) - izračunava se bitovna konjukcija operanada.
<operand 1> OR <operand 2> (eng. or - ili) - izračunava se bitovna disjunkcija operanada.
<operand 1> XOR <operand 2> (eng. exclusive or - ekskluzivno ili) - izračunava se bitovna ekskluzivna disjunkcija operanada.
NOT <operand> (eng. not - ne) - izračunava se bitovna negacija operanda.
Primer.
Instrukcije:
MOV DL, 3EH OR 0FEH
MOV BH, NOT 15H
MOV CL, 22H AND OABH
su ekvivalentne sa:
MOV DL, 0FEH
MOV BH, 0EAH
MOV CL, 22H
Napomena.
U instrukcijama i izrazima je moguće kombinovati raznovrsne operatore:
CO_ORD_ADR DW OFFSET MY_LOC+(22H*2)
U ovu grupu pseudooperatora spadaju PTR, SHORT i THIS. Svaki od ovih operatora dopušta da postojeća definicija podataka bude na neki način prevaziđena.
Pored ovih operatora, u istoj grupi se nalazi još i segmentni prefiks.
<tip> PTR <operand> (eng. pointer - pokazivač) - dopušta da se komponente operanda tretiraju u skladu sa tipom - kao reči, bajtovi, dvostruke reči.
Primer.
Dvosmislenost kao kod instrukcije:
INC [BX]
može biti prevaziđena na sledeći način:
INC WORD PTR [BX]
Primer.
Instrukcija u asemblerskom kodu:
MY_WORD DW 4142H
.
.
.
MOV AX, BYTE PTR MY_WORD
će biti asemblirana u ekvivalent od
MOV AX, 41H
Primer.
Korićenje operatora PTR kod skokova:
NEAR_LOOP:
ADD AX, BX
MOV DX, AX
.
.
.
JMP NEAR_LOOP
.
.
.
FAR_LOOP EQU FAR PTR NEAR_LOOP
JMP FAR_LOOP
THIS <tip> (eng. this - ovo) - dopušta da dva podatka definisana pseudooperacijama tako da zauzimaju uzastopne bajtove budu tumačeni u skladu sa tipom.
Operator THIS mora biti praćen tipom, tj. jednom od reči BYTE, WORD, DWORD, FWORD, QWORD, TBYTE, NEAR, FAR, PROC.
Primer.
Ilustruje kako se može dopustiti pristup sadržaju uzastopnih lokacija FIRST_BYTE i SECOND_BYTE i kako se one mogu tretirati kao jedna reč:
AB_WORD EQU THIS WORD
FIRST_BYTE DB 41H
SECOND_BYTE DB 42H
Primer.
Ilustruje kako se mogu oformiti alternativne labele za iste adrese, od kojih je jedna NEAR, a druga FAR:
FAR_LOOP EQU THIS FAR
NEAR_LOOP:
ADD AX, 2
SHORT <odredište> (eng. short - kratak) - zahteva da odredište skoka bude enkodirano u kratkoj formi.
Jasno je da operator SHORT mora biti praćen valjanim imenom labele. Neophodno je i da ta labela bude u istom segmentu gde se nalazi i instrukcija u kojoj figuriše ovaj operator.
Primer.
Instrukcija
JMP SHORT NEXT_BLOCK_LABEL
je dopuštena samo ako je labela NEXT_BLOCK_LABEL u istom segmentu u kom je i instrukcija JMP.
<segmentni registar>: - segmentni prefiks omogućuje prevazilaženje segmenata, pa se podacima koji se nalaze u jedno segmentu može pristupiti i iz drugih segmenata.
Primer.
Instrukcija
MOV AL, ES:A_BYTE
će biti asemblirana tako
da se sadržaj
U ovu grupu spadaju: LABEL, DB, DW, DD, DQ, DT, EQU, =
<ime> LABEL <tip> (eng. label - naziv) - definiše labelu.
Primer.
Ilustruje kako se može dopustiti pristup sadržaju uzastopnih lokacija FIRST_BYTE i SECOND_BYTE i kako se one mogu tretirati kao jedna reč:
AB_WORD LABEL WORD
FIRST_BYTE DB 41H
SECOND_BYTE DB 42H
Primer.
Ilustruje kako se niz reči po potrebi može posmatrati i kao niz bajtova:
ARRAYB LABEL BYTE
ARRAYW DW 100 DUP(?)
.
.
.
ADD AL, ARRAYB[99]
ADD AX, ARRAYW[49]
Pretposlednja instrukcija dodaje 100-ti bajt niza na AL, a poslednja dodaje 50 tu reč niza na AX.
Primer.
Ilustruje kako se mogu oformiti alternativne labele za iste adrese, od kojih je jedna NEAR, a druga FAR.
FAR_LOOP LABEL FAR
NEAR_LOOP:
ADD AX, 2
DB <izraz> (eng. define byte - definiši bajt) - rezerviše bajt u memoriji i inicijalizuje vrednost tog bajta na izraz.
DW <izraz> (eng. define word - definiši reč) - rezerviše reč u memoriji i inicijalizuje vrednost te reči na izraz.
DD <izraz> (eng. define double word - definiši dvostruku reč) - rezerviše dvostruku reč u memoriji i inicijalizuje vrednost te dvostruke reči na izraz.
DQ <izraz> (eng. define quoter word - definiši četvorostruku reč) - rezerviše četvorostruku reč u memoriji i inicijalizuje vrednost te četvorostruke reči na izraz.
Primer.
Ilustruje kako se na desnoj strani može javiti bilo kakav izraz. Sledeći kod je sasvim korektan
TEST:
MOV AX, BX
.
.
.
OFF_TEST DW TEST
Njime je u memorijsku lokaciju OFF_TEST smešten ofset labele TEST. Još treba istaći i da redosled pojave labele TEST i lokacije OFF_TEST ne utiče na korektnost koda.
Dakle, potpuno je ispravan i sledeći kod:
OFF_TEST DW TEST
.
.
.
TEST:
MOV AX, BX
<ime> EQU <izraz> (eng. equal - jednako) - definiše simboličku konstantu (koja se ne može redefinisati) sa nazivom ime i njenu vrednost postavlja na izraz.
Primer.
Ilustruje kako se pseuudoinstrukcija EQU može koristiti za definisanje svojih mnemonika. Pri asembliranju koda:
PREMESTI EQU MOV
ADRESA EQU DS:[BP]
INICIJALIZACIJA EQU AX,DX
PREMESTI INICIJALIZACIJA
PREMESTI AX, ADRESA
dobiće se isto što bi se dobilo asembliranjem instrukcija:
MOV AX,DS
MOV AX,DS:[BP]
<ime> = <izraz> - definiše simboličku konstantu (koja se može redefinisati) sa nazivom ime i njenu vrednost postavlja na izraz.
Primer.
Ilustruje korišćenje pseudooperatora EQU i =:
CR=0DH ;carriage return
.
.
.
CR=0H ;current record
CR=CR+1 ;uvecava vrednost current record
.
.
.
CR EQU 0H ;illegal redefinition
CR EQU CR+1 ;illegal redefinition
Kao uvek pri evaluaciji izraza, prvo se izračunavaju operatori sa najvećim prioritetom. Zagradama se može promeniti prioritet izvršenja operacija. Prioritet operatora u izrazima je prikazan tabelom koja sledi. Operator SHORT ima najmanji prioritet, a operatoori u istom redu tabele imaju jednak prioritet.
LENGTH SIZE |
Operator prevazilaženja segmenta |
PTR OFFSET SEG TYPE THIS |
HIGH LOW |
* / MOD SHL SHR |
+ - (binarni i unarni) |
EQ NE LT LE GT GE |
NOT |
AND |
OR XOR |
SHORT |
EXTRN <ime> (eng. extern - spoljašnji) - saopštava asembleru da objekat sa datim imenom nije definisan u izvornom kodu koji se upravo asemblira, već u nekom drugom modulu.
Stoga asembler nije u mogućnosti da za takvo simboličko ime generiše offset tj. adresu, već u objekt kodu stavlja oznaku koja ukazuje linkeru da tu treba da uspostavi vezu.
PUBLIC <ime> (eng. public - javan) - saopštava asembleru da objekat sa datim imenom definisan u izvornom kodu može da se koristi i u drugim modulima.
Asembler dopušta da se brojevi u programu specificiraju kao binarni, dekadni ili heksadekadni. Programer može eksplicitno (korišćenjem sufiksa B, D, H) specificirati da li da asembler nisku cifara tumai kao binarni, dekadni ili heksa broj.
Postavlja se pitanje: Ako niska nema sufiks, kako asembler određuje da li će vršiti konverziju u binarni, dekadni ili heksadekadni broj?
.RADIX <izraz> (eng. radix - osnova) - naređuje da se prilikom asembliranja niske bez sufiksa konvertuju u brojeve čija je osnova data kao parametar ove pseudoinstrukcije.
Dakle, parametar pseudoinstrukcije .RADIX je izraz čija je vrednost neki od brojeva 2, 10, 16. Operandi u izrazu moraju biti konstante čija je vrednost poznata asembleru u trenutku kada on asemblira direktivu .RADIX.
[<izraz1>] DUP(<izraz2>) - naređuje da se prilikom asembliranja u memoriju onoliko puta koliko iznosi vrednost izraza ispred pseudoinstrukcije DUP smesti vrednost izraza u zagradama. Ako izraz ispred direktive DUP ne postoji, podrazumeva se da je njegova vrednost 1.
Pseudoinstrukcija NAME služi za davanje imena asemblerskom programu.
NAME <ime>
(eng. name - ime) - postavlja naziv asemblerskog programa.
Ako u asemblerskom programu nema direktive NAME, tada se naziv određuje kao prvih šest slova imena datoteke u kojoj se nalazi program.
Pseudoinstrukcija END služi za ukazivanje na kraj asemblerskog koda. Njom se specificira i tzv. ulazna tačka programa tj. simbolička adresa od koje će početi izvršavanje programa.
END [<ime>] (eng. end - kraj) -
završava asemblerski kod i određuje ulaznu tačku programa.
Za MASM je (zbog mehanizama specificiranja adresa u obliku segent:offset) od ogromnog značaja da ima informaciju koji će se segmentni registar koristiti kako pri adresiranju instrukcija, tako pri adresiranju podataka.
ASSUME <segmentni registar>:<ime>{ <segmentni registar>:<ime>} (eng. assume - preuzmi) - informiše asembler o asocijaciji između segmenata i segmentnih registara.
Parametar ime koje figuriše u ovoj pseudoinstrukciji može biti: ime segmenta prethodno definisano pomoću direktive SEGMENT; ime grupe prethodno definisano pomoću direktive GROUP; reč NOTHING; izraz kom prethodi pseudooperator SEG; izraz koji evaluiranjem daje ime segmenta ili ime grupe
Asocijacija se može kontrolisati bilo novim ASSUME pseudoinstrukcijama, bilo operatorom prevazilaženja segmenta.
Primer.
Sledeći program ilustruje korišćenje pseudooperacije ASSUME:
DATA SEGMENT
DATA_BYTE DB 414
DATA ENDS
EXTRA SEGMENT
SCREEN_DISPLAY DB 2000H DUP(?)
EXTRA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, ES:EXTRA
MOV AX, DATA
MOV DS, AX
MOV ES, AX
MOV AL, DATA_BYTE
MOV SCREEN_DISPLAY,
ASSUME DS:DATA, ES:DATA
.
.
.
NEXT_LETTER:
INC DATA_BYTE
.
.
.
MOV AX, EXTRA
MOV DS, AX
JMP NEXT_LETTER
.
.
.
CODE ENDS
END
U ovom je primeru, zbog ASSUME pseudoinstrukcije, asembleru bilo poznato da SCREEN_DISPLAY u instrukciji
MOV SCREEN_DISPLAY,
referiše na lokaciju u segmentu na čiju adresu ukazuje ES, pa će asembler generisati prevazilaženje segmenta tako da će biti korišćen ES, a ne DS.
Isti efekat se mogao postići operatorom prevazilaženja segmenta, tako da bi bila korektna i sledeća instrukcija :
MOV ES:SCREEN_DISPLAY, AL
Naravno, ako bi se tako radilo, tada za svaku od instrukcija u kojoj ima prevazilaženja segmenta, mora eksplicitno da se koristi operator prevazilaženja segmenta.
Pri korišćenju ASSUME pseudoinstrukcije jednom uspostavljeno pridruživanje važi sve dok ga ne zameni neko drugo.
Ponekad nije moguće znati šta će biti u nekom segmentnom registru kada se izvrši određena instrukcija, što može dovesti do komplikacija. Za takve komplikacije je u MASM-u obezbeđena specijalna forma ASSUME pseudoinstrukcije, oblika ASSUME NOTHING.
Primer.
U programu iz prethodnog primera, prvi put kada se izvrši instrukcija INC sve će biti u redu (jer DS pokazuje na segment u kome se nalazi DATA_BYTE): Međutim, sledeće instrukcije postavljaju DS tako da pokazuje na EXTRA segment, pa će se po izvršenju JMP instrukcije instrukcija INC izvršavati sa nekorektno postavljenim DS-om.
Ako se napiše:
ASUME DS: NOTHING
NEXT_LETTER:
INC DATA_BYTE
problem je rešen. Pseudoinstrukcija
ASSUME DS:NOTHING
saopštava asembleru da od te tačke nadalje ne
treba pretpostavljati da DS referiše na bilo koji od imenovanih segmenata.
INC DATA_BYTE
MASM traži da vidi koji imenovani segmešta programeru da preciznije kontroliše tok asembliranja.nt sadrži DATA_BYTE. Odgovor je DATA, pa MASM potom saznaje da li postoji trenutna pretpostavka o registru koji se može koristiti za adresiranje DATA segmenta. U ovom slučaju postoji, jer iako je ASSUME DS:NOTHING, istovremeno je i ASSUME ES:DATA. Kako INC instrukcija koristi registar DS kao podrazumevani, to će ovde MASM automatski generisati prevazilaženje segmenata, pa će se
instrukcija inkrementacije asemblirati kao
INC ES:DATA_BYTE
Pseudoinstrukcija ORG dopušta programeru da preciznije kontroliše tok asembliranja. Naime, prilikom asembliranja se stalno ažurira vrednost promenljive brojač lokacija, koja sadrži na offset memorijskog objekta u odnosu na početak asembliranog segmenta (način rada asemblera i linkera biće opisan u posebnom poglavlju).
ORG <izraz>
(eng. origin - poreklo, koren) - naređuje da se prilikom asembliranja
brojač lokacija postavi na evaluiranu vrednost izraza.
Primer.
Pseudoinstrukcija
ORG 200H
postavlja vrednost brojača lokacija na ofset 200H (=512D) u odnosu na početak segmenta koji sadrži ovu pseudoinstrukciju.
Asembler MASM dopušta da programer pristupi (tj. da sazna) tekuću vrednost brojača lokacija. Ta vrednost je sa stanovišta asemblera konstantna, i može figurisati u izrazima.
$ - vraća tekuću vrednost brojača lokacije.
Primer.
Pseudoinstrukcija
ORG $+2
uvećava vrednost brojača lokacija za 2.
Primer.
U sledećem segmentu koda
MY_CODE SEGMENT
START_BROJAC = $
.
.
.
MOV BX, AX
ADD CX, [BX]
.
.
.
DUZ_KOD=$-START_BROJAC+1
MY_CODE ENDS
se simbolička konstanta DUZ_KOD postavlja na broj bajtova koji zauzima asemblirani segment MY_CODE.
Već je istaknuto da se u okviru izraza koji se javlja u pseudoinstrukciji ORG smeju naći samo konstantne vrednosti. Međutim, to je potreban uslov za korektnost izraza. Dovoljan uslov zahteva da veličine koje figurišu u izrazu budu poznate već u prvoj fazi asembliranja, čim asembler naiđe na pseudoinstrukciju. Uslov korektnosti je pooštren zato što već u prvom prolasku asembler mora oformiti i čuvati relativne ofsete onim redom kako na njih nailazi, tj. određene reference moraju biti poznate asembleru već u prvoj fazi asembliranja.
Primer.
Sledeći segment programa je nekorektan:
ORG OFFSET LATER + 15
MOV
.
.
.
LATER:
MOV AX, BX
pa će se prilikom asembliranja pojaviti poruka oblika: Must be declared in PASS 1.
S druge strane, sledeći programski segment je sasvim kotrektan:
MOV
.
.
.
LATER:
MOV AX, BX
ORG OFFSET LATER + 15
Napomena.
Kod pseudoinstrukcija .RADIX i DUP izrazi koji figurišu u njima takođe moraju biti poznati u prvoj fazi asembliranja (preciznije iskazano, moraju biti poznati kada asembler prilikom asembliranja naiđe na njih).
Pseudoinstrukcija EVEN takođe omogućuje da programer u okviru asemblerskog koda utiče na vrednost brojača lokacija prilikom asembliranja.
EVEN
(eng. even - paran) - naređuje da se prilikom asembliranja brojač
lokacija postavi na sledeću parnu adresu.
Kod procesora 8086 nije bilo svejedno da li reč otpočinje na parnoj ili neparnoj adresi, pa se reč koja počinje od neparne adrese morala uzimati u dva koraka, bajt po bajt.
Pseudoinstrukcija INCLUDE je dizajnirana radi eliminisanja potrebe za ponavljanjem sekvenci instrukcija koje su zajedničke za više asemblerskih datoteka, kao šro su datoteka sa definicijama makroa, ili skup rezultata merenja izražen kao segment podataka.
INCLUDE <ime>
(eng. include - uključi) - naređuje da se prilikom asembliranja,
od mesta pojave pseudoinstrukcije, u izvorni kod uključi sadržaj
tekstualne datoteke čije je ime parametar pseudoinstrukcije.
Primer.
Pseudoinstrukcija
INCLUDE ISKAZI.ABC
prouzrokuje da asembler sadržaj datoteke ISKAZI.ABC prekopira u izvorni program na mesto gde se nalazi pseudoinstrukcija (direktiva) INCLUDE.
U ovu grupu pesudoinstrukcija spadaju: PAGE, TITLE, SUBTTL, .LIST, .XLIST, %OUT. One nisu neophodne pri pravljenju manjih programa, ali su nezaobilazne kod velikih projekata, u kojima učestvuje više programera.
PAGE [<izraz>,<izraz>] đ PAGE +
(eng. page - strana) - podešava visinu i širinu stranice u asemblerskom
listingu, ili ubacuje znak za kraj strane u tekuću stranu asemblerskog
listinga, ili prelazi na sledeće poglavlje u listingu.
Prvi parametar je izraz čija je vrednost između 10 i 255 i on predstavlja visinu stranice, dok se vrednost drugog parametra, koji predstavlja širinu stranice, kreće u opsegu 60-132. Podrazumevane vrednosti visine i širine stranice su 64 i 80. Dakle, ukoliko se vrednosti visine i širine stranice ne specificiraju korišćenjem pseudoinstrukcije PAGE, stranica listinga će sadržati 64 kolone sa maksimalno 80 znakova u koloni.
Do uvećavanja rednog broja strane i prelaska na sledeću stranu listinga može doći bilo zato što se napunila tekuća strana, ili zato što je pri asembliranju asembler naišao na pseudoinstrukciju PAGE koju nisu pratili argumenti. Dakle, korišćenjem pseudoinstrukcije PAGE bez argumenata prelazi se na sledeću stranu.
Ukoliko asembler naiđe na PAGE+ prelazi se na sledeću stranu, uvećava se redni broj poglavlja, a redni broj stranice se postavlja na 1.
TITLE <niska>
(eng. title - naslov) - postavlja naslov u asemblerskom listingu.
Niska koja prestavlja naslov može sadržati najviše 60 znakova. Ovako specificirani naslov će se pojavljivati u prvoj liniji na svakoj strani listinga. Ako naslov nije specificiran pomoću direktive TITLE, tada će se u prvoj liniji listinga naći naziv dat korišćenjem direktive NAME. Ukoliko se u izvornom kodu ne koristi ni pseudoinstrukcija NAME ni TITLE, tada se sadržaj prve linije na svakoj strani dobija od naziva datoteke u kojoj se nalazi kod.
SUBTTL <niska>
(eng. subtitle - podnaslov) - postavlja podnaslov u asemblerskom listingu.
Niska koja prestavlja podnaslov može sadržati najviše 60 znakova. Podnaslov će se pojavljivati u liniji ispod naslova u zaglavlju svake od strana listinga.
Napomena.
Prestanak štampanja podnaslova može da sepostigne korišćenjem pseudoinstrukcije
SUBTTL
bez argumenata (tj. tada se podrazumeva da je argument prazna niska).
Sledeće dve pseudoinstrukcije omogućavaju, odnosno onemogućavaju formiranje listinga pri asembliranju.
.LIST (eng. include listing - uključi listing) - naređuje da se prilikom asembliranja, od mesta pojave pseudoinstrukcije, generiše asemblerski listing.
.XLIST (eng. exclude listing - isključi listing) - naređuje da se prilikom asembliranja, od mesta pojave pseudoinstrukcije, ne generiše asemblerski listing.
Dakle, naređenje specificirano jednom od ovih direktiva traje sve dok asembler opet ne naiđe na jednu od ove dve pseudoinstrukcije, ili dok se ne završi proces asembliranja. Ako nema ni jedne ni druge pseudoinsrtukcije u izvornom kodu, asemblerski listing će biti generisan.
Sledeća pseudoinstrukcija dopušta programeru da se tokom asembliranja, u tačkama koje on izabere, prikažu željene poruke.
%OUT <niska>
(eng. out - napolje) - naređuje asembleru da, kada naiđe na ovu
pseudoinstrukciju, na izlaz pošalje nisku.
Primer.
Kada asembler u izvornom programu naiđe na pseudoinstrukciju:
%OUT pred asembliranjem procedure CALC
tada će se na ekranu pojaviti poruka:
pred asembliranjem procedure CALC
Kao što im samo ime kaže, ove pseudoinstrukcije omogućavaju pojednostavljeno kreiranje asemblerskog koda.
.MODEL <model memorije>[[,<jezik>],<tip steka>] - definiše oblik modula i olakšava zajednički rad asemblerskih procedura u modulu i programa napisanih u nekom od viših programskih jezika.
Parametar model memorije definiše segmentnu strukturu modula.On može uzeti neku od vrednosti: TINY, SMALL, MEDIUM, COMPACT, LARGE, HUGE.
Parametar jezik definiše kave konvencije imenovanja, pozivanja i povratka pretpostavlja korišćenje direktive PROC. Jezik može biti: C, Pascal, FORTRAN, BASIC.
Parametar tip steka određuje da li će asembler pri generisanju koda pretpostaviti da je SS=DS, tj. da li je stek deo segmenta podataka. Ako je vrednost ovog parametra nearStack, tada se pretpostavlja da je stek deo segmenta podataka, pa je SS=DS i SP pokazuje na vrh zone podataka.Ako je vrednost ovog parametra farStack, tada asembler pretpostavlja da je segment steka i fizički odvojen od segmenta podataka.
.CODE [<ime>] (eng. code - kod) - definiše početak kodnog segmenta.
Ako se ime ne navede, za ime segmenta će se uzeti osnovno ime datoteke sa izvornim kodom.
.STACK [<veličina>] (eng. stack - stek, stog) - definiše početak segmenta steka.
.DATA (eng. data - podatak) - definiše početak segmenta bliskih (tj. near) inicijalizovanih podataka.
.FARDATA (eng. far - dalek, udaljen) - definiše početak segmenta udalljenih (tj. far) inicijalizovanih podataka.
Nova pseudoinstrukcija SEGMENT završava prethodni segmenat. Direktiva END završva poslednji segment u izvornoj datoteci.
.STARTUP (eng. start up - otpočinjanje, startovanje) - postavlja vrednosti registara DS, SS i SP tako da je DS=SS i da je tip nearStack.
Primer.
Ukazuje na način korišćenja pojednostavljenih direktiva:
EXTRN max, act:FAR ;konstante i far obelezje su bilo gde
.MODEL small,C
.STACK 100H
.DATA
EXTRN nvar:BYTE ;near promenljiva u bliskim podacima
.FARDATA
EXTRN fvar:WORD ;far promenljiva u udaljenim podacima
.CODE
.STARTUP
EXTRN task:PROC ;task je obelezje u bliskom kodu (na bliskost ukazuje proc ili near)
ASSUME ES: SEG fvar ;utvrdi adresibilnost segmenta
;neka ES ukazuje na udaljeni segment podataka
MOV AX, SEG fvar
MOV ES, AX
.
.
.
MOV AH, nvar ;napuni spoljasnju near promenljivu
MOV BX, fvar ;napuni spoljasnju far promenljivu
CALL task ;pozovi proceduru
JMP act ;skoci na far obelezje
END
Ove pseudoinstrukcije omogućavaju kreiranje i rad sa strukturama, odnosno podacima koje se sastoje od raznorodnih elemenata. Elementi jedne strukture nazivaju se polja strukture.
STRUC (eng. structure - struktura) - definiše strukturne promenljive. Ova pseudoinstrukcija obično ima sledeći oblik:
<ime strukture> STRUC
.
.
.
<ime strukture> ENDS
Strukturna promenljiva je kolekcija bajtova u kojoj se specifičnoj grupi bajtova može pristupiti simbolički. Grupe bajtova mogu imati različitu veličinu, ali svaki član familije će imati isto grupisanje i simbolička imena za grupu še biti ista.
Primer.
Ilustruje korišćenje pseudoinstrukcije STRUC:
REPORT STRUC
HEADER DB 30H DUP(‘ ‘)
DATE DB 6D DUP(0)
CONTENT DB 2000H DUP(‘ ‘)
REPORT ENDS
Iako asembler MASM to ne zahteva, uobičajeno je da se familija strukturnih promenljivih definiše na samom početku izvornog asemblerskog programa.Taj redosled je ovde uobičajen, a kod viših programskih jezika je zahtevan.
Primer.
Na ovaj način se oformljuju memorijski objekti sa datom strukturom
REPORT STRUC
HEADER DB 30H DUP(‘ ‘)
DATE DB 6D DUP(0)
CONTENT DB 2000H DUP(‘ ‘)
REPORT ENDS
DATA SEGMENT
.
.
.
SALES REPORT <>
MARKETING REPORT <>
.
.
.
Napomena.
Simboli <> kod struktura SALES i MARKETING u prethodnom primeru ukazuju da se ne prevazilazi inicijalizacija data u definiciji familije, tj. definiciji strukture.
Primer.
Ilustruje prevazilaženje inicijalizacije koja je data u definiciji familije:
ADRESS STRUC
PERSON DB ‘THE OCCUPIER ’
STREET DB ‘IF UNDELIVERED PLEASE RETURN ‘
CITY DB ‘TO SENDER ’
ZIPCODE DB ‘AB12 3DE ‘
COUNTRY DB ‘
ADRESS ENDS
DATA SEGMENT
.
.
.
HOME1 ADRESS <‘Mr. J.Bloggs ‘, ‘14 Railway Cuttings ‘, ‘London ‘, ‘NW10 2AG ‘, ‘GB’>
.
.
.
HOME2 ADRESS < , ‘27 Black Street
‘, ‘
.
.
.
DATA ENDS
Uočava se da su vrednosti za polja PERSON i COUNTRY u strukturi HOME2 u stvari vrednosti određene u definiciji familije.
Pristup pojedinim poljima strukturne promenljive se, slično kao u višim programskim jezicima, realizuje primenom punktualnog operatora.
<strukturna promenljiva>.<ime polja> - vraća zadato polje u datoj strukturi.
Primer.
Ilustruje primenu operatora za pristup poljima u strukturi:
STUDENT STRUC
NAME 30D DB DUP(‘ ‘)
STREET 30D DB DUP(‘ ‘)
CITY 20D DB DUP(‘ ‘)
AGE DB 18
STUDENT ENDS
DATA SEGMENT
.
.
.
DOBAR STUDENT < , , , 20>
.
.
.
LOS STUDENT < , , , 28>
.
.
.
DATA ENDS
CODE SEGMENT
.
.
.
MOV
.
.
.
MOV BX, OFFSET LOS
MOV
.
.
.
CODE ENDS
END
Napomena.
Pristup iz prethodnog primera se ne može primeniti za polja strukturi koja nisu jednočlana. Tako, ako se posmatra struktura i promenljive iz prehodnog primera, tada je
MOV DX, OFFSET DOBAR
korektno, dok je
MOV DX, OFFSET [BX].NAME
nekorektno.
Međutim, ovaj problem može biti razrešen. Pristup ofsetu pojedinog polja u okviru zadate strukture na koju ukazuje registar BX, se može realizovati korišćenjem instrukcije LEA:
LEA DX, [BX],.NAME
Napomena.
Strukture se ne mogu ugnežđavati, tj. izmedju
<ime strukture> STRUC
.
.
.
<ime strukture> ENDS
se ne sme pojaviti druga pseudoinstrukcija STRUC.
Dok je za najveći broj svrha za koje se koristi asemblerski jezik pogodno da se rukuje podacima grupisanim u bajtove, ponekad je neophodno rukovati podacima kao grupama bitova. Za rad sa podacima na ovakav način može se koristiti pseudoinstrukcija RECORD. Koristeći ovu pseudoinstrukciju, u asembleru se mogu deklarisati slogovne promenljive. Te promenljive su slične ostalim, s tim što se kod slogovnih specifičnoj grupi susednih bitova može simbolički pristupiti.
Ukupan broj bitova koji zauzimaju sve različite grupe ne sme da bude veći od 32 (odnosno, kod predhodnika procesora 80386, od 16).
<ime sloga> RECORD <polje>:<širina>š ,<polje>:<širina>ć (eng. record - slog) - definiše slogovne promenljive, tj. omogućava kreiranje familije promenjivih kod kojih se pojedinim grupama susednih bitova može simbolički pristupiti.
Ukupan broj bitova koji zauzimaju sve različite grupe ne sme da bude veći od 32 (odnosno, kod predhodnika procesora 80386, od 16).
Primer.
Neka se familija slog promenljivih koristi za pomoć u programiranju kolor prikaza na PC-u. Kada se (u jednom od modova) prikazuje tekst u koloru, boja teksta i boja pozadine za svaku poziciju karaktera na ekranu je određena postavljanjem bitova u okviru relevantnog bajta atribita: bitovi 0,1,2,3 određuju boju pozadine; bitovi 4, 5, 6 određuju boju teksta; dok bit 7 određuje da li će tekst blinkovati.
Deklarisanje familije slogovnih promenljivih koje bi se koristile u ovoj situaciji, realizuje se na sledeći način:
COLOR_SETTING RECORD BLINK:1, FOREGROUND:3, BACKGROUND:4
Ovim je deklarisano ime familije, te imena i veličine pojedinih bitovnih polja koja se nalaze u okviru promenljivih iz zadate familije slogovnih promenljivih.
Da bi se mogle koristiti slog promenljive iz prethodno definisane familije, asembleru se mora saopštiti ime promenljive i ime familije slogovnih promenljivih. Ukoliko je to neophodno, može se specificirati i inicijalna vrednost za promenljivu.
Primer.
Pseudoinstrukcija:
MENU COLOR_SETTING <0, 2, 3>
će inicijalizovati memorijsku promenljivu MENU dužine 8 na vrednost 00100011B.
Konvencija je da se deklaracije familija slog promenljivih, tj. RECORD pseudoinstrukcije, obično nalaze na samom početku asemblerskog programa.
Primer.
Obrazac deklarisanja slog promenjljive je, stoga, sledeći:
COLOR_SETTING RECORD BLINK:1, FOREGROUND:3, BACKGROUND:4
.
.
.
DATA SEGMENT
.
.
.
MENU COLOR_SETTING <0, 2, 3>
.
.
.
DATA ENDS
CODE SEGMENT
.
.
.
CODE ENDS
END
U slogu koji se deklariše, prvo deklarisano polje biće smešteno u najznačajnije cifre, tj. na pozicije najveće težine; sledeće deklarisano polje smestiće se u sledeća desna polja, tj. u sledeća polja manje težine. Nadalje se smeštanje nastavlja na isti način, sve do poslednjeg deklarisanog polja.
Ako je zbir dužina bitovnih polja takav da se slogovna promenljva može smestiti u bajt, tada će asembler oformiti slogove koji odgovaraju bajtovima. U suprotnom, oformljeni slogovi će odgovarati rečima, odnosno dvostrukim rečima. Ukoliko je zbir dužina bitovnih polja manji od 8, odnosno 16, tj. 32, tada će polja biti desno poravnata - poslednji bit poslednjeg polja će biti smešten u bitu najmanje težine bajta, odnosno reči, tj. dvostruke reči.
Primer.
Neka asemblerski program sadrži sledeći kod:
TIME RECORD HOURS:6, MINUTES:6
.
.
.
DATA SEGMENT
.
.
.
START_TIME TIME <10, 02>
.
.
.
U ovom slučaju je zbir širina polja promenljive START_TIME 12 bitova, pa će asembler rezervisati reč u memoriji i polja će biti desno poravnata. Neiskorišćeni bajtovi će imati nedefinisanu vrednost. Stoga će reč čija je simbolička adresa START_TIME biti postavljena na ????001010000010B.
Napomena.
Nemoguće je definisati sledeću familiju slogovnih promenljivih:
TIME RECORD HOURS:12, MINUTES:12, SECONDS:12
Zato što zbir dužina bitovnih polja prevazilazi 32.
Ukoliko se pri deklarisanju slogovne promenljive izostavi neka vrednost u inicijalizaciji, onda sadržaj odgovarajućeg bitovnog polja neće biti inicijalizovan.
Primer.
Neka asemblerski program sadrži sledeći kod:
DATE RECORD MONTH:4, DAY:5, YEAR:7
.
.
.
DATA SEGMENT
.
.
.
START_DATE DATE <10, , 91>
.
.
.
U ovom slučaju se START_DATE inicijalizuje tako da polje MONTH dobije vrednost 10101, polje YEAR 1001011, dok će vrednost za polje DAY ostati neinicijalizovana.
Slično bi deklaracija
START_DATE DATE < , 1, 91>
ostaviti polje MONTH neinicijalizovanim, dok će
START_DATE DATE <10, 1, >
Ostaviti polje YEAR neinicijalizovanim. Deklaracija oblika:
START_DATE DATE < , , >
ostavlja neinicijalizovanim sva tri polja.
Isto kao što se pseudoinstrukcija DUP može koristiti zajedno sa pseudooperatorima DB, DW, DD, DQ, DT za deklaraciju više od jedne promenljive, tako se pseudoinstrukcija RECORD može koristiti za deklaraciju više od jedne promeljive iz familije slogovnih promnljivih.
Primer.
Deklaracija
MY_DATES DATE 24H DUP(<>)
Prouzrokuje da asembler rezerviše 24 reči u memoriji, od kojih na prvu referiše simbolička adresa MY_DATES. Svaka od ovih reči se može tretirati kao promenljiva tipa DATE.
U ovom odeljku se opisuju operatori koje obezbeđuje asembler za manipulisanje sa slogovnim promenljivima. To opisivanje se realizuje u kontekstu korišćenja slogovnih promenljivih za implementaciju skupova.
Primer.
Neka su PASCAL promenljive deklarisane na sledeći način:
type
colours = (brown, yellow, green, red, orange);
pallete = set of colours;
var
davinci, rubens, renoir: pallete;
i neka su neke od vrednosti koje može uzeti promenljiva davinci :
[red, green], [orange], [brown, yellow, red], [brown..red], [brown..green, orange]
Obično se koristi jedan bit za predstavljanje prisustva (taj bit se tada postavi na 1) odnosno odsustva (bit se postavi na 0) svakog mogućeg elementa u skupu. Za prethodno popisane skupove bi se koristila sledeća reprezentacija:
[red, green] |
00110 |
[orange] |
00001 |
[brown, yellow, red] |
11010 |
[brown..red] |
11110 |
[brown..green,
orange] |
11101 |
Familija slogovnih promenljivih koje predstavljaju skupove bi u ovom slučaju bila definisana sledećom pseudoinstrukcijom:
PALLETE RECORD BROWN:1, YELLOW:1,
GREEN:1, RED:1,
Dakle, na ovaj način bi bila implementirana deklaracija tipa pallete definisanog u prethodnom PASCAL programu. Od strane asemblera će za svaku paletu biti uzet jedan bajt, pri čemu su od interesa samo bitovi na pet mesta najmanje težine.
Tako će efekat deklaracije
DAVINCI PALLETE <1, 1, 0, 1, 0>
biti da se u bajt na koji referiše DAVINCI pri inicijalizaciji smešta ???11010B. Ako je još istovremeno i
RUBENS PALLETE <0, 1, 0, 1, 1>
RENOIR PALLETE <1, 1, 0, 0, 1>
Tada se paskalovska naredba dodele
rubens:= davinci;
implementira sekvencom asemblerskih instrukcija
MOV AL, DAVINCI
MOV
Postoje tri operatora koji se koriste za izolaciju pojednih polja u slogu: brojač pomeraja, WIDTH i MASK.
<polje> - brojač pomeraja postaje efektivan navođenjem naziva polja u slogu. On faktički vraća broj bitovnih pozicija za koje odgovarajuće polje treba pomeriti udesno da bi to polje bilo desno poravnato.
Primer.
Ako je u asemblerskom programu familija slogovnih promenljivih definisana pseudoinstrukcijom:
PALLETE RECORD BROWN:1, YELLOW:1,
GREEN:1, RED:1,
tada se instrukcija
MOV CL, YELLOW
asemblira kao da što se asemblira instrukcija
MOV CL, 3
jer polje YELLOW mora biti pomereno za dva mesta udesno da bi bilo desno poravnato.
WIDTH <polje> (eng. width - širina) - vraća širinu polja u slogu, tj. broj bitovnih mesta koje zauzima polje.
Primer.
Ako je u asemblerskom programu familija slogovnih promenljivih definisana pseudoinstrukcijom:
PALLETE RECORD BROWN:1, YELLOW:1,
GREEN:1, RED:1,
tada se instrukcija
MOV CL, WIDTH YELLOW
asemblira kao da što se asemblira instrukcija
MOV CL, 1
MASK <polje> (eng. mask - maska) - vraća bitovnu masku za pozicije koje zauzima polje.
Primer.
Ako je u asemblerskom programu familija slogovnih promenljivih definisana pseudoinstrukcijom:
PALLETE RECORD BROWN:1, YELLOW:1,
GREEN:1, RED:1,
tada se instrukcija
MOV CL, MASK YELLOW
asemblira kao da što se asemblira instrukcija
MOV CL, 00001000B
Primer.
Implementacija PASCAL instrukcije
davinci:= [yellow, red]
bi lako mogla biti realizovana sledećim kodom (uz korišćenje slogovnih promenljivih formiranih u prethodnim primerima):
MOV
MOV CL, YELLOW
SHL AL, CL
MOV DAVINCI,
MOV
MOV CL, RED
SHL AL, CL
OR AL, DAVINCI
MOV DAVINCI,
Zadatak.Opisati
efekat izvršenja sledećeg asemblerskog koda.
DATE RECORD MONTH:4, DAY:5, YEAR:7
.
.
.
DATA SEGMENT
.
.
.
RODJEN DATE <1, 27, 76>
.
.
.
DATA ENDS
CODE SEGMENT
.
.
.
MOV AX, RODJEN
MOV BX, 0
MOV CL, DAY
MOV DL, YEAR
ADD DL, WIDTH MONTH
SHR AX, CL
AND AX, 0FFFEH
SHL AX, CL
MOV RODJEN, AX
MOV BX, NOT MASK MONTH
.
.
.
CODE ENDS
Još treba razmotriti kako se slogovne promenljive koriste za implementaciju nekih operacija i relacija nad skupovima.
Primer.
Neka su deklarisane slogovne promenljive kao u prethodnim primerima. Tada, paskalovska naredba dodele
renoir:= davinci + rubens;
može da se implementira sekvencom asemblerskih instrukcija
MOV AL, DAVINCI
OR AL, RUBENS
MOV
Primer.
Neka su deklarisane slogovne promenljive kao u prethodnim primerima. Tada, paskalovska naredba dodele
renoir:= davinci * rubens;
može da se implementira sekvencom asemblerskih instrukcija
MOV AL, DAVINCI
AND AL, RUBENS
MOV
Primer.
Neka su deklarisane slogovne promenljive kao u prethodnim primerima i neka treba proveriti da li je vrednost skupovne promenljive davinci podskup od rubens, tj. treba evaluirati izraz
davinci <= rubens
To se (uz korišćenje stava a<=b Ű a*b=a) može postići sledećom sekvencom asemblerskih instrukcija:
MOV AL, DAVINCI
AND AL, RUBENS
XOR AL, DAVINCI
Na ovaj način će u
registru
Prvo slovo u nazivu programa MASM ukazuje da se radi o makroasembleru, tj. da taj program dopušta korišćenje makroa.
Makroi su sekvence asemblrskih instrukcija koje imaju jednoznacno određeno ime. Ako programer uoči da se neke slične sekvence instrukcija javljaju više puta u kodu, on može oformiti makroe, i u kodu samo pozivati te makroe. Makroasembler na počeku asembliranja startuje tzv. makro predprocesor, koji iz izvornog koda "izvuče" sve definicije makroa i njihov kod. Potom se, makroi razviju - svi pozivi nekog makroa u izvornom kodu se zamene sa kodom koji je dat u definiciji makroa.
U definiciji makroa mogu se specificirati formalni parametri. To znači da će pri razvoju makroa svaki od tih formalnih parametara biti zamenjen sa tekstom odgovarajućeg stvarnog parametra.
MACRO - definiše asemblerski makro. Ova pseudoinstrukcija se obično javlja u paru sa pseudoinstrukcijom ENDM i ima sledeći oblik:
<ime makroa> MACRO [<parametar>š,<parametar>ć]
.
.
.
ENDM
Primer.
Od sledećeg segmenta koda (koji uređuje dva broja smeštena u bajtu)
MOV AL, PRVI
CMP AL, DRUGI
JNB GOTOVO
XCHG AL, DRUGI
MOV PRVI,
GOTOVO:
se lako može napraviti makro:
UREDI MACRO PRVI, DRUGI
MOV AL, PRVI
CMP AL, DRUGI
JNB GOTOVO
XCHG AL, DRUGI
MOV PRVI,
GOTOVO:
ENDM
Međutim, asembler bi javio grešku pri svkom pokušaju asembliranja koda koji sadrži više od jednog poziva ovog makroa. Do greške dolazi zato što se labela GOTOVO koja se javlja u definiciji makroa razvijanjem javlja na bar dva mesta u kodu, što bi značilo da dve različite memorijske lokacije imaju istu simboličku adresu.
Da bi se prevazišli problemi ove vrste, u makroasemblerski jezik je uvedena pseudoinstrukcija koja proglašava da će data labela prilikom razvoja makroa dobiti jedinstveno ime. To je pseudoinstrukcija LOCAL.
LOCAL <ime> (eng. local - lokalno) - saopštava asembleru da je svako od imena u listi lokalno za makro i da im se pri svakom razvoju makroa daje ime koje ih jednoznačno identifikuje.
Primer.
Dakle, makro iz prethodnog primera će biti sledeći:
UREDI MACRO PRVI, DRUGI
LOCAL GOTOVO
MOV AL, PRVI
CMP AL, DRUGI
JNB GOTOVO
XCHG AL, DRUGI
MOV PRVI,
GOTOVO:
ENDM
Primer.
Ilustruje pozivanje makroa napravljenog u prethodnom primeru:
UREDI MACRO PRVI, DRUGI
LOCAL GOTOVO
MOV AL, PRVI
CMP AL, DRUGI
JNB GOTOVO
XCHG AL, DRUGI
MOV PRVI,
GOTOVO:
ENDM
DATA SEGMENT
TOTAL DB ?
SUM DB ?
MILES DB ?
DATA ENDS
STK SEGMENT STACK
DB 100H DUP(?)
STK ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:STK
START:
MOV AX, DATA
MOV DS, AX
;procitaj bajtove sa ulaza
CALL READCHAR
MOV TOTAL,
CALL READCHAR
MOV SUM,
CALL READCHAR
MOV
;izvrsi uredjivanje
UREDI TOTAL, SUM
UREDI SUM, MILES
UREDI TOTAL, SUM
;prikazi rezultate
MOV DL, TOTAL
CALL PRINTCHAR
MOV DL, SUM
CALL PRINTCHAR
MOV DL, MILES
CALL PRINTCHAR
;kraj programa
MOV AX, 4c00h
INT 21H
;procedura za ucitavanje znaka sa tastature
READCHAR:
MOV AH, 1
INT 21H
RET
;procedura za prikaz znaka na ekran
PRINTCHAR:
MOV AH, 2
INT 21H
RET
CODE ENDS
END START
Budući da makroi i podprogrami obavljaju donekle istu funkciju, logično se postavlja pitanje: kada koristiti jedne, a kada koristiti druge?
Naravno, jasno je da i jedan i drugi koncept značajno poboljšavaju programerski kod i olakšavaju proces programiranja.
Ne postoje jasna i brza pravila koja bi dala odgovor na prethodno postavljeno pitanje. Normalno bi billo koristiti podprograme onda kada se ponavljaju grupe instrukcija koje su potpuno iste u svim svojim pojavama. S druge strane, ima smisla koristiti makroe u slučajevima kada su mnemonici instrukcija isti, ali se labele, promenljive ili izrazi menjaju od jedne do druge pojave.
Primer.
Za segment asemblerskog programa:
ADD AX, BX
MUL DX
CMP AX, 3
JNZ TEST1
.
.
.
ADD AX, BX
MUL DX
CMP AX, 3
JNZ TEST2
.
.
.
ADD AX, BX
MUL DX
CMP AX, 3
JNZ TEST3
.
.
.
je mnogo pogodnije koristiti makroe:
TEST MACRO LABELA
ADD AX, BX
MUL DX
CMP AX, 3
JNZ LABELA
ENDM
.
.
.
TEST TEST1
.
.
.
TEST TEST2
.
.
.
TEST TEST3
.
.
.
nego da se radi preko procedura:
SABMNOPOR:
ADD AX, BX
MUL DX
CMP AX, 3
pa da se skok, u zavisnosti od postavljenih flegova, izvršava po izlasku iz procedure.
Napomena.
Kako su makroi zasnovani na zameni stringova, to mesto njihovog pojavljivanja nije bitno. Ipak obično su definicije makroa date bilo na početku asemblerskog programa, bilo u posebnim datotekama koje pomoću pseudoinstrukcije INCLUDE bivaju uključene u izvorni kod.
Već je prethodni primer ukazao da parametri u definiciji makroa mogu predstavljati ne samo promenljive, već i labele. Parametri takođe mogu predstavljati registre, instrukcije, opkodove instrukcija, niske, ili numeričke vrednosti.
Primer.
U definiciji makroa iz jednog od prethodnih primera:
UREDI MACRO PRVI, DRUGI
LOCAL GOTOVO
MOV AL, PRVI
CMP AL, DRUGI
JNB GOTOVO
XCHG AL, DRUGI
MOV PRVI,
GOTOVO:
ENDM
registar
Stoga, mogao bi se napraviti novi makro:
NOVOUREDI MACRO PRIVRREG, PRVI, DRUGI
LOCAL GOTOVO
MOV PRIVRREG, PRVI
CMP PRIVRREG, DRUGI
JNB GOTOVO
XCHG PRIVRREG, DRUGI
MOV PRVI, PRIVRREG
GOTOVO:
ENDM
Asembler sadrži sa neke, već ugrađene, makroe, koje programer može pozivati a da ih prethodno ne definiše. Ti predefinisani makroi omogućavaju da programer radi onako kako bi radio u nekom od viših programskih jezika.
Koristeći makroe FORDO i ENDFOR, može se oformiti programska struktura ekvivalentna sa for petljom u nekom od viših programskih jezika.
FORDO <donja granica>,<gornja granica>,<labela početak>,<labela kraj>,<registar brojač> - omogućava, zajedno sa makroom ENDFOR, lako kreiranje brojačke petlje.
Ovaj makro ima sledeći izgled:
FORDO MACRO DONJI, GORNJI, START, STOP, REG
MOV REG, GORNJI
SUB REG, DONJI
JB STOP
INC REG
START:
CMP REG, 0
JE STOP
DEC REG
ENDM
ENDFOR <donja granica>,<gornja granica> - omogućava, zajedno sa makroom FORDO, lako kreiranje brojačke petlje.
Definicija ovog makroa je:
ENDFOR MACRO START, STOP
JMP START
STOP:
ENDM
Primer.
Odavde je jasno da će programski sistem oblika:
FORDO 1, 12H, BEG, END, SI
MOV AH, 1
INT 21H
ENDFOR BEG, END
pri asembliranju formirati sledeći listing:
FORDO 1, 12H, BEG, END, SI
1 MOV SI, 12H
1 SUB SI, 1
1 JB END
1 INC SI
1 BEG: CMP SI, 0
1 JE END
1 DEC SI
MOV AH, 1
INT 21H
ENDFOR BEG, END
1 JMP BEG
1 END:
Napomena.
Uočava se da, ukoliko je prvi parametar makroa veći od drugog parametra, tada nema prolazaka kroz telo petlje. Takvo ponašanje karakteriše i više programske jezike.
Primer.
Ovim primerom se realizuje štampanje velikih i malih slova abecede na ekran.
FORDO ‘A’, ‘Z’, BEGPRINT, ENDPRINT, CL
MOV DL, ‘Z’
SUB DL, CL
;stampaj veliko slovo
CALL PRINTCHAR
;konvertuj u malo slovo
ADD DL, 20H
;stampaj malo slovo
CALL PRINTCHAR
;vrati u veliko slovo
SUB DL, 20H
ENDFOR BEGPRINT, ENDPRINT
Parametri u definiciji makroa mogu biti instrukcije, ali ne mogu biti sami nazivi makroa.
Primer.
Makro koji sledi ilustruje prethodno tvrđenje:
RADIPUNO MACRO BROJ, BROJAC_REG, INSTRUKCIJA, OPERAND
FORDO 1, BROJ, POCRADIPUNO, KRAJRADIPUNO, BROJAC_REG
INSTRUKCIJA OPERAND
ENDFOR POCRADIPUNO, KRAJRADIPUNO
ENDM
Poziv ovog makroa može imati oblik:
RADIPUNO 27D, AH, INC, BX
će pri asembliranju biti raširen u 27 instrukcija INC BX.
Kako se razvijanje makroa zasniva na zameni niski (stringova), to redosled definisanja nije od nikakvog značaja. Ali, program će biti čitljiviji ako se prvo definišu makroi - gradivni elementi, potom složeniji makroi (oni koji koriste makroe - gradivne elemente), da bi tek posle njih bile instrukcije programa.
Zadatak. Koristeći
makroe FORDO i ENDFOR, napisati asemblerski program koji radi sledeće:
a) Izračunava
sumu kvadrata prvih 30D prirodnih brojeva:
b) Za dati dan u
nedelji u koji “pada” prvi tog meseca, i za dati broj dana u mesecu, štampati
kalendar u obliku
|
U |
Sr |
C |
Pe |
Su |
N |
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
|
|
|
Zadatak. Napisati
makro ekvivalente za while i repeat
petlju u PASCAL-u. Potom, koristeći prethodno napravljene makroe, napisati
programe za:
a) Proveru da li je
unesena sekvenca zagrada korektna.
b) Određivanje i
štampanje svih trocifrenih brojeva čija
je vrednost jednaka zbiru kubova njegovih cifara.
Ponekad je poželjno da se koriste makroi za definisanje nizova podataka.
Primer.
Neka je potrebno definisati niz dvostrukih reči koje sadrže stepene broja 2, i kojima se može indidvidualno pristupiti preko simboličkih imena DVANA1 (sadrži 2), DVANA2 (sadrži 4), DVANA3 (sadrži 8) itd, sve do DVANA10 (sadrži 1024).
Za realizaciju takvog cilja, programeru su na raspolaganju i sledeći pseudooperatori:
<izraz>&<ime > - spaja na izraz vrednost zadatog imena u trenutku izvršenja pseudoinstrukcije.
%<izraz > - primorava makroasembler da evaluira izraz, pa vraća evaluiranu vrednost zadatog izraza.
Primer.
Da bi se postiglo definisanje drugog stepena broja 2, makro bi trebao da sadrži sledeće instrukcije:
BROJ_LABELA=2
VREDNOST=4
DVANA&BROJ_LABELA DD VREDNOST
Pored toga, poželjno je da postoji i predefinisani makro, takav da omogućava da se neka sekvenca asemblerskih instrukcija ponovi zadati broj puta.
REPT - (eng. repeat - ponovi) određuje da se kod između poziva ove pseudoinstrukcije i prvog ENDM ponavlja potreban broj puta. Dakle, pseudoinstrukcija REPT se obično javlja u paru sa pseudoinstrukcijom ENDM i ima sledeći oblik:
REPT <broj ponavljanja>
.
.
.
ENDM
Primer.
Da bi se postiglo definisanje prvih deset stepeni broja 2 onako kako je zahtevano u prvom primeru ovog poglavlja, potrebna su dva makroa:
Razvojem prvog od njih, definiše se jedan podatak, tj. jedan stepen dvojke:
DVA_NA MACRO BROJ_LABELA, VREDNOST
DVANA&BROJ_LABELA DD VREDNOST
ENDM
Sada se ovaj makro treba pozvati 10 puta, svaki put sa nešto drugačijim parametrima. Jedan od načina za ciklično pozivanje je korišćenje makroa FORDO i ENDFOR. Drugi način, u kom se koristi makro REPT, je:
NIZ_DV_NA MACRO
REPT 10D
IZLOZILAC = IZLOZILAC + 1
STEPEN = STEPEN * 2
DVA_NA %IZLOZILAC, %STEPEN
ENDM
ENDM
U ovom slučaju pseudoinstrukcije REPT i ENDM usmeravaju asembler da deset puta ponavlja instrukcije unutar petlje. Na taj način sekvenca pseudoinstrukcija
IZLOZILAC = 0
STEPEN = 1
NIZ_DVA_NA
biva tokom asembliranja raširena u:
IZLOZILAC = 0
STEPEN = 1
DVANA1 DD 2
DVANA2 DD 4
DVANA3 DD 8
DVANA4 DD 16
DVANA5 DD 32
DVANA6 DD 64
DVANA7 DD 128
DVANA8 DD 256
DVANA9 DD 512
DVANA10 DD 1024
^esto se dešava da niz podataka ne sadrži vrednosti koje se lako mogu odrediti formulom. U tom slučaju, prethodno opisani pristup pada u vodu.
Primer.
Neka je potrebno definisati niz bajtova koji sadrže uzastopne proste brojeve, i kojima se može indidvidualno pristupiti preko simboličkih imena PROSTI1, PROSTI 2, PROSTI 3 itd, sve do PROSTI 10.
Asembler MASM sadrži još jedan predefinisani makro, koji olakšava programiranje u ovakvim slučajevima:
IRP - (eng. iterative repeat - iterativno ponavljanje) određuje da se kod između pseudoinstrukcije i prvog ENDM ponavlja onoliko puta, koliko je veličina drugog (nizovnog) argumenta, pri čemu u svakoj iterraciji prvi argumenat biva zamenjen sa odgovarajućom komponentom drugog argumenta. Pseudoinstrukcija IRP se najčešće javlja u paru sa pseudoinstrukcijom ENDM. Ona ima sledeći oblik:
IRP <ime>,<niz>
.
.
.
ENDM
Primer.
Da bi se postiglo definisanje prvih deset prostih brojeva na način zahtevan u prethodnom primeru, potrebna su dva makroa:
Prvi makro se koristi za definisanje jednog podatka:
PROST MACRO BROJ_LABELA, PROST
PROSTI&BROJ_LABELA DB PROST
ENDM
Sada se ovaj makro treba pozvati 10 puta, svaki put sa nešto drugačijim parametrima. Ne postoji formula koja bi za redni broj elementa na jednostavan i lak način određivala vrednost tog elementa.
NIZ_PROSTIH MACRO
IRP PRIM, <2, 3, 5, 7, 11, 13, 17, 19, 23, 29>
BROJ = BROJ + 1
PROST %BROJ, PRIM
ENDM
ENDM
Na ovaj način sekvenca pseudoinstrukcija
BROJ = 0
NIZ_PROSTIH
biva tokom asembliranja raširena u:
BROJ = 0
PROSTI1 DB 2
PROSTI2 DB 3
PROSTI3 DB 5
PROSTI4 DB 7
PROSTI5 DB 11
PROSTI6 DB 13
PROSTI7 DB 17
PROSTI8 DB 19
PROSTI9 DB 23
PROSTI10 DB 29
Primer.
Jednim pozivom sledećeg makroa sadržaji registara AX, BX, CX, DX, SI, DI će biti gurnuti na stek:
PUSH_REGIS MACRO
IRP REGIS, <AX, BX, CX, DX, SI, DI>
PUSH REGIS
ENDM
ENDM
Kada se ovaj makro raširi, dobija se asemblerski kod:
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
Pseudoinstrukcija IRPC je varijacija pseudoinstrukcije IRP. Kod te pseudoinstrukcije drugi parametar nije niz, već niska (string).
IRPC - (eng. iterative repeat of characters - iterativno ponavljanje znakova) određuje da se kod između pseudoinstrukcije i prvog ENDM ponavlja onoliko puta, koliko iznosi dužina drugog argumenta, pri čemu u svakoj iterraciji prvi argumenat biva zamenjen sa odgovarajućim znakom drugog argumenta. Pseudoinstrukcija IRPC se skoro uvek javlja u paru sa pseudoinstrukcijom ENDM. Ona ima sledeći oblik:
IRPC <ime>,<niska>
.
.
.
ENDM
Primer.
Sledeći kod :
DATA SEGMENT
.
.
.
IRPC CODE, CXPRMNYZTUABVDIJKEFGHOQSW
DW ‘&CODE&’
ENDM
.
.
.
DATA ENDS
će pri asembliranju biti raširen u:
DATA SEGMENT
.
.
.
DW ‘C’
DW ‘X’
.
.
.
DW ‘S’
DW ‘W’
.
.
.
DATA ENDS
Ovo, na primer, može predstavljati tajni kod po kome se slovo A kodira slovom C, slovo B slovom X, slovo C slovom P, itd.
Zadatak. Koristeći
pseudoinstrukcije REPT, IRP ili IRPC, napisati deo asemblerskog program za
inicijalizaciju sledećih promenljivih:
a) Kvadrate prvih
deset celih brojeva u neoznačenoj 8-bitnoj formi, nazvane KVAD1, KVAD2,
KVAD3 itd.
b) Broj dana u svakom
mesecu, počev od januara, sa oznakama MES1, MES2, itd.
c) 26 promenljivih,
nazvanih A, B, C, ..., Y, Z inicijalizovanih na istu vrednost.
d) Prvih deset
stepeni broja 3, označene sa TRINA1, TRINA2, itd. u neoznačenoj
64-bitovnoj formi.
Zadatak. Napisati i
testirati makro SPACES, koji ima jedan parametar: nenegativan ceo broj. Pri
razvijanju makroa treba da se dobiju instrukcije za štampanje tog broja
blankova.
Zadatak. Ispitati
makro FORDO. Da li je moguće napisati ekvivalentan makro bez korišćenja
parametara START i STOP? Ako da, kako? Ako ne, zašto?
U ovom poglavlju će biti opisan način rada asemblera i linkera.
Asembler MASM je, kao što je nešto ranije istaknuto dvoprolazan - asembliranje se odvija u dve faze.
Za rad sa lokacijama koje odgovaraju simbolima u pvoj fazi asembliranja, makroasembler MASM koristi promenljivu nazvanu brojač lokacija. Brojač lokacija se postavlja na nulu na početku asembliranja ma kog segmenta. Kako se prolazi kroz svaku od instrukcija u segmentu, tako se brojač lokacija uvećava za broj bajtova koje zauzima konkretna instrukcija. Brojač lokacija se koristi za konstruisanje tabele simbola, koja čuva relativne ofsete podataka i instrukcija u okviru jednog segmenta. Podaci iz tabele simbola se koriste u drugom prolasku radi generisanja adresa operanada.
Sam postupak kojim se realizuje prvi prolazak asemblera, mogao bi se opisati sledećim pseudo-PASCAL kodom:
brojac_lokacija:= 0;
pročitaj novu instrukciju sa izvora;
while pročitana instrukcija nije END pseudoinstrukcija do
begin
if promenljiva ili labela je već u tabela_simbola then
begin
odstampaj poruku o grešci
else
u tabelu simbola unesi simbol, trenutnu vrednost promenljive brojac_lokacija
i informacije o tipu simbola
end;
case pročitana instrukcija koristi of
DB, DW, DD, DQ,...::
begin
odredi dužinu prostora koji treba rezervisati;
uvećaj brojač lokacija za tu veličinu;
end;
SEGMENT:
begin
brojac_lokacija:= 0;
unesi ime segmenta u tabelu simbola;
end;
end;
if pročitana instrukcija je korektna then
begin
odredi duzinu instrukcije na osnovu podataka iz unutrašnje tabele;
uvećaj brojač lokacija za dužinu instrukcije;
end
else
odštampaj poruku o grešci;
end;
Generisanje mašinskog (tj. objekt) koda u se realizuje drugom prolazu, a na osnovu internih tabela koje za svaku formu instrrukcije sadrže odgovarajuće podatke. To generisanje nije uvek jednostavno, jer asembler dopušta da instrukcije i pseudoinstrukcije sadrže aritmetičke izraze. U drugom prolazu će, pre generisanja koda, biti evaluirani svi izrazi koji se javljaju u asemblerskom programu.
U drugom prolazu se razrešava i problem tzv. prosleđenih referenci (eng. forward reference - prosleđena referenca). Kada asembler naiđe na instrukciju koja sadrži prosleđenu referencu, tada će (ako mu programer direktivom FAR nije naglasio suprotno) pretpostaviti da se radi o bliskom skoku, pa će u prvom prolazu biti rezervisan prostor samo za ofset odredišta (za toliku vrednost še se uvećati brojač lokacija). Razrešavanje problema prosleđenih referenci može dovesti do toga da informacije iz prvog i drugog prolaska budu nekonzistentne, pa se javlja tzv. greška u fazama (eng. phase error - fazna greška).
Način korišćenja linkera i njegova svrha su već ranije opisani. Ovde će se detalljnije razmotriti realokacija i upravljanje memorijom, koji dopuštaju programeru da kontroliše format izvršnog programa koji se konstruiše iz individualnih modula.
Linker ima tri osnovna zadatka:
1) Pronalazk modula koji će se linkovati.
2) Uklapanje između referenci na spoljašnje ime (eng. external reference - spoljašnja referenca) i modula koji sadrži definiciju koja odgovara tom imenu.
3) Konstruisanje izvršnog koda kombinovanjem svih objektnih modula u jedan program.
Da bi dopustio linkeru da reši zadatak povezivanja između deklaracija i definicija, asembler neće dodeljivati vrednosti svim adresama koje se koriste u asemblerskom programu. Naravno, programe može, korišćenjem prethodno opisanih pseudoinstrukcija, narediti asembleru da konkretna simbolička adresa dobije određenu vrednost.
Dakle, po asembliranju modula neke vrednosti segmenta i ofseta mogu biti označene kao relokabilne, tj. može biti omogućeno linkeru da odredi aktuelnu adresu.
Primer.
Sledeći dijagram ukazuje na rad linkera u povezivanju dva modula:
Procesor 80386 nema ugrađene mogućnosti za rad sa brojevima u pokretnom zarezu (eng. floating point - plutajuća tačka). Jedan od puteva za obezbeđenje takvog rada je pisanje biblioteke podprograma koje implementiraju različite aritmetičke operacije. Međutim, aritmetika u pokretnom zarezu će biti bitno ubrzana korišćenjem specijalizovanog hardvera. Takav hardver je INTEL-ov čip 80387.
Matematički procesor (ili koprocesor) 80387 izvršava operacije u pokretnom zarezu mnogo brže nego odgovarajuće rutine procesora 80386. Asemblerski programeri mogu uključiti instrukcije procesora 80387 u programe pisane za procesor 80386, baš kao da su to instrukcije procesora 80386. Kada procesor 80386 “naiđe” na instrukciju koprocesora, ta instrukcija biva prosleđena na izvršenje koprocesoru 80387. Na asemblerskom nivou, sve instrukcije procesora 80387 počinju slovom f (eng .fast - brz).
[ta se dešava kada procesor 80386 “naiđe” na instrukciju za procesor 80387, a koprocesora 80387 nema u računaru? U tom slučaju procesor predaje kontrolu programu za rukovanje sa izuzecima, koji je kreiran od strrane operativnog sistema. INTEL je obezbedio rutinu za obradu izuzetaka pod nazivom E80387 koja softverski emulira rad procesora 80387. Korišćenjem ovakve rutine, program radi kao da je prisutan procesor 80387, samo dosta sporije.
Procesori 8087 i 80287 su neposredni prethodnici procesora 80387. Razlike između procesora 80387 i njegovih prethodnika su nastale ne samo usled razvoja tehnologije, već i zbog toga što je u vreme nastanka procesora 80387 organizacija IEEE usvojila i propisala standard za računanje sa brojevima u pokretnom zarezu. Dizajneri koprocesora 80387 su u potpunosti ispoštovali taj standard.
U zapisu broja u pokretnom zarezu razlikuju se: znak broja, eksponent (ili izložilac) i mantisa.
Ovakav zapis broja ne mora biti jednoznačan, pa se stoga obično nameće pravilo da mantisa ima oblik X.XXXX...X, pri čemu je X oznaka za cifru brojnog sistema. Mantisa ovakvog oblika naziva se normalizovana mantisa, a broj sa normalizovanom mantisom je broj u normalizovanom obliku, ili normalizovan broj. Ostali načini zapisa tog istog broja se nazivaju nenormalizovani.
Kod procesora 80387 broj se takođe sastoji od znaka, eksponenta i mantise, pri čemu je osnova brojnog sistema 2.
Ovaj procesor radi sa brojevima u pokretnom zarezu, koji mogu biti zapamćeni u nekom od sledećih formata: jednostruka preciznost (eng. single precision), dvostruka preciznost (eng. double precision) i raširena preciznost (eng. extended precision).
Sledeći dijagram ukazuje sa kojim sve formatima brojeva radi procesor 80387 i koje bitovne pozicije zauzimaju znak broja, eksponent i mantisa.
|
1 |
8 |
23 |
|
||||
jednostruka preciznost |
Z |
E |
M |
(4 bajta) |
||||
|
1 |
11 |
52 |
|
||||
dvostruka preciznost |
Z |
E |
M |
(8 bajtova) |
||||
|
1 |
15 |
64 |
|
||||
raširena preciznost |
Z |
E |
M |
(10 bajtova) |
||||
Zapis pojedinih elemenata koji obrazuju broj u pokretnom zarezu (eksponenta i mantise) je isti kao zapis brojeva u fiksnom zarezu: krajnje levo se nalazi mesto naveće težine, a udesno se značaj, tj. težina mesta smanjuje. Istu intuiciju sledi i razmeštaj bitovnih polja u koje se zapisuju mantisa, eksponent i znak broja u pokretnom zarezu: najznačajniji delovi (tj. oni delovi čija eventualna izmena najviše utiče na vrednost broja) smeštaju se krajnje levo, nešto manje značajni delovi se smeštaju desno od njih, a krajnje desno se smeštaju namanje značajni delovi zapisa broja.
Na prethodnom dijagramu je polje za znak označeno sa slovom Z. Ako je broj pozitivan, u polju za znak će biti nula. Ako je broj negativan, u polju za znak će biti smeštena jedinica. Zbog toga kod procesora 80387 postoje dve nule, +0 i -0, alli je to “skriveno” od programera.
Primer.
Iako se bitovni zapisi broja +0 i -0 razlikuju, instrukcija poređenja kod procesora 80387 postavlja bitove u ćelijama svojih registara kao da su ta dva broja isti.
Već je istaknuto da je mantisa normalizovana, i da je oblika 1.XX..XX, pri čemu je XΚ0, 1ć (zapisuje se normalizovani broj, pa ispred decimalne tačke mora biti nenula cifra - dakle 1).
Da bi postigli najveću tačnost (preciznost), potrebno je da se u ograničenom prostoru predviđenom za mantisu smesti što je moguće više cifara. Pametnim izborom normalizovane mantise izbegnuto je smeštanje vodećih nula, a ispostavlja se da se ne mora smeštati ni celobrojni deo mantise. Bit koji predstavlja ceo deo mantise mora biti 1. Taj bit se ne pamti u okviru mantise i zato se zove implicitni bit.
Zbog više razloga (jedan je brzina izvršavanja operacije, drugi je to što je prostor dovoljno veliki za postizanje tačnosti) trik sa implicitnim bitom se ne primenjuje kod mantisa brojeva u raširenoj tačnosti.
Osnova brojnog sistema kod eksponenta je, naravno,
2. Sadržaj polja se tumači kao neoznačeni broj. Kako eksponent može
biti i negativan, to se eksponent pamti tako što se na njegovu stvarnu vrednost
doda pozitivna konstanta bias (eng. bias - kosina , predrasuda). Veličina
konstane bias zavisi od formata datog broja u pokretnom zarezu. Veličina
bias-a se određuje tako da u polju za izložilac uvek bude pozitivna
vrednost - pa ona direktno zavisi od širine bitovnog polja u koje se smešta
eksponent. Za broj u jednostrukoj tačnosti veličina bias-a iznosi
Primer.
Ako broja u jednostrukoj tačnosti ima eksponent čija je vrednost 5, tada se u polju za ekponsnt nalaze bitovi 10000100B =132D.
Ako je vrednost eksponenta broja u jednostrukoj tačnosti -5, tada se u polju za ekponsnt nalaze bitovi 1111010B =122D.
Kod procesora 80387 je korišćenje najmanjeg i najvećeg eksponenta rezervisano za rukovanje greškama.
Vrednost broja u jednostrukoj tačnosti, čiji je zapis ze1e2...e7e8m1m2... m22m23 data je sledećim izrazom:
Vrednost broja u dvostrukoj tačnosti, čiji je zapis ze1e2...e10e11m1m2... m51m52 data je sledećim izrazom:
Vrednost broja u dvoostrukoj tačnosti, čiji je zapis ze1e2...e14e15m1m2... m63m64 data je sledećim izrazom:
Primer.
^etiri bajta
1 |
1011đ1111đ01011đ1111đ0 |
110đ0000đ0000đ0000đ0000đ0000 |
će, ako se tumače kao broj u pokretnom zarezu, sa jednostrukom preciznošću, imati Z=1, E=126, M=11000000000000000000000, pa je odgovarajuća vrednost broja u pokretnom zarezu
Veličine brojeva u pokretnom zarezu opisane su sledećom tabelom:
Format broja |
Značajne cifre |
Najmanji stepen broja 10 |
Najveći stepen broja 10 |
Jednostruka preciznost |
6 |
-37 |
38 |
Dvostruka preciznost |
15 |
-307 |
308 |
Raširena preciznost |
19 |
-4931 |
4932 |
Iz prethodne tabele direktno sledi da jednostruka preciznost garantuje samo 6 cifara. Stoga, jednostruku tačnost treba koristiti samo kada prostor predstavlja izuzetno snažan limitirajući faktor.
Budući da procesor 80387 interno operiše sa brojevima u raširenoj tačnosti, svi brojevi sa kojima se radi će prvo biti konvertovani u raširenu prreciznost. Prema tome, rad sa brojevima u jednostrukoj tačnosti neće biti mnogo brži od rada sa brojevima u dvostrukoj tačnosti. Uočava se da je kod formmata dvostruke tačnosti uvećana veličina prostora za eksponent (uvećani su i tačnost i opseg), što kod nekih računara nije bio slučaj. Povećanjem veličine izlložioca postignuto je da broj u formatu dvostruke tačnosti može, bez gubitka preciznosti i bez greške, prihvatiti proizvod dva broja u jednostrukoj tačnosti.
Svrha postojanja brojeva u raširenoj tačnosti je čuvanje privremenih rezultata, kako bi se omoguućilo dobijanje korektnog krajnjeg rezultata u dvostrukoj tačnosti.
Primer.
Izračunavanjem funkcije , gde su x i y u dvostrukoj tačnosti, trebalo bi da se dobije z u dvostrukoj tačnosti. Međutim, tu dvostruku tačnost je teško garantovati bez korišćenja formata raširene tačnosti za smeštaj privremenih rezultata.
Neka je . Tu je z završni rezultat, a privremeni rezultat.
Ukoliko se razdvoji na ceo i razlomljeni deo, tj. , tada je .
Kako je to je značajni deo normalizovane reprezentacije broja z, a i je eksponenet. Budući da krajnji rezultat z treba biti u dvostrukoj tačnosti, to i zahteva 11 bitova, dok f zahteva 53 bita. Dakle, međurezultat i+f zahteva 64 bita.
Još se postavlja pitanje: zašto je dužina broja u raširenoj tačnosti 80 bitova (deset bajtova) a ne neki stepen dvojke?
Jedan razlog za takvu realizaciju je što bi izbor stepena dvojke zahtevao više aritmetičkog hardvera, illi bi se sa postojećim hardverom postizale slabije performanse. Drudi razlog je to što, kako je u prethodnom primeru pokazano, deset bajtova predstavlja dovoljan prostor za čuvanje privremenih rezultata tako da krajnji rezultat (čak i u dvostrukoj tačnosti) ne izgubi preciznost.
Intervali brojeva u pokretnom zarezu, za sva tri formata, opisani su sledećom tabelom”
|
najmanji negativan |
najveći negativan |
najmanji pozitivan |
najveći pozitivan |
||||||||
|
|
|
|
|
||||||||
jednostruka tačnost |
1 |
1 ...10 |
11 ... 1 |
1 |
0 ...01 |
00... 0 |
0 |
0 ...01 |
00... 0 |
0 |
1 ...10 |
11 ... 1 |
|
-3.37 1038 |
-1.17 10-38 |
1.17 10-38 |
3.37 1038 |
||||||||
|
|
|
|
|
||||||||
dvostruka tačnost |
1 |
1 ...10 |
11 ... 1 |
1 |
0 ...01 |
00... 0 |
0 |
0 ...01 |
00... 0 |
0 |
1 ...10 |
11 ... 1 |
|
-1.67 10308 |
-2.23 10-308 |
2.23 10-308 |
1.67 10308 |
||||||||
|
|
|
|
|
||||||||
raširena tačnost |
1 |
1 ...10 |
11 ... 1 |
1 |
0 ...01 |
00... 0 |
0 |
0 ...01 |
00... 0 |
0 |
1 ...10 |
11 ... 1 |
|
-1.2 104932 |
-3.37 10-4932 |
3.37 10-4932 |
1.2 104932 |
Pri tome se broj 0, bez obzira da li se radi o -0 ili o +0, u svakom od ovih formata predstavlja tako što polje za eksponent i polje za mantisu sadrže isključivo nule.
Numerički izuzeci (eng. exception - izuzetak) koji se mogu dogoditi pri radu sa procesorom 80387, grubo rangirani po učestanosti, su:
Netačan rezultat (eng. inexact result) - ovakvo stanje nastaje kada rezultat operacije sa brojevima u pokretnom zarezu ne može biti precizno smešten u željenom odredišnom formatu. Mnogi korisnici aritmetike u pokretnom zarezu neće smatrati da je netačan rezultat greška i očekivaće da automatski bude primenjena neka vrsta rezanja ili zaolruživanja.
Numeričko podkoračenje (eng. numerical underflow)
- ono nastupa kada je nenula rezultat toliko
Numeričko prekoračenje (eng. numerical overflow) - nastaje kada je rezultat suviše veliki po modulu, tako da isti ne može biti predstavljen.
Deljenje sa nulom (eng. divide by zero) - nastupa kada je vrši operacija deljenja, pri čemu je delilac nula.
Nenormalizovani operand (eng. denormalized operand) - nastupa kada se vrši operacija sa nenormalizovanim operandom.
Invalidna operacija (eng. invalid operation) -- ova kategorija izuzetaka uključuje sve preostale izuzetke (npr. deljenje nule nulom, kvadratni koren negativnog broja, pokušaji koriš]enja nepostojećih i praznih registara procesora 80387, itd.).
Najčešće se koristi jedan od sledeća dva metoda za rad sa greškama:
Suspendovanje, hvatanje u zamku (eng. trapping - hvatanje u zamku): prekida se izvršavanje operacija ukoliko je uslov zadovoljen.
Prosleđivanje specijalnih vrednosti grešaka, odnosno vrednosti izuzetaka.
Razlozi protiv korišćenja drugog metoda:
1. Vrednost greške mora biti različita od uobičajenih vrednosti.
2. Kad god program sadrži uslovan skok baziran na poređenju, mora se razmotriti mogućnost da je jedan od operanada pri poređenju baš vrednost koja indicira grešku. Realizacija takvih razmatranja dodatno komplikuje kod.
3. Postupak dibagirnja programa se usložnjava i otežava sa udaljavanjem izvora greške od mesta prekida rada.
Razlozi koji, u konkretnom radu sa procesorom 80387, ohrabruju korišćenje drugog metoda:
1. Procesor 80387 dopušta vrednosti grešaka, tj. vrednosti izuzetaka, ukoliko je eksponent 0...0 ili 1...1.
2. Poređenje brojeva u pokretnom zarezu je mnogo ređe od poređenja brojeva u fiksnom zarezu.
3. Može se dogoditi da, dođe do greške u izračunavanju međurezultata, a da vrednost krajneg rezultata ipak bude korektna.
Tu spadaju: celobrojna reč (eng. word integer), kratak ceo broj (eng. short integer), dugi ceo broj (eng. long integer) i pakovani dekadni broj (eng. packed decimal).
Sledeći dijagram prikazuje sve celobrojne formate koje podržava procesor 80387:
|
16 |
|
|||||||||
celobrojna reč |
|
(2 bajta) |
|||||||||
|
32 |
|
|||||||||
kratki ceo brojt |
|
(4 bajta) |
|||||||||
|
64 |
|
|||||||||
dugi ceo broj |
|
(8 bajtova) |
|||||||||
|
1 |
7 |
72 |
|
|||||||
pakovani dekadni broj |
Z |
0...0 |
D17 |
D16 |
... |
D1 |
D0 |
(10 bajtova) |
|
||
Ovi celi brojevi se, sem poslednjeg formata, čuvaju u potpunom komplementu.
Postavlja se pitanje: čemu služe ovi formati, kad se zna da je procesor 80387 prvenstveno dizajniran za rad sa brojevima u pokretnom zarezu?
Ovi formati se najčešće koriste za konverzije između celih brojeva i brojeva u pokretnom zarezu. Te konverzije se moraju vršiti pri izraačnavanjima u kojima su pomešane obe vrste brojeva.
Procesor 80387 dopunjava rad procesora 80386. I ovaj procesor mnog brže operiše sa podacima koji se nalaze u registrima, nego sa brojevima koji su u memoriji.
Procesor 80387 sadrži registre, nazvane numerički registri, koji su korisni za računanje u pokretnom zarezu. Oni služe za smeštaj argumenata i međurezultata i sadrže isključivo brojeve u raširenoj tačnosti.
Ti registri su prikazani na sledećoj shemi:
|
80 |
R0: |
|
R1: |
|
R2: |
|
R3: |
|
R4: |
|
R5: |
|
R6: |
|
R7: |
|
Iako svaki od ovih registara ima svoju oznaku, instrukcije procesora 80387 su dizajnirane tako da olakšavaju (pomalo neuobičajen) stek-orjentisan pristup numeričkim registrima. Naime, broj numeričkog registra specificiran u instrukciji procesora 80387 se uvek sabira sa sadržajem trobitnog polja ST (eng. stack top - vrh steka) koje se nalazi u okviru statusnog registra procesora 80387. Tako dobijena suma, po modulu 8, određuje koji će se numerički registar zbilja koristiti. Na ovaj način se skup memoriskih registara vidi kao stek, kao što i ilustruje naredni dijagram:
R0: |
|
ST(5) |
|
R1: |
|
ST(6) |
|
3 |
R2: |
|
ST(7) |
ST |
R3: |
vrh steka |
ST(0) |
R4: |
prvi ispod vrha steka |
ST(1) |
|
R5: |
|
ST(2) |
|
R6: |
|
ST(3) |
|
R7: |
|
ST(4) |
Dizajneri procesora 80387 su smatrali da većina programera želi korišćenje numeričkih registara u stek maniru, i zbog toga najveći broj instukcija procesora 80387 tokom svog izvršenja modifikuje i bitovno polje ST.
Zbog ovakvog načina pristupa registrima, nadalje će skup numeričkih registrara često biti nazivan registarski stek.
Kontrolni registar je 16-bitni registar. On sadrži polja čije vrednosti modifikuju celokupno ponašanje procesora 80387.
|
|
|
12 |
11 |
10 |
9 |
8 |
|
|
5 |
4 |
3 |
2 |
1 |
0 |
|
|
|
IC |
R |
C |
P |
C |
|
|
PM |
UM |
|
ZM |
DM |
IM |
Pet bitova najmanje težine služe za maskiranje izuzetaka. Izuzeci koji mogu nastupiti tokom rada procesora 80387 su opisani u prethodnom poglavlju.
IM - maska invalidne operacije (eng. invalid operation mask).
DM - maska nenormalizovanog operatora (eng. denormalized operator mask).
ZM - maska deljenja sa nulom (eng. zero mask).
UM - maska numeričkog podkoračenja (eng. underflow mask).
PM - maska netačnog rezultata (eng. precision mask).
Ako je bit maske nula, tada će događanje odgovarajućeg izuzetka dovesti do suspenzije rada programa i do izvršenja odgovarajućeg prekida. Ukoliko je bit maske postavljen, tada se odgovarajući izuzetak maskiran i nastavlja se rad.
PC - dvobitno polje kontrole preciznosti (eng. precision control) koje ukazuje na koju će tačnost biti zaokruženi rezultati. Za PC=11 zaokruživanje će se vršiti na raširenu tačanost, i to je podrazumevano ponašanje. Ako je PC=10, rezulatat će biti zaokružen na dvostruku precianost. Ukoliko je PC=00, vrši se zaokruživanje na jednostruku preciznoat.
Ovo polje postoji iz dva razloga. Prvi razlog je omogućavanje nesmetanog izvršavanja programa pisanih za pretke ovog procesora.Takvi programi mogu sadržavati trikove koji su bazirani na nižoj preciznosti. Drugi razlog je prilagođavanje onim jezicima visokog nivoa koji za me”urezultate zahtevaju upravo takvu preciznost.
RC - dvobitno polje kontrole zaokruživanja (eng. rounding control) koje ukazuje na koji način će se zaokruženi rezultati. Za PC=00 zaokruživanje će se vršiti prema najbližem, i to je podrazumevano ponašanje. Ako je PC=01, rezulatat će biti zaokružen naniže (prema -Ą), a za PC=10, rezulatat će biti zaokružen naviše (prema +Ą). Ukoliko je PC=11, vrši se zaokruživanje prema nuli.
IC - kontrola beskonačnosti (eng. infinity control) koje je ostalo zbog kompatibilnosti sa prethodnicima. Ovo jednobitno oplje određije da li je beskonačnost afina ili projektivna. Kod procesora 80387 u ovom polju mora biti 1, što označava afinu beskonačnost.
Statusni registar je registar dužine 16. On sadrži polja koja odslikavaju uslove u kojima 80387 obično ne menja svoje ponašanje.
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
B |
C3 |
|
ST |
|
C2 |
C1 |
C0 |
ES |
SF |
PE |
UE |
OE |
ZE |
DE |
IE |
Pet bitova najmanje težine služe za indiciranje izuzetaka.
IE - izuzetak invalidne operacije (eng. invalid operation exception).
DE - izuzetak nenormalizovanog operatora (eng. denormalized operator exception).
ZE - izuzetak deljenja sa nulom (eng. zero exception).
OE - izuzetak numeričkog prekoračenja (eng. overflow exception).
UE - izuzetak numeričkog podkoračenja (eng. underflow exception).
PE - izuzetak netačnog rezultata (eng. precision exception).
SF - greška steka (eng. stack fault) - ukazuje da li je do generisanja izuzetka došlo zbog nekorektnog rada sa procesorskim stekom.
Dakle, na bitovnim pozicijama 0-6 se nalaze flegovi izuzetaka. Kada dođe do izuzetka (bilo maskirranog ili nemaskiranog) tada se odgovarajući fleg u ovom registru postavi na 1.
ES - fleg zbirne greške (eng. error sumary flag) - postavlja se u slučaju ma koje greške.
C0, C1, C2, C3 - sadrže uslovne kodove (eng. condition - uslov) zasnovane na poređenju ili deljenju sa ostatkom. Sama interpretacija uslovnog koda zavisi od instrukcije koja se konkretno izvršava i biće razmatrana pri razmatranju tih instrukcija.
B - fleg zauzetosti (eng. busy - zauzet) postavljen je kad god procesor 387 izvršava instrukciju signaliziranja ili prekida. Ovaj fleg je 0 kad god je procesor 80387 slobodan.
Ovaj 16-bitni registar se koristi interno kod procesora 80387 za sumarni prikaz sadržaja numeričkih registara, a u cilju optimizacije performansi i radi detekcije izuzetaka.
15 |
14 |
13 |
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
||||||||||||||||
|
Ta |
g7 |
Ta |
g6 |
Ta |
g5 |
Ta |
g4 |
Ta |
g3 |
Ta |
g2 |
Ta |
g1 |
Ta |
g0 |
||||||||||||||||
Tag registar sadrži osam dvobitnih polja. Svako polje odgovara jednom od numeričkih registara. Ako je sadržaj polja 00, to znači da je sadržaj odgovarajućeg registra validan. Ako je sadržaj dvobitnog polja 01, u odgovarajućem registru je nula. Ukoliko bitovno polje sadrži 10, sadržaj registra je invalidan, a ako bitovno polje sadrži 11, registar je prazan.
Registri sa tagom “prazan” su ili neinicijalizovani, ili skinuti sa steka numeričkih registara. Procesor 80387 koristi tag “prazan” za otkrivanje prekoračenja i podkoračenja steka.
Ovi registri obezeđuju memorijske adrese za posllednju korišćenu 387 instrukciju i za memorijski operator, ukoliko taj operator postoji. Ove informacije su od značaja programima za rukovanje izuzecima (eng. exception handler - rukovalac izuzecima).
Svi opkodovi za procesor 80387 počinju sa istih pet bitova, koji upozoravaju procesor 80386 da te instrukcije on ne izvršava. Stoga, svi mnemonci opkodova procesora 80387 počinju sa slovom F (eng. fast - brz). Pri radu su dopušteni svi uobičajeni adresni modovi procesora 80386.
Primer.
Različiti načini adresiranja kod instrukcija za 80387:
FADD IME
FADD W[EBX]
FADD IME[EBX][ESI]
Asembler je u mogućnosti da implictno detektuje veličinu (tj. tačnost) memorijskog operanda jer ima informaciju o korišćenju neke od pseudoinstrukcija DD, DQ, DT.
Najveći broj instrukcija ima formate koji
referišu na registarski stek. Takav format je ST(i), što ožnačava i-ti
element ispod vrha registarskog steka. Registru na vrhu steka se može
pristupiti
Ovim instrukcijama se realizuje premeštanje iz memorije u numeričke registre, iz numeričkih registara u memoriju i između numeričkih registara.
FLD S (eng. fast load - brzo ucitaj)
FILD S (eng fast integer load - brzo ucitaj ceo broj)
FBLD S (eng fast BCD load - brzo ucitaj BCD broj)
FSTP D (eng. fast store and pop - brzo smesti i skini)
FISTP D (eng. fast integer store and pop - brzo smesti i skini ceo broj)
FBSTP D (eng. fast BCD store and pop - brzo smesti i skini BCD broj)
FST D (eng. fast store - brzo smesti)
FIST D (eng. fast integer store - brzo smesti ceo broj)
FXCH D (eng. fast exchange - brzo razmeni)
FLDZ (eng. fast load zero - brzo ucitaj nulu)
FLD1 (eng. fast load one - brzo ucitaj jedinicu)
FLDPI (eng. fast load pi - brzo ucitaj p)
FLDLG2 (eng. fast load log102 - brzo ucitaj jedinicu log102)
FLDLN2 (eng. fast load ln2- brzo ucitaj jedinicu ln2)
FLDL2T (eng. fast load log210 - brzo ucitaj jedinicu log210)
FLDL2E (eng. fast load log2e - brzo ucitaj jedinicu log2e)
^etiri osnovne binarne aritmetičkle operacije su sabiranje, oduzimanje, množenje i delljenje.
Kod aritmetičkih instrukcija za 80387, jedan od operandad mora biti vrh registarskog steka. Instrukcije se javljaju u jednoj od sledećih formi:
Fxxx - instrukcija se odnosi na vrh registarskog steka i elemenat nepostedno ispod vrha.
Fxxx <mem> - instrukcija se odnosi na vrh registarskog steka i memorijsku lokaciju.
FIxxx <mem> - instrukcija se odnosi na vrh registarskog steka i memorijsku lokaciju, pri čemu se radi sa celim brojevima.
Niska xxx može uzeti vrednosti: ADD, SUB, MUL, DIV, SUBR (eng. subtract reversed - obratno oduzimanje), DIVR (eng divide reversed - obratno deljenje)
Ovim instrukcijama se, na osnovu vrednosti operanda, postavljaju neki od bitova statusnog registra.
FCOM (eng. fast compare - brzo uporedi)
FUCOM (eng. fast unordered compare - brzo neuređeno uporedi)
FICOM (eng. fast integer compare - brzo uporedi cele brojeve)
FCOMP (eng. fast compare and pop - brzo uporedi i skini)
FUCOMP (eng. fast unordered compare and pop - brzo neuređeno uporedi i skini)
FICOMP (eng. fast integer compare and pop - brzo uporedi cele brojeve i skini)
FCOMPP (eng. fast compare and pop twice - brzo uporedi i dvaput skini)
FUCOMPP (eng. fast unordered compare and pop twice - brzo neuređeno uporedi i dvaput skini)
FTST (eng. fast test - brzo testiraj, uporedi sa nulom)
Pri poređenju se bitovi statusnog registra postavljaju na sledeći način:
C3 |
C0 |
uslov |
0 |
0 |
ST(0)>x |
0 |
1 |
ST(0)<x |
1 |
0 |
ST(0)=x |
1 |
1 |
neuređeno |
Napomena.
Instrukcija FSTSW AX, uvedena kod procesora 80287 omogućuje da se statusna reč koprocesora smesti u registar AX, a potom se lako mogu testirati postavljanja bitova.
Ako bi se, izvršenjem instrukcije LAHF sadržaj AH prebacio u registar flegova, tada bi bitu C0 odgovarao CF, a bitu C3 odgovara ZF.