Inštrukcie posuvov a rotácií


<= =>


Tieto inštrukcie sú dobrým pomocníkom každému, kto ich vie používať. Jedná sa o bitový posun vo vnútri slabiky, alebo slova. Počet bitov posuvu je špecifikovaný použitým registrom, alebo označením pamäťového miesta.

Posuvy:

Rotácia:

Použitie posuvov a rotácií

Kontrola jednotlivých bitov
Ak potrebujeme skontrolovať, akú hodnotu niektorý z bitov nesie, stačí slovo alebo slabiku rotovať cez register CF. Hodnotu, ktorú bit nesie, potom zistíme kontrolou registra CF.

Tvorba masky
Ak nevieme, ako vytvoriť slabiku alebo slovo pre vymaskovanie, použijeme inštrukciu posuvu. MOV AL, 1; SHL AL, 3. Takto získame slabiku s nastaveným bitom na štvrtom mieste (00001000).

Celočíselné delenie mocninou 2 a násobenie konštantou
Je to najdôležitejšie použitie posuvov. Vychádza z faktu, že bitový posuv čísla doľava o jeden krok je rovnaký, ako by sme číslo vynásobili dvomi. Naopak bitový posuv čísla doprava o jeden krok je rovnaký, ako by sme číslo delili dvomi. Delenie: Do registra umiestnime delenca. Ten potom posunieme doprava o toľko, koľkou mocninou 2 je deliteľ:

Pozor! Toto delenie je síce veľmi rýchle, ale použiteľné len vtedy, keď chceme číslo deliť mocninou 2 (a to býva našťastie najčastejšie). K zisteniu zbytku po celočíselnom delení použijeme operáciu AND (ako bolo popísané vyššie).
Násobenie čísla konštantou: Do toľkých registrov, koľko je log. 1 v binárnom vyjadrení konštanty, umiestnime hodnotu čísla. Potom jednotlivé registre posunieme doľava. Každý o toľko, na koľkátom mieste bola log. 1 v binárnom vyjadrení konštanty. Nakoniec všetky registre pričítame k jedinému, v ktorom bude výsledok.
Príklad: Vynásobme konštantou 18 vložené číslo: Logická 1 je teda na mieste č.1 a č.4. Preto použijeme dva registre, tie posunieme o 1 a 4 kroky. Nakoniec je sčítame.
#include <stdio.h>
unsigned int cislo;
main() {
  scanf("%d",&cislo);
  asm {
    MOV AX,cislo    // naber číslo do prvého registra
    MOV BX, AX      // naber číslo do druhého registra
    SHL AX, 1       // v prvom registre raz doľava <=> vynásob 2
    SHL BX, 4       // v druhom registre štyrikrát doľava <=> vynásob 16
    ADD AX, BX      // sčítaj obsahy oboch registrov
    MOV cislo, AX   // vráť cez premennú cislo
  }
  printf("cislo*18=%d",cislo);
}

Uvedený postup môžete jednoducho previesť na ľubovoľnú konštantu. Vzhľadom k zdĺhavosti násobenia inštrukciou MUL vám tento algoritmus občas zrýchli program.

Nasledujúci príklad vytvára reťazec informácií o čase. Ten si zistí z pamäti CMOS. Čítanie prevádzame tak, že na adresu portu 0x70 vyšleme číslo čítanej slabiky (0 - sekundy, 2 - minúty, 4 - hodiny) v CMOS. Z portu 0x71 potom prečítame jej hodnotu. Ta je v CMOS v zhustenom BCD tvare. Preto ju prevedieme na nezhustený a až potom na kód ASCII. Nakoniec dáta zapíšeme do premennej slovo v tvare, v akom je zvykom čas zapisovať. Program som optimalizoval tak, aby mal čo najmenší počet inštrukcií. Vzhľadom k tomu, že vo vloženom assembleri som nepoužil cyklus, tvorím ho pomocou “céčkového” for cyklu. Podobným spôsobom by sme čítali i iné užitočné informácie z pamäti CMOS (dátum, konfigurácie . . .).

#include <stdio.h>
#include <conio.h>
unsigned char i;
char slovo[254]=" . . ";
main() {
  clrscr();
  do {
    for (i=0; i<= 2; i++) {
      asm {
        MOV BX,offset slovo  // naber adresu premennej slovo
        XOR AH,AH            // vymaž hornú polovicu registra AX
        MOV AL,i             // naber do dolnej polovice AX krok i
        SUB BX,AX            // odčítaj od BX obsah AX
        SHL AL,1             // vynásob, AL:=AL*2
        SUB BX,AX            // odčítaj od BX obsah AX
        OUT 0x70,AL          // pošli na CMOS adresu čítanej slabiky
        IN  AL,0x71          // prečítaj z CMOS obsah čítanej slabiky
        MOV AH,AL            // skopíruj obsah prečítanej slabiky do AH
        SHR AH,4             // desiatky posuň do dolnej polovice AH
        AND AX,0x0F0F        // odstráň zbytočné bity
        OR  AX,0x3030        // urob prevod do ASCII
        MOV 7[BX],AL         // nastav jednotky v premennej slovo
        MOV 6[BX],AH         // nastav desiatky v premennej slovo
      }
      gotoxy (1,1);
      printf("%s",slovo);
    }
  } while (!kbhit());
}



<= =>