Programátor pri svojej činnosti potrebuje nie len presuny dát. V každom programe sú nutné
i výpočty a to s bežnými dátami, alebo s adresami. Tie v assembleri prevádzajú
len s celými číslami. Operácie s desatinnými číslami sú zdĺhavé, i keď
sú uskutočniteľné pomocou určitých algoritmov. ASM86 pre ne ale nemá inštrukcie.
Väčšina matematických operácií sa prevádza s číslami v registroch alebo
v pamäti. Označenie operandov je zhodné ako pri presunoch. Zároveň tieto
inštrukcie nastavujú indikátory registru F. Umožnia tak vetviť program.
Informácie o nastavovaných indikátoroch nájdeme v tabuľke inštrukcií (+).
Sčítanie
Pri tvorbe programu si musíme ujasniť, či chceme k cieľovému miestu pričítať 1, alebo iné číslo.
Podľa toho volíme inštrukciu:
-
INC cieľ - k cieľu pričítaj jedna (register, pamäť)
-
ADD cieľ, zdroj - k cieľu pričítaj zdroj (register - hodnota, pamäť -hodnota, register
- register, pamäť - register, register - pamäť)
-
ADC cieľ, zdroj - rovnako ako ADD, ale pričítaj i bit CF (prenos)
Príklady:
INC AX - pričítaj k registru AX hodnotu 1
INC WORD
PTR [BX] - pričítaj k slovu na adrese určenej DS:BX hodnotu 1
INC BYTEPTR
CS:[adresa] - pričítaj k slabike na adrese určenej CS:adresa (konštantná)
1
SEGESINC BYTE [DI + 2] - pričítaj k slabike na adrese ES:DI + 2 hodnotu 1
ADD AX, BX - k slovu v registri AX pričítaj obsah registra BX (slovo)
ADD AH, 8 - k slabike v registri AH pričítaj číslo 8}
SEGCSADD DX, WORD PTR [BX] - k registru DX pričítaj slovo na adrese CS:BX
ADD premenná, 5 - k deklarovanej premennej pričítaj 5
ADD BYTEPTR [SI], 30 - k slabike na adrese DS:SI pričítaj 30}
ADD BYTEPTR ES:[BP], AL - k slabike na adrese ES:BP pričítaj obsah registra AL
Pokiaľ pri týchto operáciách dôjde k preplneniu cieľa, nastaví sa register OF do log. 1.
Aby pri odlaďovaní vašich programov nedošlo k zbytočným hádkam s prekladačom,
uvedomte si, že zdroj i cieľ musia mať rovnaký počet bitov (tzn. 8, alebo 16).
Odčítanie
Inštrukcie slúžiace k odčítaniu sú zápisom operandov zhodné s inštrukciami pre sčítanie. Preto
si uvedieme len ich zoznam:
-
DEC cieľ - od cieľa odčítaj 1 (register, pamäť)
-
SUB cieľ, zdroj - od cieľa odčítaj zdroj (register - hodnota, pamäť - hodnota, register
- register, pamäť - register, register - pamäť)
-
SBB cieľ, zdroj - rovnako ako SUB, ale odčítaj i bit CF Príklady by boli zhodné so
sčítaním.
Napriek tomu sú tu špecifické inštrukcie:
-
NEG cieľ - otoč znamienko v cieli (register, pamäť)
-
CMP cieľ, zdroj - odčítaj bez zmeny cieľa, nastav len register F (register - hodnota,
pamäť - hodnota, register - register, pamäť - register, register - pamäť)
Inštrukcia CMP porovnáva dve čísla odčítaním. Pretože ale nedôjde k ich zmene, použijeme
túto inštrukciu pred vetvením programu. Za CMP totiž väčšinou nasledujú
inštrukcie skoku závislé na stave príznakov registra F.
#include <stdio.h>
#include <conio.h>
int a,b,s,r;
main () {
clrscr(); // vymaž obrazovku
printf("a=");
scanf("%d",&a); // vstup hodnoty a
printf("b=");
scanf("%d",&b); // vstup hodnoty b
asm { // začiatok bloku asm
MOV AX, a // do AX vlož hodnotu premennej a (z pamäte)
ADD AX,b // k AX pričítaj hodnotu premennej b
MOV s, AX // do premennej s vlož súčet z registra AX
MOV AX,a // znovu naber a
SUB AX,b // odčítaj od AX hodnotu b
MOV r,AX // do premennej r vlož rozdiel z registra AX
INC a // k a pričítaj 1
DEC b // od b odčítaj 1
} // koniec bloku asm
printf("\na+b=%d a-b=%d",s,r); // vypíš obsahy premenných
printf("\na+1=%d b-1=%d",a,b);
}
Uvedený príklad
ukazuje najjednoduchšie použitie inštrukcií ADD, SUB, INC,
DEC.
Všimnite si, že so zápismi adries premenných si nemusí programátor ani
moc lámať hlavu. V tom mu totiž pomáha prekladač C++.
Násobenie
I keď programátori
neradi používajú inštrukcie násobenia a delenia pre ich dlhú dobu prevádzania
(na procesore 8086, u iných procesorov je už rýchle), ASM86 ich má. Niekedy
dokonca neexistuje iná možnosť ako ich použiť. I tieto operácie sú definované
len na celých číslach. Rozlišujeme tiež, či ich prevádzame so znamienkom,
alebo bez znamienka.
-
MUL zdroj
- register AL vynásob so zdrojom (osembitový register, alebo pamäť) a výsledok
zapíš do registra AX (osembitové násobenie).
-
MUL zdroj
- register AX vynásob so zdrojom (šestnásťbitový register, alebo pamäť)
a výsledok (32 bitov zapíš do registrového páru DX,AX za sebou (šestnásťbitové
násobenie).
-
IMUL zdroj
- ako MUL ale násobenie so znamienkom IMUL cieľ,[zdroj,]konštanta
- [286], do cieľa vlož súčin zdroja a konštanty (šestnásťbitový register
- šestnásťbitový register - hodnota, šestnásťbitový register - slovo v
pamäti - hodnota, šestnásťbitový register - osembitová hodnota, to znamená
cieľ := zdroj * konštanta, alebo cieľ := cieľ * konštanta)
POZOR!, o koľkobitové
násobenie sa jedná určuje označenie miesta zdroje.
Delenie
Táto operácia je
jednou z najzdĺhavejších. Jej prevádzanie trvá (na 8086) až 190 periód
hodín (sčítanie trvá okolo 3 periód). Jeho výhodou je ale to, že je možné
zistiť ako výsledok po celočíselnom delení (DIV), tak i zvyšok po celočíselnom
delení (MOD). A to všetko len jednou inštrukciou.
-
DIV zdroj
- register AX vydeľ zdrojom (osembitový register, alebo pamäť) a podiel
ulož do AL, zvyšok po delení ulož do AH (Osembitové delenie)
-
DIV zdroj
- dvojslovo v registroch DX, AX vydeľ zdrojom (šestnásťbitový register,
alebo pamäť) a podiel ulož do AX, zvyšok po delení ulož do DX (Šestnásťbitové
delenie)
-
IDIV zdroj
- ako DIV ale delenie so znamienkom Použitie týchto inštrukcií je
podobné ako násobenie. Program si musíme ošetriť tak, aby nemohlo dôjsť
k deleniu nulou. Ak k nemu predsa dôjde, procesor zavolá prerušenie INT
0.
#include <stdio.h>
#include <conio.h>
unsigned char a,b,d,z;
unsigned int s;
main () {
clrscr();
printf("a=");
scanf("%d",&a);
printf("b=");
scanf("%d",&b);
asm {
MOV AL, a // do AL vlož hodnotu a
MUL b // vynásob hodnotou b (v pamäti)
MOV s, AX // do premennej s vlož súčin z registra AX
MOV AH, 0 // nuluj AH (číslo je len 8 bitové)
MOV AL, a // do AL vlož hodnotu a
DIV b // vydeľ premennou b
MOV d, AL // výsledok vlož do premennej d
MOV z, AH // zbytok pt delení vlož do premennej z
}
printf("\na*b=%d",s);
printf("\na div b=%d a mod b=%d",d,z);
}
Zmena počtu bitov
Často potrebujeme opraviť šestnásťbitové číslo na osembitové a naopak. Pri tejto zmene môže
ale dôjsť k strate informácie v prípade úbytku bitov. Prevod čísiel bez
znamienka prevedieme najjednoduchšie využitím pólenia registrov.
-
Slabika -> Slovo
Do šestnásťbitového
registra načítame do dolnej polovice slabiku. Hornú polovicu nulujeme.
Slovo potom načítame zo všetkých šestnástich bitov:
unsigned char b;
unsigned int w;
main() {
b = 10;
asm {
MOV AL, b // do AL osem bitov z premennej b
MOV AH, 0 // nuluj AH
MOV w, AX // do premennej w vlož všetkých šestnásť bitov
}
}
-
Slovo-> Slabika
Operácia je opačná.
Šestnásťbitové číslo vložíme do celého šestnásťbitového registra. Do slabiky
potom vložíme len spodných osem bitov. Ale pozor, tu môže dôjsť k strate
bitov v horných ôsmich bitoch. Pretože úprava čísel so znamienkami by bola
zložitá, prichádza opäť na pomoc ASM86 s inštrukciami:
-
CBW - preveď obsah AL do AX so zachovaním znamienka
-
CWD - preveď obsah AX do DX, AX (32 bitov) so zachovaním znamienka
Práca s číslami v kódu BCD
Čísla v BCD kódu môžu byť uložené v týchto formátoch:
-
Nezhustený tvar
V jednej slabike
je uložená jedna číslica v BCD kódu. Má hodnotu 0-9 a obsadzuje teda len
spodné 4 bity. Horná polovica slabiky je nulová (to sa doporučuje pre operácie
násobenia a delenia, pre sčítanie a odčítanie môže mať ľubovoľný obsah).
Tento tvar je vhodný pre prevod do kódu ASCII. Stačí len k slabike pričítať
číslo 48 (logický súčet s číslom 0x30).
-
Zhustený tvar
V jednej slabike
sú uložené dve BCD číslice. Spodné 4 bity nesú hodnotu nižšieho rádu (jednotky),
horní 4 nesú hodnotu vyššieho rádu (desiatky). Do slabiky ide teda uložiť
číslo v rozsahu 0-99. ASM86 nepodporuje priamo matematické operácie s takto
kódovanými číslami. Napriek tomu o obsahuje inštrukcie pre ich úpravu po
prevedení bežných operácií určených pre čísla v prirodzenom dvojkovom kóde
(obyčajné dvojkovo uložené číslo). V ASM86 nájdeme i inštrukcie, ktoré
pre tieto operácie čísla v BCD kódu pripravia. Jedná sa o inštrukcie: AAA,
AAD,
AAM, AAS, DAA, DAS (bližšie informácie v tabuľke
inštrukcií).