Aritmetické instrukce
Programátor při své činnosti
potřebuje nejen přesuny dat. V každém programu jsou nutné i
výpočty a to s běžnými daty, nebo s adresami. Ty se v
assembleru provádějí jen s celými čísly. Operace s
desetinnými čísly jsou zdlouhavé, i když jsou proveditelné
pomocí určitých algoritmů. ASM86 pro ně ale nemá instrukce.
Většina matematických operací se provádí s čísly v
registrech nebo v paměti. Označení operandů je shodné jako
při přesunech. Zároveň tyto instrukce nastavují indikátory
registru F. Umožní tak větvit program. Informace o
nastavovaných indikátorech najdeme v tabulce instrukcí (+).
Sčítání
Při tvorbě programu si musíme
ujasnit, jestli chceme k cílovému místu přičíst 1, nebo
jiné číslo. Podle toho volíme instrukci:
- INC cíl - k
cíli přičti jedna (registr, paměť)
- ADD cíl,
zdroj - k cíli přičti zdroj (registr - hodnota,
paměť -hodnota, registr - registr, paměť - registr,
registr - paměť)
- ADC cíl,
zdroj - stejně jako ADD, ale přičti i
bit CF (přenos)
Příklady:
INC AX - přičti
k registru AX hodnotu 1
INC WORD PTR
[BX] - přičti k slovu na adrese určené DS:BX hodnotu 1
INC BYTE PTR
CS:[adresa] - přičti k slabice na adrese určené CS:adresa
(konstantní) 1
SEGES INC BYTE
[DI + 2] - přičti k slabice na adrese ES:DI + 2 hodnotu 1
ADD AX, BX - ke slovu v registru AX přičti
obsah registru BX (slovo)
ADD AH, 8 - k slabice v registru AH přičti
číslo 8}
SEGCS ADD DX, WORD
PTR [BX] - k registru DX přičti slovo na
adrese CS:BX
ADD promenna, 5 - k deklarované proměnné
přičti 5
ADD BYTE PTR
[SI], 30 - k slabice na adrese DS:SI přičti 30}
ADD BYTE PTR
ES:[BP], AL - k slabice na adrese ES:BP přičti obsah registru
AL
Pokud při těchto operacích
dojde k přeplnění cíle, nastaví se registr OF do log. 1. Aby
při odlaďování vašich programů nedošlo ke zbytečným
hádkám s překladačem, uvědomte si, že zdroj i cíl musí
mít stejný počet bitů (tzn. 8, nebo 16).
Odčítání
Instrukce sloužící k
odčítání jsou zápisem operandů shodné s instrukcemi pro
sčítání. Proto si uvedeme jen jejich seznam:
- DEC cíl - d
cíle odečti 1 (registr, paměť)
- SUB cíl,
zdroj - od cíle odečti zdroj (registr - hodnota,
paměť - hodnota, registr - registr, paměť - registr,
registr - paměť)
- SBB cíl,
zdroj - stejně jako SUB, ale odečti i bit CF Příklady
by byly shodné se sčítáním.
Přesto jsou zde specifické
instrukce:
- NEG cíl -
otoč znaménko v cíli (registr, paměť)
- CMP cíl,
zdroj - odečti bez změny cíle, nastav jen registr F
(registr - hodnota, paměť - hodnota, registr - registr,
paměť - registr, registr - paměť)
Instrukce CMP
porovnává dvě čísla odečtením. Protože ale nedojde k
jejich změně, použijeme tuto instrukci před větvením
programu. Za CMP totiž většinou následu+jí
instrukce skoku závislé na stavu příznaků registru F.
Příklad:
uses crt;
var a,b,s,r:integer;
begin
clrscr; {vymaž obrazovku}
write ('a=');
readln(a); {vstup hodnoty a}
write ('b=');
readln(b); {vstup hodnoty b}
asm {začátek bloku asm}
MOV AX, a {do AX vlož hodnotu proměnné a (z paměti)}
ADD AX,b {k AX přičti hodnotu proměnné b}
MOV s, AX {do proměnné s vlož součet z registru AX}
MOV AX,a {znovu naber a}
SUB AX,b {odečti od AX hodnotu b}
MOV r,AX {do proměnné r vlož rozdíl z registru AX}
INC a {k a přičti 1}
DEC b {od b odečti 1}
end; {konec bloku asm}
writeln ('a+b=',s,' a-b=',r);{vypiš obsahy proměnných}
writeln ('a+1=',a,' b-1=',b);
end.
Uvedený příklad ukazuje
nejjednodušší použití instrukcí ADD, SUB,
INC, DEC. Všimněte si, že se
zápisy adres proměnných si nemusí programátor ani moc lámat
hlavu. V tom mu totiž pomáhá překladač Pascalu.
Násobení
I když programátoři neradi
používají instrukce násobení a dělení pro jejich dlouhou
dobu provádění (na procesoru 8086, u jiných procesorů je už
rychlé), ASM86 je má. Někdy dokonce neexistuje jiná možnost
než je použít. I tyto operace jsou definovány jen na celých
číslech. Rozlišujeme také, jestli je provádíme se
znaménkem, nebo bez znaménka.
- MUL zdroj -
registr AL vynásob se zdrojem (osmibitový registr, nebo
paměť) a výsledek zapiš do registru AX (osmibitové
násobení).
- MUL zdroj -
registr AX vynásob se zdrojem (šestnáctibitový
registr, nebo paměť) a výsledek (32 bitů) zapiš do
registrového páru DX,AX za sebou (šestnáctibitové
násobení).
- IMUL zdroj -
jako MUL ale násobení se znaménkem IMUL
cíl,[zdroj,]konstanta - [286], do cíle vlož součin
zdroje a konstanty (šestnáctibitový registr -
šestnáctibitový registr - hodnota, šestnáctibitový
registr - slovo v paměti - hodnota, šestnáctibitový
registr - osmibitová hodnota, to znamená cíl := zdroj
* konstanta, nebo cíl := cíl * konstanta)
POZOR!, o kolikabitové násobení
se jedná určuje označení místa zdroje.
Dělení
Tato operace je jednou z
nejzdlouhavějších. Její provádění trvá (na 8086) až 190
period hodin (sčítání trvá kolem 3 period). Jeho výhodou je
ale to, že je možné zjistit jak výsledek po celočíselném
dělení (DIV), tak i zbytek po celočíselném dělení (MOD). A
to všechno jen jednou instrukcí.
- DIV zdroj -
registr AX vyděl zdrojem (osmibitový registr, nebo
paměť) a podíl ulož do AL, zbytek po dělení ulož
do AH (Osmibitové dělení)
- DIV zdroj -
dvojslovo v registrech DX, AX vyděl zdrojem
(šestnáctibitový registr, nebo paměť) a podíl ulož
do AX, zbytek po dělení ulož do DX (Šestnáctibitové
dělení)
- IDIV zdroj -
jako DIV ale dělení se znaménkem
Použití těchto instrukcí je podobné jako násobení.
Program si musíme ošetřit tak, aby nemohlo dojít k
dělení nulou. Jestliže k němu přesto dojde, procesor
zavolá přerušení INT 0.
Příklad:
uses crt;
var a,b,d,z:byte;
s:word;
begin
clrscr;
write ('a=');
readln (a);
write ('b=');
readln (b);
asm
MOV AL,a {do AL vlož hodnotu a}
MUL b {vynásob hodnotou b (v paměti)}
MOV s,AX {do proměnné s vlož součin z registru AX}
MOV AH,0 {nuluj AH (číslo je jen 8 bitové)}
MOV AL,a {do AL vlož hodnotu a}
DIV b {vyděl proměnnou b}
MOV d,AL {výsledek vlož do proměnné d}
MOV z,AH {zbytek po dělení vlož do proměnné z}
end;
writeln ('a*b=',s);
writeln ('a div b=',d,' a mod b=',z);
readkey;
end.
Změna počtu bitů
Často potřebujeme opravit
šestnáctibitové číslo na osmibitové a naopak. Při této
změně může ale dojít ke ztrátě informace v případě
úbytku bitů. Převod čísel bez znaménka provedeme
nejjednodušeji využitím půlení registrů.
- Slabika -> Slovo
Do šestnáctibitového registru načteme do
dolní poloviny slabiku. Horní polovinu nulujeme. Slovo
potom načteme ze všech šestnácti bitů:
var b:byte;
w:word;
begin
b:=10;
asm
MOV AL,b {do AL osm bitů z proměnné b}
MOV AH, 0 {nuluj AH}
MOV w, AX {do proměnné w vlož všech šestnáct bitů}
end;
end.
- Slovo-> Slabika
Operace je opačná. Šestnáctibitové číslo
vložíme do celého šestnáctibitového registru. Do
slabiky potom vložíme jen spodních osm bitů. Ale
pozor, tady může dojít ke ztrátě bitů v horních
osmi bitech. Protože úprava čísel se znaménky by
byla složitá, přichází opět na pomoc ASM86 s
instrukcemi:
- CBW
- převeď obsah AL do AX se zachováním
znaménka
- CWD
- převeď obsah AX do DX, AX (32 bitů) se
zachováním znaménka
Práce s
čísly v kódu BCD
Čísla v BCD kódu mohou být
uložena v těchto formátech:
- Nezhuštěný tvar
V jedné slabice je uložena jedna číslice v
BCD kódu. Má hodnotu 0-9 a obsazuje tedy jen spodní 4
bity. Horní polovina slabiky je nulová (to se
doporučuje pro operace násobení a dělení, pro
sčítání a odčítání může mít libovolný obsah).
Tento tvar je vhodný pro převod do kódu ASCII. Stačí
jen k slabice přičíst číslo 48 (logický součet s
číslem $30).
- Zhuštěný tvar
V jedné slabice jsou uloženy dvě BCD
číslice. Spodní 4 bity nesou hodnotu nižšího řádu
(jednotky), horní 4 nesou hodnotu vyššího řádu
(desítky). Do slabiky jde tedy uložit číslo v rozsahu
0-99. ASM86 nepodporuje přímo matematické operace s
takto kódovanými čísly. Přesto obsahuje instrukce
pro jejich úpravu po provedení běžných operací
určených pro čísla v přirozeném dvojkovém kódu
(obyčejné dvojkově uložené číslo). V ASM86 nejdeme
i instrukce, které pro tyto operace čísla v BCD kódu
připraví. Jedná se o instrukce: AAA, AAD,
AAM, AAS, DAA,
DAS (bližší informace v tabulce instrukcí).
|