Učebnice Assembleru 86

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:

Rotace:

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:

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:

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.

Směr