Instrukce posuvů a rotací
Tyto instrukce jsou dobrým
pomocníkem každému, kdo je umí používat. Jedná se o
bitový posuv uvnitř slabiky, nebo slova. Počet bitů posuvu je
specifikován použitým registrem, nebo označením
paměťového místa.
Posuvy:
- SHL cíl,
počet <=> SAL cíl, počet - v cíli posuň tak,
že nejnižší bit nahradíš nulou, ostatní přesuň z
nižšího místa o jedno výše, nejvyšší bit
přesuň do registru CF (registr - CL (který nese počet
kroků posuvu), registr - 1, [286] registr - počet
kroků posuvu)
- SHR cíl,
počet - v cíli posuň tak, že nejvyšší bit
nahradíš nulou, ostatní přesuň z vyššího místa
na nižší, nejnižší bit přesuň do registru CF
(registr - CL (který nese počet kroků posuvu), registr
- 1, [286] registr - počet kroků posuvu)
- SAR cíl,
počet - v cíli posuň tak, že nejvyšší bit
nezměníš a kopíruj ho do nižšího bitu, ostatní
přesuň z vyššího místa na nižší, nejnižší bit
přesuň do registru CF (registr - CL (který nese počet
kroků posuvu), registr - 1, [286] registr - počet
kroků posuvu)
Rotace:
- ROL cíl,
počet - v cíli posuň tak, že každý nižší bit
kopíruj do vyššího, nejvyšší kopíruj na místo
nejnižšího a do registru CF (registr - CL (který nese
počet kroků posuvu), registr - 1, [286] registr -
počet kroků posuvu)
- ROR cíl,
počet - v cíli posuň tak, že každý vyšší bit
kopíruj do nižšího, nejnižší kopíruj na místo
nejvyššího a do registru CF (registr - CL (který nese
počet kroků posuvu), registr - 1, [286] registr -
počet kroků posuvu)
- RCL cíl,
počet - v cíli posuň tak, že každý nižší bit
kopíruj do vyššího, nejvyšší kopíruj do registru
CF, obsah CF přenes na místo nejnižšího (registr -
CL (který nese počet kroků posuvu), registr - 1, [286]
registr - počet kroků posuvu)
- RCR cíl,
počet - v cíli posuň tak, že každý vyšší bit
kopíruj do nižšího, nejnižší kopíruj do registru
CF, obsah CF přenes na místo nejvyššího (registr -
CL (který nese počet kroků posuvu), registr - 1, [286]
registr - počet kroků posuvu)
Použití
posuvů a rotací
Kontrola jednotlivých
bitů
Jestliže potřebujeme zkontrolovat, jakou hodnotu
některý z bitů nese, stačí slovo nebo slabiku rotovat přes
registr CF. Hodnotu, kterou bit nese, potom zjistíme kontrolou
registru CF.
Tvorba masky
Jestliže nevíme, jak vytvořit slabiku nebo slovo pro
vymaskování, použijeme instrukci posuvu. MOV AL,
1; SHL AL, 3. Takto získáme slabiku s
nastaveným bitem na čtvrtém místě (00001000).
Celočíselné dělení
mocninou 2 a násobení konstantou
Je to nejdůležitější použití posuvů. Vychází z
faktu, že bitový posuv čísla doleva o jeden krok je stejný,
jako bychom číslo vynásobili dvěma. Naopak bitový posuv
čísla doprava o jeden krok je stejný, jako bychom číslo
dělili dvěma. Dělení: Do registru umístíme dělence. Ten
potom posuneme doprava o tolik, kolikátou mocninou 2 je
dělitel:
- SHR AL, 1 -
AL := AL div 2
- SHR AL, 2 -
AL := AL div 4
- SHR AL, 3 -
AL := AL div 8
- SHR AL, 4 -
AL := AL div 16 . . .
Pozor! Toto dělení je sice velmi
rychlé, ale použitelné jen tehdy, jestliže chceme číslo
dělit mocninou 2 (a to bývá naštěstí nejčastěji). Ke
zjištění zbytku po celočíselném dělení použijeme operaci
AND (jak bylo popsáno výše).
Násobení čísla konstantou: Do tolika registrů, kolik je log.
1 v binárním vyjádření konstanty, umístíme hodnotu
čísla. Potom jednotlivé registry posuneme doleva. Každý o
tolik, na kolikátém místě byla log. 1 v binárním
vyjádření konstanty. Nakonec všechny registry přičteme k
jedinému, ve kterém bude výsledek.
Příklad: Vynásobme konstantou 18 vložené číslo:
- 18 : 2 = 9 (0)...0
- 9 : 2 = 4 (1)...1
- 4 : 2 = 2 (0)...2
- 2 : 2 = 1 (0)...3
- 1 : 2 = 0 (1)...4
Logická 1 je tedy na místě č.1
a č.4. Proto použijeme dva registry, ty posuneme o 1 a 4 kroky.
Nakonec je sečteme.
{$G+}
var cislo:word;
begin
readln (cislo);
asm
MOV AX,cislo {naber číslo do prvního registru}
MOV BX, AX {naber číslo do druhého registru}
SHL AX, 1 {v prvním registru jednou doleva<=>vynásob 2}
SHL BX, 4 {v druhém registru čtyřikrát doleva<=>vynásob 16}
ADD AX, BX {sečti obsahy obou registrů}
MOV cislo, AX {vrať přes proměnnou cislo}
end;
writeln ('Číslo*18=',cislo);
end.
Uvedený postup můžete snadno
převést na libovolnou konstantu. Vzhledem ke zdlouhavosti
násobení instrukcí MUL vám tento algoritmus
občas zrychlí program.
Následující příklad
vytváří řetězec informací o čase. Ten si zjistí z paměti
CMOS. Čtení provádíme tak, že na adresu portu $70 vyšleme
číslo čtené slabiky (0 - sekundy, 2 - minuty, 4 - hodiny) v
CMOS. Z portu $71 potom přečteme její hodnotu. Ta je v CMOS ve
zhuštěném BCD tvaru. Proto ji převedeme na nezhuštěný a
teprve potom na kód ASCII. Nakonec data zapíši do proměnné
slovo typu string ve tvaru, v jakém je zvykem čas zapisovat.
Program jsem optimalizoval tak, aby měl co nejmenší počet
instrukcí. Vzhledem k tomu, že ve vloženém assembleru jsem
nepoužil cyklus, tvořím jej s pomocí pascalovského for
cyklu. Podobným způsobem bychom četli i jiné užitečné
informace z paměti CMOS (datum, konfigurace . . .).
Příklad:
uses crt;
var i:byte;
slovo:string;
begin
slovo[0]:=#8;
slovo[3]:='.';
slovo[6]:='.';
clrscr;
repeat
for i:=0 to 2 do
asm
MOV BX,offset slovo {naber adresu proměnné slovo do BX}
XOR AH,AH {vymaž horní polovinu registru AX}
MOV AL,i {naber do dolní poloviny AX krok i}
SUB BX,AX {odečti od BX obsah AX}
SHL AL,1 {vynásob, AL:=AL*2}
SUB BX,AX {odečti od BX obsah AX}
OUT $70,AL {pošli na CMOS adresu čtené slabiky}
IN AL,$71 {přečti z CMOS obsah čtené slabiky}
MOV AH,AL {zkopíruj obsah přečtené slabiky do AH}
SHR AH,4 {desítky posuň do dolní poloviny AH}
AND AX,$0F0F {odstraň zbytečné bity}
OR AX,$3030 {proveď převod do ASCII}
MOV 8[BX],AL {nastav jednotky v proměnné slovo}
MOV 7[BX],AH {nastav desítky v proměnné slovo}
end;
gotoxy (1,1);
write(slovo);
until keypressed;
readkey;
end.
|