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:

  • 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.

Směr